3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * Copied from packet-tftp.c
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 * Routines for IRC packet dissection
17 * http://www.irchelp.org/irchelp/rfc/
19 * and the RFCs and other documents it mentions, such as RFC 1459, RFCs
20 * 2810, 2811, 2812, and 2813,
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
30 #include <epan/packet.h>
31 #include <epan/expert.h>
33 void proto_register_irc(void);
34 void proto_reg_handoff_irc(void);
37 static int proto_irc_ctcp
;
38 static int hf_irc_request
;
39 static int hf_irc_request_prefix
;
40 static int hf_irc_request_command
;
41 static int hf_irc_request_command_param
;
42 static int hf_irc_request_trailer
;
43 static int hf_irc_response
;
44 static int hf_irc_response_prefix
;
45 static int hf_irc_response_command
;
46 static int hf_irc_response_num_command
;
47 static int hf_irc_response_command_param
;
48 static int hf_irc_response_trailer
;
49 static int hf_irc_ctcp
;
50 static int hf_irc_ctcp_command
;
51 static int hf_irc_ctcp_params
;
54 static int ett_irc_request
;
55 static int ett_irc_request_command
;
56 static int ett_irc_response
;
57 static int ett_irc_response_command
;
59 static expert_field ei_irc_missing_end_delimiter
;
60 static expert_field ei_irc_numeric_request_command
;
61 static expert_field ei_irc_response_command
;
62 static expert_field ei_irc_prefix_missing_ending_space
;
63 static expert_field ei_irc_request_command
;
64 static expert_field ei_irc_tag_data_invalid
;
66 /* This must be a null-terminated string */
67 static const uint8_t TAG_DELIMITER
[] = {0x01, 0x00};
68 /* patterns used for tvb_ws_mempbrk_pattern_uint8 */
69 static ws_mempbrk_pattern pbrk_tag_delimiter
;
71 static dissector_handle_t ctcp_handle
;
73 #define TCP_PORT_RANGE "6667,57000" /* Not IANA registered */
76 dissect_irc_ctcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
78 proto_tree
*ctcp_tree
;
80 const uint8_t *str_command
, *str_params
;
81 int space_offset
= -1;
83 ti
= proto_tree_add_item(tree
, hf_irc_ctcp
, tvb
, 0, -1, ENC_ASCII
|ENC_NA
);
84 ctcp_tree
= proto_item_add_subtree(ti
, ett_irc
);
86 space_offset
= tvb_find_uint8(tvb
, 1, -1, ' ');
87 if (space_offset
== -1) {
88 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
);
91 proto_tree_add_item_ret_string(ctcp_tree
, hf_irc_ctcp_command
, tvb
, 0, space_offset
, ENC_ASCII
|ENC_NA
, pinfo
->pool
, &str_command
);
92 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
);
95 return tvb_captured_length(tvb
);
99 dissect_irc_tag_data(proto_tree
*tree
, proto_item
*item
, tvbuff_t
*tvb
, int offset
, int datalen
, packet_info
*pinfo
, const uint8_t* command
)
101 unsigned char found_start_needle
= 0,
102 found_end_needle
= 0;
103 int tag_start_offset
, tag_end_offset
;
106 tag_start_offset
= tvb_ws_mempbrk_pattern_uint8(tvb
, offset
, datalen
, &pbrk_tag_delimiter
, &found_start_needle
);
107 if (tag_start_offset
== -1)
113 tag_end_offset
= tvb_ws_mempbrk_pattern_uint8(tvb
, tag_start_offset
+1, datalen
, &pbrk_tag_delimiter
, &found_end_needle
);
114 if (tag_end_offset
== -1)
116 expert_add_info(pinfo
, item
, &ei_irc_missing_end_delimiter
);
120 if ((strcmp(command
, "NOTICE") != 0) &&
121 (strcmp(command
, "PRIVMSG") != 0))
123 expert_add_info(pinfo
, item
, &ei_irc_tag_data_invalid
);
126 /* Placeholder to call CTCP dissector, strip out delimiter */
128 next_tvb
= tvb_new_subset_length(tvb
, tag_start_offset
+1, datalen
-2 );
129 dissect_irc_ctcp(next_tvb
, pinfo
, tree
, NULL
);
134 dissect_irc_request(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
, int offset
, int linelen
)
136 proto_tree
*request_tree
, *command_tree
= NULL
;
137 proto_item
*request_item
;
138 int start_offset
= offset
;
139 int end_offset
= start_offset
+linelen
;
143 tag_start_offset
, tag_end_offset
;
144 const uint8_t *str_command
;
145 unsigned char found_tag_needle
= 0;
146 bool first_command_param
= true;
148 request_item
= proto_tree_add_item(tree
, hf_irc_request
, tvb
, offset
, linelen
, ENC_ASCII
);
152 request_tree
= proto_item_add_subtree(request_item
, ett_irc_request
);
154 /* Check if message has a prefix */
155 if (tvb_get_uint8(tvb
, offset
) == ':')
157 /* find the end of the prefix */
158 eop_offset
= tvb_find_uint8(tvb
, offset
+1, linelen
-1, ' ');
159 if (eop_offset
== -1)
161 expert_add_info(pinfo
, request_item
, &ei_irc_prefix_missing_ending_space
);
165 proto_tree_add_item(request_tree
, hf_irc_request_prefix
, tvb
, offset
+1, eop_offset
-offset
-1, ENC_ASCII
);
166 offset
= eop_offset
+1;
169 /* clear out any whitespace before command */
170 while(offset
< end_offset
&& tvb_get_uint8(tvb
, offset
) == ' ')
174 if (offset
== end_offset
)
176 expert_add_info(pinfo
, request_item
, &ei_irc_request_command
);
180 eoc_offset
= tvb_find_uint8(tvb
, offset
, end_offset
-offset
, ' ');
181 if (eoc_offset
== -1)
183 const uint8_t* col_str
;
184 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
);
185 col_append_fstr( pinfo
->cinfo
, COL_INFO
, " (%s)", col_str
);
187 /* Warn if there is a "numeric" command */
188 if ((end_offset
-offset
== 3) &&
189 (g_ascii_isdigit(tvb_get_uint8(tvb
, offset
))) &&
190 (g_ascii_isdigit(tvb_get_uint8(tvb
, offset
+1))) &&
191 (g_ascii_isdigit(tvb_get_uint8(tvb
, offset
+2))))
193 expert_add_info(pinfo
, request_item
, &ei_irc_numeric_request_command
);
198 proto_tree_add_item_ret_string(request_tree
, hf_irc_request_command
, tvb
, offset
, eoc_offset
-offset
, ENC_ASCII
|ENC_NA
, pinfo
->pool
, &str_command
);
199 col_append_fstr( pinfo
->cinfo
, COL_INFO
, " (%s)", str_command
);
201 /* Warn if there is a "numeric" command */
202 if ((eoc_offset
-offset
== 3) &&
203 (g_ascii_isdigit(tvb_get_uint8(tvb
, offset
))) &&
204 (g_ascii_isdigit(tvb_get_uint8(tvb
, offset
+1))) &&
205 (g_ascii_isdigit(tvb_get_uint8(tvb
, offset
+2))))
207 expert_add_info(pinfo
, request_item
, &ei_irc_numeric_request_command
);
210 offset
= eoc_offset
+1;
212 /* clear out any whitespace before command parameter */
213 while(offset
< end_offset
&& tvb_get_uint8(tvb
, offset
) == ' ')
217 if (offset
== end_offset
)
219 /* No command parameters */
223 /* Check if message has a trailer */
224 if (tvb_get_uint8(tvb
, offset
) == ':')
226 proto_tree_add_item(request_tree
, hf_irc_request_trailer
, tvb
, offset
+1, end_offset
-offset
-1, ENC_ASCII
);
227 dissect_irc_tag_data(request_tree
, request_item
, tvb
, offset
+1, end_offset
-offset
-1, pinfo
, str_command
);
231 while(offset
< end_offset
)
233 eocp_offset
= tvb_find_uint8(tvb
, offset
, end_offset
-offset
, ' ');
234 tag_start_offset
= tvb_ws_mempbrk_pattern_uint8(tvb
, offset
, end_offset
-offset
, &pbrk_tag_delimiter
, &found_tag_needle
);
236 /* Create subtree when the first parameter is found */
237 if (first_command_param
)
239 command_tree
= proto_tree_add_subtree(request_tree
, tvb
, offset
, end_offset
-offset
,
240 ett_irc_request_command
, NULL
, "Command parameters");
241 first_command_param
= false;
244 if (((eocp_offset
== -1) && (tag_start_offset
== -1)) ||
245 ((eocp_offset
!= -1) && (tag_start_offset
== -1)) ||
246 (eocp_offset
< tag_start_offset
))
248 /* regular message should be dissected */
250 if (eocp_offset
== -1)
252 proto_tree_add_item(command_tree
, hf_irc_request_command_param
, tvb
, offset
, end_offset
-offset
, ENC_ASCII
);
256 proto_tree_add_item(command_tree
, hf_irc_request_command_param
, tvb
, offset
, eocp_offset
-offset
, ENC_ASCII
);
257 offset
= eocp_offset
+1;
259 /* clear out any whitespace before next command parameter */
260 while(offset
< end_offset
&& tvb_get_uint8(tvb
, offset
) == ' ')
264 if (offset
== end_offset
)
269 /* Check if message has a trailer */
270 if (tvb_get_uint8(tvb
, offset
) == ':')
272 proto_tree_add_item(request_tree
, hf_irc_request_trailer
, tvb
, offset
+1, end_offset
-offset
-1, ENC_ASCII
);
273 dissect_irc_tag_data(request_tree
, request_item
, tvb
, offset
+1, end_offset
-offset
-1, pinfo
, str_command
);
277 else if (((eocp_offset
== -1) && (tag_start_offset
!= -1)) ||
278 (eocp_offset
> tag_start_offset
))
280 /* tag data dissected */
282 found_tag_needle
= 0;
283 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
);
284 if (tag_end_offset
== -1)
286 expert_add_info(pinfo
, request_item
, &ei_irc_missing_end_delimiter
);
290 dissect_irc_tag_data(request_tree
, request_item
, tvb
, tag_start_offset
, tag_end_offset
-tag_start_offset
, pinfo
, str_command
);
291 offset
= tag_end_offset
+1;
297 dissect_irc_response(proto_tree
*tree
, tvbuff_t
*tvb
, packet_info
*pinfo
, int offset
, int linelen
)
299 proto_tree
*response_tree
, *command_tree
= NULL
;
300 proto_item
*response_item
, *hidden_item
;
301 int start_offset
= offset
;
302 int end_offset
= start_offset
+linelen
;
306 tag_start_offset
, tag_end_offset
;
307 const uint8_t* str_command
;
308 uint16_t num_command
;
309 unsigned char found_tag_needle
= 0;
310 bool first_command_param
= true;
312 response_item
= proto_tree_add_item(tree
, hf_irc_response
, tvb
, offset
, linelen
, ENC_ASCII
);
316 response_tree
= proto_item_add_subtree(response_item
, ett_irc_response
);
318 /* Check if message has a prefix */
319 if (tvb_get_uint8(tvb
, offset
) == ':')
321 /* find the end of the prefix */
322 eop_offset
= tvb_find_uint8(tvb
, offset
+1, linelen
-1, ' ');
323 if (eop_offset
== -1)
325 expert_add_info(pinfo
, response_item
, &ei_irc_prefix_missing_ending_space
);
329 proto_tree_add_item(response_tree
, hf_irc_response_prefix
, tvb
, offset
+1, eop_offset
-offset
-1, ENC_ASCII
);
330 offset
= eop_offset
+1;
333 /* clear out any whitespace before command */
334 while(offset
< end_offset
&& tvb_get_uint8(tvb
, offset
) == ' ')
338 if (offset
== end_offset
)
340 expert_add_info(pinfo
, response_item
, &ei_irc_response_command
);
344 eoc_offset
= tvb_find_uint8(tvb
, offset
, end_offset
-offset
, ' ');
345 if (eoc_offset
== -1)
347 const uint8_t* col_str
;
348 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
);
349 col_append_fstr( pinfo
->cinfo
, COL_INFO
, " (%s)", col_str
);
351 /* if response command is numeric, allow it to be filtered as an integer */
352 if ((end_offset
-offset
== 3) &&
353 (g_ascii_isdigit(tvb_get_uint8(tvb
, offset
))) &&
354 (g_ascii_isdigit(tvb_get_uint8(tvb
, offset
+1))) &&
355 (g_ascii_isdigit(tvb_get_uint8(tvb
, offset
+2))))
357 num_command
= ((tvb_get_uint8(tvb
, offset
)-0x30)*100) + ((tvb_get_uint8(tvb
, offset
+1)-0x30)*10) + (tvb_get_uint8(tvb
, offset
+2)-0x30);
358 hidden_item
= proto_tree_add_uint(response_tree
, hf_irc_response_num_command
, tvb
, offset
, end_offset
-offset
, num_command
);
359 proto_item_set_hidden(hidden_item
);
364 proto_tree_add_item_ret_string(response_tree
, hf_irc_response_command
, tvb
, offset
, eoc_offset
-offset
, ENC_ASCII
|ENC_NA
, pinfo
->pool
, &str_command
);
365 col_append_fstr( pinfo
->cinfo
, COL_INFO
, " (%s)", str_command
);
367 /* if response command is numeric, allow it to be filtered as an integer */
368 if ((eoc_offset
-offset
== 3) &&
369 (g_ascii_isdigit(tvb_get_uint8(tvb
, offset
))) &&
370 (g_ascii_isdigit(tvb_get_uint8(tvb
, offset
+1))) &&
371 (g_ascii_isdigit(tvb_get_uint8(tvb
, offset
+2))))
373 num_command
= ((tvb_get_uint8(tvb
, offset
)-0x30)*100) + ((tvb_get_uint8(tvb
, offset
+1)-0x30)*10) + (tvb_get_uint8(tvb
, offset
+2)-0x30);
374 hidden_item
= proto_tree_add_uint(response_tree
, hf_irc_response_num_command
, tvb
, offset
, eoc_offset
-offset
, num_command
);
375 proto_item_set_hidden(hidden_item
);
378 offset
= eoc_offset
+1;
380 /* clear out any whitespace before command parameter */
381 while(offset
< end_offset
&& tvb_get_uint8(tvb
, offset
) == ' ')
385 if (offset
== end_offset
)
387 /* No command parameters */
391 /* Check if message has a trailer */
392 if (tvb_get_uint8(tvb
, offset
) == ':')
394 proto_tree_add_item(response_tree
, hf_irc_response_trailer
, tvb
, offset
+1, end_offset
-offset
-1, ENC_ASCII
);
395 dissect_irc_tag_data(response_tree
, response_item
, tvb
, offset
+1, end_offset
-offset
-1, pinfo
, str_command
);
399 while(offset
< end_offset
)
401 eocp_offset
= tvb_find_uint8(tvb
, offset
, end_offset
-offset
, ' ');
402 tag_start_offset
= tvb_ws_mempbrk_pattern_uint8(tvb
, offset
, end_offset
-offset
, &pbrk_tag_delimiter
, &found_tag_needle
);
404 /* Create subtree when the first parameter is found */
405 if (first_command_param
)
407 command_tree
= proto_tree_add_subtree(response_tree
, tvb
, offset
, end_offset
-offset
,
408 ett_irc_response_command
, NULL
, "Command parameters");
409 first_command_param
= false;
412 if ((tag_start_offset
== -1) || (eocp_offset
< tag_start_offset
))
414 /* regular message should be dissected */
416 if (eocp_offset
== -1)
418 proto_tree_add_item(command_tree
, hf_irc_response_command_param
, tvb
, offset
, end_offset
-offset
, ENC_ASCII
);
422 proto_tree_add_item(command_tree
, hf_irc_response_command_param
, tvb
, offset
, eocp_offset
-offset
, ENC_ASCII
);
423 offset
= eocp_offset
+1;
425 /* clear out any whitespace before next command parameter */
426 while(offset
< end_offset
&& tvb_get_uint8(tvb
, offset
) == ' ')
430 if (offset
== end_offset
)
435 /* Check if message has a trailer */
436 if (tvb_get_uint8(tvb
, offset
) == ':')
438 proto_tree_add_item(response_tree
, hf_irc_response_trailer
, tvb
, offset
+1, end_offset
-offset
-1, ENC_ASCII
);
439 dissect_irc_tag_data(response_tree
, response_item
, tvb
, offset
+1, end_offset
-offset
-1, pinfo
, str_command
);
443 else if ((eocp_offset
== -1) || (eocp_offset
> tag_start_offset
))
445 /* tag data dissected */
447 found_tag_needle
= 0;
448 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
);
449 if (tag_end_offset
== -1)
451 expert_add_info(pinfo
, response_item
, &ei_irc_missing_end_delimiter
);
455 dissect_irc_tag_data(response_tree
, response_item
, tvb
, tag_start_offset
, tag_end_offset
-tag_start_offset
, pinfo
, str_command
);
456 offset
= tag_end_offset
+1;
462 dissect_irc(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
464 proto_tree
*irc_tree
, *ti
;
469 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "IRC");
471 col_set_str(pinfo
->cinfo
, COL_INFO
,
472 (pinfo
->match_uint
== pinfo
->destport
) ? "Request" : "Response");
474 ti
= proto_tree_add_item(tree
, proto_irc
, tvb
, 0, -1, ENC_NA
);
475 irc_tree
= proto_item_add_subtree(ti
, ett_irc
);
478 * Process the packet data, a line at a time.
480 while (tvb_offset_exists(tvb
, offset
))
483 * Find the end of the line.
485 linelen
= tvb_find_line_end(tvb
, offset
, -1, &next_offset
, false);
486 if (next_offset
== offset
) {
488 * XXX - we really want the "show data a
489 * line at a time" loops in various
490 * dissectors to do reassembly and to
491 * throw an exception if there's no
492 * line ending in the current packet
493 * and we're not doing reassembly.
500 if (pinfo
->match_uint
== pinfo
->destport
)
502 dissect_irc_request(irc_tree
, tvb
, pinfo
, offset
, linelen
);
506 dissect_irc_response(irc_tree
, tvb
, pinfo
, offset
, linelen
);
509 offset
= next_offset
;
511 return tvb_captured_length(tvb
);
515 proto_register_irc(void)
517 static hf_register_info hf
[] = {
518 { &hf_irc_response
, { "Response", "irc.response", FT_STRING
, BASE_NONE
,
519 NULL
, 0x0, "Line of response message", HFILL
}},
521 { &hf_irc_request
, { "Request", "irc.request", FT_STRING
, BASE_NONE
,
522 NULL
, 0x0, "Line of request message", HFILL
}},
524 { &hf_irc_request_prefix
, { "Prefix", "irc.request.prefix", FT_STRING
, BASE_NONE
,
525 NULL
, 0x0, "Request prefix", HFILL
}},
527 { &hf_irc_request_command
, { "Command", "irc.request.command", FT_STRING
, BASE_NONE
,
528 NULL
, 0x0, "Request command", HFILL
}},
530 { &hf_irc_request_command_param
, { "Parameter", "irc.request.command_parameter", FT_STRING
, BASE_NONE
,
531 NULL
, 0x0, "Request command parameter", HFILL
}},
533 { &hf_irc_request_trailer
, { "Trailer", "irc.request.trailer", FT_STRING
, BASE_NONE
,
534 NULL
, 0x0, "Request trailer", HFILL
}},
536 { &hf_irc_response_prefix
, { "Prefix", "irc.response.prefix", FT_STRING
, BASE_NONE
,
537 NULL
, 0x0, "Response prefix", HFILL
}},
539 { &hf_irc_response_command
, { "Command", "irc.response.command", FT_STRING
, BASE_NONE
,
540 NULL
, 0x0, "Response command", HFILL
}},
542 { &hf_irc_response_num_command
, { "Command", "irc.response.num_command", FT_UINT16
, BASE_DEC
,
543 NULL
, 0x0, "Response (numeric) command", HFILL
}},
545 { &hf_irc_response_command_param
, { "Parameter", "irc.response.command_parameter", FT_STRING
, BASE_NONE
,
546 NULL
, 0x0, "Response command parameter", HFILL
}},
548 { &hf_irc_response_trailer
, { "Trailer", "irc.response.trailer", FT_STRING
, BASE_NONE
,
549 NULL
, 0x0, "Response trailer", HFILL
}},
551 { &hf_irc_ctcp
, { "CTCP", "irc.ctcp", FT_STRING
, BASE_NONE
,
552 NULL
, 0x0, NULL
, HFILL
}},
554 { &hf_irc_ctcp_command
, { "Command", "irc.ctcp.command", FT_STRING
, BASE_NONE
,
555 NULL
, 0x0, "CTCP command", HFILL
}},
557 { &hf_irc_ctcp_params
, { "Parameters", "irc.ctcp.parameters", FT_STRING
, BASE_NONE
,
558 NULL
, 0x0, "CTCP parameters", HFILL
}},
561 static int *ett
[] = {
564 &ett_irc_request_command
,
566 &ett_irc_response_command
569 static ei_register_info ei
[] = {
570 { &ei_irc_missing_end_delimiter
, { "irc.missing_end_delimiter", PI_MALFORMED
, PI_ERROR
, "Missing ending tag delimiter (0x01)", EXPFILL
}},
571 { &ei_irc_tag_data_invalid
, { "irc.tag_data_invalid", PI_PROTOCOL
, PI_WARN
, "Tag data outside of NOTICE or PRIVMSG command", EXPFILL
}},
572 { &ei_irc_prefix_missing_ending_space
, { "irc.prefix_missing_ending_space", PI_MALFORMED
, PI_ERROR
, "Prefix missing ending <space>", EXPFILL
}},
573 { &ei_irc_request_command
, { "irc.request.command.missing", PI_MALFORMED
, PI_ERROR
, "Request has no command", EXPFILL
}},
574 { &ei_irc_numeric_request_command
, { "irc.request.command.numeric", PI_PROTOCOL
, PI_WARN
, "Numeric command not allowed in request", EXPFILL
}},
575 { &ei_irc_response_command
, { "irc.response.command.missing", PI_MALFORMED
, PI_ERROR
, "Response has no command", EXPFILL
}},
578 expert_module_t
* expert_irc
;
580 proto_irc
= proto_register_protocol("Internet Relay Chat", "IRC", "irc");
581 register_dissector("irc", dissect_irc
, proto_irc
);
582 proto_register_field_array(proto_irc
, hf
, array_length(hf
));
583 proto_register_subtree_array(ett
, array_length(ett
));
584 expert_irc
= expert_register_protocol(proto_irc
);
585 expert_register_field_array(expert_irc
, ei
, array_length(ei
));
587 /* subdissector code */
588 proto_irc_ctcp
= proto_register_protocol_in_name_only("Client To Client Protocol", "CTCP", "irc.ctcp", proto_irc
, FT_PROTOCOL
);
590 /* compile patterns */
591 ws_mempbrk_compile(&pbrk_tag_delimiter
, TAG_DELIMITER
);
595 proto_reg_handoff_irc(void)
597 dissector_add_uint_range_with_preference("tcp.port", TCP_PORT_RANGE
, find_dissector("irc"));
599 ctcp_handle
= create_dissector_handle(dissect_irc_ctcp
, proto_irc_ctcp
);
603 * Editor modelines - https://www.wireshark.org/tools/modelines.html
608 * indent-tabs-mode: nil
611 * vi: set shiftwidth=4 tabstop=8 expandtab:
612 * :indentSize=4:tabSize=8:noTabs=true: