/src/wireshark/epan/dissectors/packet-irc.c
Line | Count | Source |
1 | | /* packet-irc.c |
2 | | * |
3 | | * Wireshark - Network traffic analyzer |
4 | | * By Gerald Combs <gerald@wireshark.org> |
5 | | * Copyright 1998 Gerald Combs |
6 | | * |
7 | | * Copied from packet-tftp.c |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | |
12 | | /* |
13 | | * Routines for IRC packet dissection |
14 | | * |
15 | | * See |
16 | | * |
17 | | * http://www.irchelp.org/irchelp/rfc/ |
18 | | * |
19 | | * and the RFCs and other documents it mentions, such as RFC 1459, RFCs |
20 | | * 2810, 2811, 2812, and 2813, |
21 | | * |
22 | | * For CTCP, see : |
23 | | * http://www.irchelp.org/irchelp/rfc/ctcpspec.html |
24 | | * http://web.archive.org/web/20031203073050/http://www.invlogic.com/irc/ctcp.html |
25 | | * https://www.ietf.org/archive/id/draft-oakley-irc-ctcp-02.txt |
26 | | */ |
27 | | |
28 | | #include "config.h" |
29 | | |
30 | | #include <epan/packet.h> |
31 | | #include <epan/expert.h> |
32 | | #include <wsutil/array.h> |
33 | | |
34 | | void proto_register_irc(void); |
35 | | void proto_reg_handoff_irc(void); |
36 | | |
37 | | static int proto_irc; |
38 | | static int proto_irc_ctcp; |
39 | | static int hf_irc_request; |
40 | | static int hf_irc_request_prefix; |
41 | | static int hf_irc_request_command; |
42 | | static int hf_irc_request_command_param; |
43 | | static int hf_irc_request_trailer; |
44 | | static int hf_irc_response; |
45 | | static int hf_irc_response_prefix; |
46 | | static int hf_irc_response_command; |
47 | | static int hf_irc_response_num_command; |
48 | | static int hf_irc_response_command_param; |
49 | | static int hf_irc_response_trailer; |
50 | | //static int hf_irc_ctcp; |
51 | | static int hf_irc_ctcp_command; |
52 | | static int hf_irc_ctcp_params; |
53 | | |
54 | | static int ett_irc; |
55 | | static int ett_irc_request; |
56 | | static int ett_irc_request_command; |
57 | | static int ett_irc_response; |
58 | | static int ett_irc_response_command; |
59 | | |
60 | | static expert_field ei_irc_missing_end_delimiter; |
61 | | static expert_field ei_irc_numeric_request_command; |
62 | | static expert_field ei_irc_response_command; |
63 | | static expert_field ei_irc_prefix_missing_ending_space; |
64 | | static expert_field ei_irc_request_command; |
65 | | static expert_field ei_irc_tag_data_invalid; |
66 | | |
67 | | /* This must be a null-terminated string */ |
68 | | static const char TAG_DELIMITER[] = "\x01"; |
69 | | /* patterns used for tvb_ws_mempbrk_pattern_uint8 */ |
70 | | static ws_mempbrk_pattern pbrk_tag_delimiter; |
71 | | |
72 | | static dissector_handle_t ctcp_handle; |
73 | | |
74 | 14 | #define TCP_PORT_RANGE "6667,57000" /* Not IANA registered */ |
75 | | |
76 | | static int |
77 | | dissect_irc_ctcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
78 | 120 | { |
79 | 120 | proto_tree *ctcp_tree; |
80 | 120 | proto_item *ti; |
81 | 120 | const uint8_t *str_command, *str_params; |
82 | 120 | int space_offset = -1; |
83 | | |
84 | 120 | ti = proto_tree_add_item(tree, proto_irc, tvb, 0, -1, ENC_ASCII|ENC_NA); |
85 | 120 | ctcp_tree = proto_item_add_subtree(ti, ett_irc); |
86 | | |
87 | 120 | space_offset = tvb_find_uint8(tvb, 1, -1, ' '); |
88 | 120 | if (space_offset == -1) { |
89 | 76 | proto_tree_add_item_ret_string(ctcp_tree, hf_irc_ctcp_command, tvb, 0, tvb_reported_length(tvb), ENC_ASCII|ENC_NA, pinfo->pool, &str_command); |
90 | 76 | } |
91 | 44 | else { |
92 | 44 | proto_tree_add_item_ret_string(ctcp_tree, hf_irc_ctcp_command, tvb, 0, space_offset, ENC_ASCII|ENC_NA, pinfo->pool, &str_command); |
93 | 44 | proto_tree_add_item_ret_string(ctcp_tree, hf_irc_ctcp_params, tvb, space_offset+1, tvb_reported_length(tvb)-space_offset-1, ENC_ASCII|ENC_NA, pinfo->pool, &str_params); |
94 | 44 | } |
95 | | |
96 | 120 | return tvb_captured_length(tvb); |
97 | 120 | } |
98 | | |
99 | | static void |
100 | | dissect_irc_tag_data(proto_tree *tree, proto_item *item, tvbuff_t *tvb, int offset, int datalen, packet_info *pinfo, const char* command) |
101 | 165 | { |
102 | 165 | unsigned char found_start_needle = 0, |
103 | 165 | found_end_needle = 0; |
104 | 165 | int tag_start_offset, tag_end_offset; |
105 | 165 | tvbuff_t *next_tvb; |
106 | | |
107 | 165 | tag_start_offset = tvb_ws_mempbrk_pattern_uint8(tvb, offset, datalen, &pbrk_tag_delimiter, &found_start_needle); |
108 | 165 | if (tag_start_offset == -1) |
109 | 24 | { |
110 | | /* no tag data */ |
111 | 24 | return; |
112 | 24 | } |
113 | | |
114 | 141 | tag_end_offset = tvb_ws_mempbrk_pattern_uint8(tvb, tag_start_offset+1, datalen, &pbrk_tag_delimiter, &found_end_needle); |
115 | 141 | if (tag_end_offset == -1) |
116 | 21 | { |
117 | 21 | expert_add_info(pinfo, item, &ei_irc_missing_end_delimiter); |
118 | 21 | return; |
119 | 21 | } |
120 | | |
121 | 120 | if ((strcmp(command, "NOTICE") != 0) && |
122 | 120 | (strcmp(command, "PRIVMSG") != 0)) |
123 | 120 | { |
124 | 120 | expert_add_info(pinfo, item, &ei_irc_tag_data_invalid); |
125 | 120 | } |
126 | | |
127 | | /* Placeholder to call CTCP dissector, strip out delimiter */ |
128 | 120 | if(tree) { |
129 | 120 | next_tvb = tvb_new_subset_length(tvb, tag_start_offset+1, datalen-2 ); |
130 | 120 | dissect_irc_ctcp(next_tvb, pinfo, tree, NULL); |
131 | 120 | } |
132 | 120 | } |
133 | | |
134 | | static void |
135 | | dissect_irc_request(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, int linelen) |
136 | 737 | { |
137 | 737 | proto_tree *request_tree, *command_tree = NULL; |
138 | 737 | proto_item *request_item; |
139 | 737 | int start_offset = offset; |
140 | 737 | int end_offset = start_offset+linelen; |
141 | 737 | int eop_offset = -1, |
142 | 737 | eoc_offset = -1, |
143 | 737 | eocp_offset, |
144 | 737 | tag_start_offset, tag_end_offset; |
145 | 737 | const char *str_command; |
146 | 737 | unsigned char found_tag_needle = 0; |
147 | 737 | bool first_command_param = true; |
148 | | |
149 | 737 | request_item = proto_tree_add_item(tree, hf_irc_request, tvb, offset, linelen, ENC_ASCII); |
150 | 737 | if (linelen <= 0) |
151 | 0 | return; |
152 | | |
153 | 737 | request_tree = proto_item_add_subtree(request_item, ett_irc_request ); |
154 | | |
155 | | /* Check if message has a prefix */ |
156 | 737 | if (tvb_get_uint8(tvb, offset) == ':') |
157 | 87 | { |
158 | | /* find the end of the prefix */ |
159 | 87 | eop_offset = tvb_find_uint8(tvb, offset+1, linelen-1, ' '); |
160 | 87 | if (eop_offset == -1) |
161 | 58 | { |
162 | 58 | expert_add_info(pinfo, request_item, &ei_irc_prefix_missing_ending_space); |
163 | 58 | return; |
164 | 58 | } |
165 | | |
166 | 29 | proto_tree_add_item(request_tree, hf_irc_request_prefix, tvb, offset+1, eop_offset-offset-1, ENC_ASCII); |
167 | 29 | offset = eop_offset+1; |
168 | 29 | } |
169 | | |
170 | | /* clear out any whitespace before command */ |
171 | 849 | while(offset < end_offset && tvb_get_uint8(tvb, offset) == ' ') |
172 | 170 | { |
173 | 170 | offset++; |
174 | 170 | } |
175 | 679 | if (offset == end_offset) |
176 | 13 | { |
177 | 13 | expert_add_info(pinfo, request_item, &ei_irc_request_command); |
178 | 13 | return; |
179 | 13 | } |
180 | | |
181 | 666 | eoc_offset = tvb_find_uint8(tvb, offset, end_offset-offset, ' '); |
182 | 666 | if (eoc_offset == -1) |
183 | 355 | { |
184 | 355 | const uint8_t* col_str; |
185 | 355 | proto_tree_add_item_ret_string(request_tree, hf_irc_request_command, tvb, offset, end_offset-offset, ENC_ASCII|ENC_NA, pinfo->pool, &col_str); |
186 | 355 | col_append_fstr( pinfo->cinfo, COL_INFO, " (%s)", col_str); |
187 | | |
188 | | /* Warn if there is a "numeric" command */ |
189 | 355 | if ((end_offset-offset == 3) && |
190 | 36 | (g_ascii_isdigit(tvb_get_uint8(tvb, offset))) && |
191 | 0 | (g_ascii_isdigit(tvb_get_uint8(tvb, offset+1))) && |
192 | 0 | (g_ascii_isdigit(tvb_get_uint8(tvb, offset+2)))) |
193 | 0 | { |
194 | 0 | expert_add_info(pinfo, request_item, &ei_irc_numeric_request_command); |
195 | 0 | } |
196 | 355 | return; |
197 | 355 | } |
198 | | |
199 | 311 | proto_tree_add_item_ret_string(request_tree, hf_irc_request_command, tvb, offset, eoc_offset-offset, ENC_ASCII|ENC_NA, pinfo->pool, (const uint8_t**)&str_command); |
200 | 311 | col_append_fstr( pinfo->cinfo, COL_INFO, " (%s)", str_command); |
201 | | |
202 | | /* Warn if there is a "numeric" command */ |
203 | 311 | if ((eoc_offset-offset == 3) && |
204 | 25 | (g_ascii_isdigit(tvb_get_uint8(tvb, offset))) && |
205 | 7 | (g_ascii_isdigit(tvb_get_uint8(tvb, offset+1))) && |
206 | 6 | (g_ascii_isdigit(tvb_get_uint8(tvb, offset+2)))) |
207 | 5 | { |
208 | 5 | expert_add_info(pinfo, request_item, &ei_irc_numeric_request_command); |
209 | 5 | } |
210 | | |
211 | 311 | offset = eoc_offset+1; |
212 | | |
213 | | /* clear out any whitespace before command parameter */ |
214 | 518 | while(offset < end_offset && tvb_get_uint8(tvb, offset) == ' ') |
215 | 207 | { |
216 | 207 | offset++; |
217 | 207 | } |
218 | 311 | if (offset == end_offset) |
219 | 56 | { |
220 | | /* No command parameters */ |
221 | 56 | return; |
222 | 56 | } |
223 | | |
224 | | /* Check if message has a trailer */ |
225 | 255 | if (tvb_get_uint8(tvb, offset) == ':') |
226 | 9 | { |
227 | 9 | proto_tree_add_item(request_tree, hf_irc_request_trailer, tvb, offset+1, end_offset-offset-1, ENC_ASCII); |
228 | 9 | dissect_irc_tag_data(request_tree, request_item, tvb, offset+1, end_offset-offset-1, pinfo, str_command); |
229 | 9 | return; |
230 | 9 | } |
231 | | |
232 | 588 | while(offset < end_offset) |
233 | 581 | { |
234 | 581 | eocp_offset = tvb_find_uint8(tvb, offset, end_offset-offset, ' '); |
235 | 581 | tag_start_offset = tvb_ws_mempbrk_pattern_uint8(tvb, offset, end_offset-offset, &pbrk_tag_delimiter, &found_tag_needle); |
236 | | |
237 | | /* Create subtree when the first parameter is found */ |
238 | 581 | if (first_command_param) |
239 | 246 | { |
240 | 246 | command_tree = proto_tree_add_subtree(request_tree, tvb, offset, end_offset-offset, |
241 | 246 | ett_irc_request_command, NULL, "Command parameters"); |
242 | 246 | first_command_param = false; |
243 | 246 | } |
244 | | |
245 | 581 | if (((eocp_offset == -1) && (tag_start_offset == -1)) || |
246 | 468 | ((eocp_offset != -1) && (tag_start_offset == -1)) || |
247 | 311 | (eocp_offset < tag_start_offset)) |
248 | 455 | { |
249 | | /* regular message should be dissected */ |
250 | | |
251 | 455 | if (eocp_offset == -1) |
252 | 166 | { |
253 | 166 | proto_tree_add_item(command_tree, hf_irc_request_command_param, tvb, offset, end_offset-offset, ENC_ASCII); |
254 | 166 | return; |
255 | 166 | } |
256 | | |
257 | 289 | proto_tree_add_item(command_tree, hf_irc_request_command_param, tvb, offset, eocp_offset-offset, ENC_ASCII); |
258 | 289 | offset = eocp_offset+1; |
259 | | |
260 | | /* clear out any whitespace before next command parameter */ |
261 | 700 | while(offset < end_offset && tvb_get_uint8(tvb, offset) == ' ') |
262 | 411 | { |
263 | 411 | offset++; |
264 | 411 | } |
265 | 289 | if (offset == end_offset) |
266 | 31 | { |
267 | 31 | break; |
268 | 31 | } |
269 | | |
270 | | /* Check if message has a trailer */ |
271 | 258 | if (tvb_get_uint8(tvb, offset) == ':') |
272 | 6 | { |
273 | 6 | proto_tree_add_item(request_tree, hf_irc_request_trailer, tvb, offset+1, end_offset-offset-1, ENC_ASCII); |
274 | 6 | dissect_irc_tag_data(request_tree, request_item, tvb, offset+1, end_offset-offset-1, pinfo, str_command); |
275 | 6 | return; |
276 | 6 | } |
277 | 258 | } |
278 | 126 | else if (((eocp_offset == -1) && (tag_start_offset != -1)) || |
279 | 126 | (eocp_offset > tag_start_offset)) |
280 | 126 | { |
281 | | /* tag data dissected */ |
282 | | |
283 | 126 | found_tag_needle = 0; |
284 | 126 | tag_end_offset = tvb_ws_mempbrk_pattern_uint8(tvb, tag_start_offset+1, end_offset-tag_start_offset-1, &pbrk_tag_delimiter, &found_tag_needle); |
285 | 126 | if (tag_end_offset == -1) |
286 | 36 | { |
287 | 36 | expert_add_info(pinfo, request_item, &ei_irc_missing_end_delimiter); |
288 | 36 | return; |
289 | 36 | } |
290 | | |
291 | 90 | dissect_irc_tag_data(request_tree, request_item, tvb, tag_start_offset, tag_end_offset-tag_start_offset, pinfo, str_command); |
292 | 90 | offset = tag_end_offset+1; |
293 | 90 | } |
294 | 581 | } |
295 | 246 | } |
296 | | |
297 | | static void |
298 | | dissect_irc_response(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, int linelen) |
299 | 849 | { |
300 | 849 | proto_tree *response_tree, *command_tree = NULL; |
301 | 849 | proto_item *response_item, *hidden_item; |
302 | 849 | int start_offset = offset; |
303 | 849 | int end_offset = start_offset+linelen; |
304 | 849 | int eop_offset = -1, |
305 | 849 | eoc_offset = -1, |
306 | 849 | eocp_offset, |
307 | 849 | tag_start_offset, tag_end_offset; |
308 | 849 | const char* str_command; |
309 | 849 | uint16_t num_command; |
310 | 849 | unsigned char found_tag_needle = 0; |
311 | 849 | bool first_command_param = true; |
312 | | |
313 | 849 | response_item = proto_tree_add_item(tree, hf_irc_response, tvb, offset, linelen, ENC_ASCII); |
314 | 849 | if (linelen <= 0) |
315 | 0 | return; |
316 | | |
317 | 849 | response_tree = proto_item_add_subtree(response_item, ett_irc_response ); |
318 | | |
319 | | /* Check if message has a prefix */ |
320 | 849 | if (tvb_get_uint8(tvb, offset) == ':') |
321 | 50 | { |
322 | | /* find the end of the prefix */ |
323 | 50 | eop_offset = tvb_find_uint8(tvb, offset+1, linelen-1, ' '); |
324 | 50 | if (eop_offset == -1) |
325 | 38 | { |
326 | 38 | expert_add_info(pinfo, response_item, &ei_irc_prefix_missing_ending_space); |
327 | 38 | return; |
328 | 38 | } |
329 | | |
330 | 12 | proto_tree_add_item(response_tree, hf_irc_response_prefix, tvb, offset+1, eop_offset-offset-1, ENC_ASCII); |
331 | 12 | offset = eop_offset+1; |
332 | 12 | } |
333 | | |
334 | | /* clear out any whitespace before command */ |
335 | 1.20k | while(offset < end_offset && tvb_get_uint8(tvb, offset) == ' ') |
336 | 393 | { |
337 | 393 | offset++; |
338 | 393 | } |
339 | 811 | if (offset == end_offset) |
340 | 41 | { |
341 | 41 | expert_add_info(pinfo, response_item, &ei_irc_response_command); |
342 | 41 | return; |
343 | 41 | } |
344 | | |
345 | 770 | eoc_offset = tvb_find_uint8(tvb, offset, end_offset-offset, ' '); |
346 | 770 | if (eoc_offset == -1) |
347 | 378 | { |
348 | 378 | const uint8_t* col_str; |
349 | 378 | proto_tree_add_item_ret_string(response_tree, hf_irc_response_command, tvb, offset, end_offset-offset, ENC_ASCII|ENC_NA, pinfo->pool, &col_str); |
350 | 378 | col_append_fstr( pinfo->cinfo, COL_INFO, " (%s)", col_str); |
351 | | |
352 | | /* if response command is numeric, allow it to be filtered as an integer */ |
353 | 378 | if ((end_offset-offset == 3) && |
354 | 40 | (g_ascii_isdigit(tvb_get_uint8(tvb, offset))) && |
355 | 2 | (g_ascii_isdigit(tvb_get_uint8(tvb, offset+1))) && |
356 | 0 | (g_ascii_isdigit(tvb_get_uint8(tvb, offset+2)))) |
357 | 0 | { |
358 | 0 | num_command = ((tvb_get_uint8(tvb, offset)-0x30)*100) + ((tvb_get_uint8(tvb, offset+1)-0x30)*10) + (tvb_get_uint8(tvb, offset+2)-0x30); |
359 | 0 | hidden_item = proto_tree_add_uint(response_tree, hf_irc_response_num_command, tvb, offset, end_offset-offset, num_command); |
360 | 0 | proto_item_set_hidden(hidden_item); |
361 | 0 | } |
362 | 378 | return; |
363 | 378 | } |
364 | | |
365 | 392 | proto_tree_add_item_ret_string(response_tree, hf_irc_response_command, tvb, offset, eoc_offset-offset, ENC_ASCII|ENC_NA, pinfo->pool, (const uint8_t**)&str_command); |
366 | 392 | col_append_fstr( pinfo->cinfo, COL_INFO, " (%s)", str_command); |
367 | | |
368 | | /* if response command is numeric, allow it to be filtered as an integer */ |
369 | 392 | if ((eoc_offset-offset == 3) && |
370 | 60 | (g_ascii_isdigit(tvb_get_uint8(tvb, offset))) && |
371 | 40 | (g_ascii_isdigit(tvb_get_uint8(tvb, offset+1))) && |
372 | 19 | (g_ascii_isdigit(tvb_get_uint8(tvb, offset+2)))) |
373 | 19 | { |
374 | 19 | num_command = ((tvb_get_uint8(tvb, offset)-0x30)*100) + ((tvb_get_uint8(tvb, offset+1)-0x30)*10) + (tvb_get_uint8(tvb, offset+2)-0x30); |
375 | 19 | hidden_item = proto_tree_add_uint(response_tree, hf_irc_response_num_command, tvb, offset, eoc_offset-offset, num_command); |
376 | 19 | proto_item_set_hidden(hidden_item); |
377 | 19 | } |
378 | | |
379 | 392 | offset = eoc_offset+1; |
380 | | |
381 | | /* clear out any whitespace before command parameter */ |
382 | 1.41k | while(offset < end_offset && tvb_get_uint8(tvb, offset) == ' ') |
383 | 1.02k | { |
384 | 1.02k | offset++; |
385 | 1.02k | } |
386 | 392 | if (offset == end_offset) |
387 | 55 | { |
388 | | /* No command parameters */ |
389 | 55 | return; |
390 | 55 | } |
391 | | |
392 | | /* Check if message has a trailer */ |
393 | 337 | if (tvb_get_uint8(tvb, offset) == ':') |
394 | 25 | { |
395 | 25 | proto_tree_add_item(response_tree, hf_irc_response_trailer, tvb, offset+1, end_offset-offset-1, ENC_ASCII); |
396 | 25 | dissect_irc_tag_data(response_tree, response_item, tvb, offset+1, end_offset-offset-1, pinfo, str_command); |
397 | 25 | return; |
398 | 25 | } |
399 | | |
400 | 876 | while(offset < end_offset) |
401 | 867 | { |
402 | 867 | eocp_offset = tvb_find_uint8(tvb, offset, end_offset-offset, ' '); |
403 | 867 | tag_start_offset = tvb_ws_mempbrk_pattern_uint8(tvb, offset, end_offset-offset, &pbrk_tag_delimiter, &found_tag_needle); |
404 | | |
405 | | /* Create subtree when the first parameter is found */ |
406 | 867 | if (first_command_param) |
407 | 312 | { |
408 | 312 | command_tree = proto_tree_add_subtree(response_tree, tvb, offset, end_offset-offset, |
409 | 312 | ett_irc_response_command , NULL, "Command parameters"); |
410 | 312 | first_command_param = false; |
411 | 312 | } |
412 | | |
413 | 867 | if ((tag_start_offset == -1) || (eocp_offset < tag_start_offset)) |
414 | 805 | { |
415 | | /* regular message should be dissected */ |
416 | | |
417 | 805 | if (eocp_offset == -1) |
418 | 204 | { |
419 | 204 | proto_tree_add_item(command_tree, hf_irc_response_command_param, tvb, offset, end_offset-offset, ENC_ASCII); |
420 | 204 | return; |
421 | 204 | } |
422 | | |
423 | 601 | proto_tree_add_item(command_tree, hf_irc_response_command_param, tvb, offset, eocp_offset-offset, ENC_ASCII); |
424 | 601 | offset = eocp_offset+1; |
425 | | |
426 | | /* clear out any whitespace before next command parameter */ |
427 | 1.15k | while(offset < end_offset && tvb_get_uint8(tvb, offset) == ' ') |
428 | 552 | { |
429 | 552 | offset++; |
430 | 552 | } |
431 | 601 | if (offset == end_offset) |
432 | 52 | { |
433 | 52 | break; |
434 | 52 | } |
435 | | |
436 | | /* Check if message has a trailer */ |
437 | 549 | if (tvb_get_uint8(tvb, offset) == ':') |
438 | 10 | { |
439 | 10 | proto_tree_add_item(response_tree, hf_irc_response_trailer, tvb, offset+1, end_offset-offset-1, ENC_ASCII); |
440 | 10 | dissect_irc_tag_data(response_tree, response_item, tvb, offset+1, end_offset-offset-1, pinfo, str_command); |
441 | 10 | return; |
442 | 10 | } |
443 | 549 | } |
444 | 62 | else if ((eocp_offset == -1) || (eocp_offset > tag_start_offset)) |
445 | 62 | { |
446 | | /* tag data dissected */ |
447 | | |
448 | 62 | found_tag_needle = 0; |
449 | 62 | tag_end_offset = tvb_ws_mempbrk_pattern_uint8(tvb, tag_start_offset+1, end_offset-tag_start_offset-1, &pbrk_tag_delimiter, &found_tag_needle); |
450 | 62 | if (tag_end_offset == -1) |
451 | 37 | { |
452 | 37 | expert_add_info(pinfo, response_item, &ei_irc_missing_end_delimiter); |
453 | 37 | return; |
454 | 37 | } |
455 | | |
456 | 25 | dissect_irc_tag_data(response_tree, response_item, tvb, tag_start_offset, tag_end_offset-tag_start_offset, pinfo, str_command); |
457 | 25 | offset = tag_end_offset+1; |
458 | 25 | } |
459 | 867 | } |
460 | 312 | } |
461 | | |
462 | | static int |
463 | | dissect_irc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
464 | 175 | { |
465 | 175 | proto_tree *irc_tree, *ti; |
466 | 175 | int offset = 0; |
467 | 175 | int next_offset; |
468 | 175 | int linelen; |
469 | | |
470 | 175 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "IRC"); |
471 | | |
472 | 175 | col_set_str(pinfo->cinfo, COL_INFO, |
473 | 175 | (pinfo->match_uint == pinfo->destport) ? "Request" : "Response"); |
474 | | |
475 | 175 | ti = proto_tree_add_item(tree, proto_irc, tvb, 0, -1, ENC_NA); |
476 | 175 | irc_tree = proto_item_add_subtree(ti, ett_irc); |
477 | | |
478 | | /* |
479 | | * Process the packet data, a line at a time. |
480 | | */ |
481 | 3.67k | while (tvb_offset_exists(tvb, offset)) |
482 | 3.50k | { |
483 | | /* |
484 | | * Find the end of the line. |
485 | | */ |
486 | 3.50k | linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, false); |
487 | 3.50k | if (next_offset == offset) { |
488 | | /* |
489 | | * XXX - we really want the "show data a |
490 | | * line at a time" loops in various |
491 | | * dissectors to do reassembly and to |
492 | | * throw an exception if there's no |
493 | | * line ending in the current packet |
494 | | * and we're not doing reassembly. |
495 | | */ |
496 | 0 | break; |
497 | 0 | } |
498 | | |
499 | 3.50k | if (linelen != 0) |
500 | 1.58k | { |
501 | 1.58k | if (pinfo->match_uint == pinfo->destport) |
502 | 737 | { |
503 | 737 | dissect_irc_request(irc_tree, tvb, pinfo, offset, linelen); |
504 | 737 | } |
505 | 849 | else |
506 | 849 | { |
507 | 849 | dissect_irc_response(irc_tree, tvb, pinfo, offset, linelen); |
508 | 849 | } |
509 | 1.58k | } |
510 | 3.50k | offset = next_offset; |
511 | 3.50k | } |
512 | 175 | return tvb_captured_length(tvb); |
513 | 175 | } |
514 | | |
515 | | void |
516 | | proto_register_irc(void) |
517 | 14 | { |
518 | 14 | static hf_register_info hf[] = { |
519 | 14 | { &hf_irc_response, { "Response", "irc.response", FT_STRING, BASE_NONE, |
520 | 14 | NULL, 0x0, "Line of response message", HFILL }}, |
521 | | |
522 | 14 | { &hf_irc_request, { "Request", "irc.request", FT_STRING, BASE_NONE, |
523 | 14 | NULL, 0x0, "Line of request message", HFILL }}, |
524 | | |
525 | 14 | { &hf_irc_request_prefix, { "Prefix", "irc.request.prefix", FT_STRING, BASE_NONE, |
526 | 14 | NULL, 0x0, "Request prefix", HFILL }}, |
527 | | |
528 | 14 | { &hf_irc_request_command, { "Command", "irc.request.command", FT_STRING, BASE_NONE, |
529 | 14 | NULL, 0x0, "Request command", HFILL }}, |
530 | | |
531 | 14 | { &hf_irc_request_command_param, { "Parameter", "irc.request.command_parameter", FT_STRING, BASE_NONE, |
532 | 14 | NULL, 0x0, "Request command parameter", HFILL }}, |
533 | | |
534 | 14 | { &hf_irc_request_trailer, { "Trailer", "irc.request.trailer", FT_STRING, BASE_NONE, |
535 | 14 | NULL, 0x0, "Request trailer", HFILL }}, |
536 | | |
537 | 14 | { &hf_irc_response_prefix, { "Prefix", "irc.response.prefix", FT_STRING, BASE_NONE, |
538 | 14 | NULL, 0x0, "Response prefix", HFILL }}, |
539 | | |
540 | 14 | { &hf_irc_response_command, { "Command", "irc.response.command", FT_STRING, BASE_NONE, |
541 | 14 | NULL, 0x0, "Response command", HFILL }}, |
542 | | |
543 | 14 | { &hf_irc_response_num_command, { "Command", "irc.response.num_command", FT_UINT16, BASE_DEC, |
544 | 14 | NULL, 0x0, "Response (numeric) command", HFILL }}, |
545 | | |
546 | 14 | { &hf_irc_response_command_param, { "Parameter", "irc.response.command_parameter", FT_STRING, BASE_NONE, |
547 | 14 | NULL, 0x0, "Response command parameter", HFILL }}, |
548 | | |
549 | 14 | { &hf_irc_response_trailer, { "Trailer", "irc.response.trailer", FT_STRING, BASE_NONE, |
550 | 14 | NULL, 0x0, "Response trailer", HFILL }}, |
551 | | |
552 | | //{ &hf_irc_ctcp, { "CTCP", "irc.ctcp", FT_STRING, BASE_NONE, |
553 | | // NULL, 0x0, NULL, HFILL }}, |
554 | | |
555 | 14 | { &hf_irc_ctcp_command, { "Command", "irc.ctcp.command", FT_STRING, BASE_NONE, |
556 | 14 | NULL, 0x0, "CTCP command", HFILL }}, |
557 | | |
558 | 14 | { &hf_irc_ctcp_params, { "Parameters", "irc.ctcp.parameters", FT_STRING, BASE_NONE, |
559 | 14 | NULL, 0x0, "CTCP parameters", HFILL }}, |
560 | 14 | }; |
561 | | |
562 | 14 | static int *ett[] = { |
563 | 14 | &ett_irc, |
564 | 14 | &ett_irc_request, |
565 | 14 | &ett_irc_request_command, |
566 | 14 | &ett_irc_response, |
567 | 14 | &ett_irc_response_command |
568 | 14 | }; |
569 | | |
570 | 14 | static ei_register_info ei[] = { |
571 | 14 | { &ei_irc_missing_end_delimiter, { "irc.missing_end_delimiter", PI_MALFORMED, PI_ERROR, "Missing ending tag delimiter (0x01)", EXPFILL }}, |
572 | 14 | { &ei_irc_tag_data_invalid, { "irc.tag_data_invalid", PI_PROTOCOL, PI_WARN, "Tag data outside of NOTICE or PRIVMSG command", EXPFILL }}, |
573 | 14 | { &ei_irc_prefix_missing_ending_space, { "irc.prefix_missing_ending_space", PI_MALFORMED, PI_ERROR, "Prefix missing ending <space>", EXPFILL }}, |
574 | 14 | { &ei_irc_request_command, { "irc.request.command.missing", PI_MALFORMED, PI_ERROR, "Request has no command", EXPFILL }}, |
575 | 14 | { &ei_irc_numeric_request_command, { "irc.request.command.numeric", PI_PROTOCOL, PI_WARN, "Numeric command not allowed in request", EXPFILL }}, |
576 | 14 | { &ei_irc_response_command, { "irc.response.command.missing", PI_MALFORMED, PI_ERROR, "Response has no command", EXPFILL }}, |
577 | 14 | }; |
578 | | |
579 | 14 | expert_module_t* expert_irc; |
580 | | |
581 | 14 | proto_irc = proto_register_protocol("Internet Relay Chat", "IRC", "irc"); |
582 | 14 | register_dissector("irc", dissect_irc, proto_irc); |
583 | 14 | proto_register_field_array(proto_irc, hf, array_length(hf)); |
584 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
585 | 14 | expert_irc = expert_register_protocol(proto_irc); |
586 | 14 | expert_register_field_array(expert_irc, ei, array_length(ei)); |
587 | | |
588 | | /* subdissector code */ |
589 | 14 | proto_irc_ctcp = proto_register_protocol_in_name_only("Client To Client Protocol", "CTCP", "irc.ctcp", proto_irc, FT_PROTOCOL); |
590 | | |
591 | | /* compile patterns */ |
592 | 14 | ws_mempbrk_compile(&pbrk_tag_delimiter, TAG_DELIMITER); |
593 | 14 | } |
594 | | |
595 | | void |
596 | | proto_reg_handoff_irc(void) |
597 | 14 | { |
598 | 14 | dissector_add_uint_range_with_preference("tcp.port", TCP_PORT_RANGE, find_dissector("irc")); |
599 | | |
600 | 14 | ctcp_handle = create_dissector_handle(dissect_irc_ctcp, proto_irc_ctcp); |
601 | 14 | } |
602 | | |
603 | | /* |
604 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
605 | | * |
606 | | * Local variables: |
607 | | * c-basic-offset: 4 |
608 | | * tab-width: 8 |
609 | | * indent-tabs-mode: nil |
610 | | * End: |
611 | | * |
612 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
613 | | * :indentSize=4:tabSize=8:noTabs=true: |
614 | | */ |