Coverage Report

Created: 2025-12-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
 */