Coverage Report

Created: 2026-07-12 07:10

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