Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/epan/dissectors/packet-git.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-git.c
2
 * Routines for git packet dissection
3
 * Copyright 2010, Jelmer Vernooij <jelmer@samba.org>
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * Copied from packet-pop.c
10
 *
11
 * SPDX-License-Identifier: GPL-2.0-or-later
12
 *
13
 * Current testing suite 'case_dissect_git' can be found at
14
 * test/suite_dissection.py
15
 */
16
17
#include "config.h"
18
19
#include <stdio.h>    /* for sscanf() */
20
21
#include <epan/packet.h>
22
#include <epan/expert.h>
23
#include <epan/prefs.h>
24
#include "packet-tcp.h"
25
26
void proto_register_git(void);
27
void proto_reg_handoff_git(void);
28
29
static dissector_handle_t git_handle;
30
31
static int proto_git;
32
static expert_field ei_git_bad_pkt_len;
33
static expert_field ei_git_malformed;
34
35
static int ett_git;
36
37
static int hf_git_protocol_version;
38
static int hf_git_packet_type;
39
static int hf_git_packet_len;
40
static int hf_git_packet_data;
41
static int hf_git_sideband_control_code;
42
static int hf_git_upload_pack_adv;
43
static int hf_git_upload_pack_req;
44
static int hf_git_upload_pack_res;
45
46
14
#define PNAME  "Git Smart Protocol"
47
14
#define PSNAME "Git"
48
28
#define PFNAME "git"
49
50
14
#define TCP_PORT_GIT    9418
51
52
static const value_string packet_type_vals[] = {
53
  { 0, "Flush" },
54
  { 1, "Delimiter" },
55
  { 2, "Response end" },
56
  { 0, NULL }
57
};
58
59
static const value_string version_vals[] = {
60
  { '1', "Git protocol version 1" },
61
  { '2', "Git protocol version 2" },
62
  { 0, NULL }
63
};
64
65
#define SIDEBAND_PACKFILE_DATA 0x01
66
#define SIDEBAND_PROGRESS_INFO 0x02
67
#define SIDEBAND_ERROR_INFO 0x03
68
static const value_string sideband_vals[] = {
69
  { SIDEBAND_PACKFILE_DATA, "Git packfile data" },
70
  { SIDEBAND_PROGRESS_INFO, "Git progress data" },
71
  { SIDEBAND_ERROR_INFO, "Git error data" },
72
  { 0, NULL }
73
};
74
75
/* desegmentation of Git over TCP */
76
static bool git_desegment = true;
77
78
static bool get_packet_length(tvbuff_t *tvb, int offset,
79
                                  uint16_t *length)
80
0
{
81
0
  uint8_t *lenstr;
82
83
0
  lenstr = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, 4, ENC_ASCII);
84
85
0
  return (sscanf(lenstr, "%hx", length) == 1);
86
0
}
87
88
static unsigned
89
get_git_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
90
0
{
91
0
  uint16_t plen;
92
93
0
  if (!get_packet_length(tvb, offset, &plen))
94
0
    return 0; /* No idea what this is */
95
96
0
  return plen < 4
97
0
      ? 4   // Special packet (e.g., flush-pkt)
98
0
      : plen;
99
0
}
100
101
/* Parse pkt-lines one-by-one
102
 *
103
 * @param  tvb       The buffer to dissect.
104
 * @param  pinfo     Packet info associated to this buffer.
105
 * @param  git_tree  The git protocol subtree.
106
 * @param  offset    The offset at which to start the dissection.
107
 * @return bool      After successful/unsuccessful parsing.
108
 *
109
 * This new helper takes the contents of the tvbuffer, updates the
110
 * offset, and returns to the caller for subsequent processing of the
111
 * remainder of the data.
112
*/
113
static bool
114
dissect_pkt_line(tvbuff_t *tvb, packet_info *pinfo, proto_tree *git_tree,
115
                 int *offset)
116
0
{
117
0
  uint16_t plen;
118
119
  // what type of pkt-line is it?
120
0
  if (!get_packet_length(tvb, *offset, &plen))
121
0
    return false;
122
0
  if (plen < 4) {   // a special packet (e.g., flush-pkt)
123
0
    proto_item *ti =
124
0
        proto_tree_add_uint(git_tree, hf_git_packet_type, tvb,
125
0
                            *offset, 4, plen);
126
0
    *offset += 4;
127
128
0
    if (!try_val_to_str(plen, packet_type_vals))
129
0
      expert_add_info(pinfo, ti, &ei_git_bad_pkt_len);
130
0
    return true;
131
0
  }
132
133
0
  proto_tree_add_uint(git_tree, hf_git_packet_len, tvb, *offset, 4, plen);
134
0
  *offset += 4;
135
0
  plen -= 4;
136
137
  /*
138
   * Parse out the version of the Git Protocol
139
   *
140
   * The initial server response contains the version of the Git Protocol in use;
141
   * 1 or 2. Parsing out this information helps identify the capabilities and
142
   * information that can be used with the protocol.
143
  */
144
0
  if (plen >= 9 && !tvb_strneql(tvb, *offset, "version ", 8)) {
145
0
    proto_tree_add_item(git_tree, hf_git_protocol_version, tvb, *offset + 8,
146
0
                        1, ENC_NA);
147
0
  }
148
149
  /*
150
   * Parse out the sideband control code.
151
   *
152
   * Not all pkt-lines have a sideband control code. With more context from the rest of
153
   * the request or response, we would be able to tell whether sideband is expected here;
154
   * lacking that, let's assume for now that all pkt-lines starting with \1, \2, or \3
155
   * are using sideband.
156
   */
157
0
  int sideband_code = tvb_get_uint8(tvb, *offset);
158
159
0
  if (1 <= sideband_code && sideband_code <= 3) {
160
0
    proto_tree_add_uint(git_tree, hf_git_sideband_control_code, tvb, *offset, 1,
161
0
                        sideband_code);
162
0
    (*offset)++;
163
0
    plen--;
164
0
  }
165
166
0
  proto_tree_add_item(git_tree, hf_git_packet_data, tvb, *offset, plen, ENC_NA);
167
0
  *offset += plen;
168
0
  return true;
169
0
}
170
171
static int
172
dissect_git_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
173
0
{
174
0
  proto_tree             *git_tree;
175
0
  proto_item             *ti;
176
0
  int offset = 0;
177
178
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME);
179
180
0
  col_set_str(pinfo->cinfo, COL_INFO, PNAME);
181
182
0
  ti = proto_tree_add_item(tree, proto_git, tvb, offset, -1, ENC_NA);
183
0
  git_tree = proto_item_add_subtree(ti, ett_git);
184
185
0
  if (!dissect_pkt_line(tvb, pinfo, git_tree, &offset))
186
0
    return 0;
187
188
0
  return tvb_captured_length(tvb);
189
0
}
190
191
/* Parse http packs
192
 *
193
 * @param  tvb        The buffer to dissect.
194
 * @param  pinfo      The Packet Info.
195
 * @param  tree       The protocol tree.
196
 * @param  hfindex    The type of http pack.
197
 * @return tvb_length The amount of captured data in the buffer,
198
 *                    returns 0 if parsing failed.
199
 *
200
 * This new helper takes the contents of the tvbuffer sent by http
201
 * dissectors, adds the packs to the git subtree and returns the amount
202
 * of consumed bytes in the tvb buffer.
203
*/
204
static int
205
dissect_http_pkt_lines(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int hfindex)
206
0
{
207
0
  proto_tree             *git_tree;
208
0
  proto_item             *ti;
209
0
  int offset = 0;
210
0
  int total_len = 0;
211
212
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, PSNAME);
213
214
0
  col_set_str(pinfo->cinfo, COL_INFO, PNAME);
215
216
0
  ti = proto_tree_add_item(tree, proto_git, tvb, offset, -1, ENC_NA);
217
0
  git_tree = proto_item_add_subtree(ti, ett_git);
218
219
0
  proto_tree_add_item(git_tree, hfindex, tvb, offset,
220
0
                      tvb_captured_length(tvb), ENC_NA);
221
222
0
  total_len = tvb_reported_length(tvb);
223
0
  while (offset < total_len) {
224
    /* Add expert info if there is trouble parsing part-way through */
225
0
    if (!dissect_pkt_line(tvb, pinfo, git_tree, &offset)) {
226
0
      proto_tree_add_expert(git_tree, pinfo, &ei_git_malformed, tvb, offset, -1);
227
0
      break;
228
0
    }
229
0
  }
230
231
0
  return tvb_captured_length(tvb);
232
0
}
233
234
static int
235
dissect_git_upload_pack_adv(tvbuff_t *tvb, packet_info *pinfo,
236
                            proto_tree *tree, void *data _U_)
237
0
{
238
0
  return dissect_http_pkt_lines(tvb, pinfo, tree, hf_git_upload_pack_adv);
239
0
}
240
241
static int
242
dissect_git_upload_pack_req(tvbuff_t *tvb, packet_info *pinfo,
243
                            proto_tree *tree, void *data _U_)
244
0
{
245
0
  return dissect_http_pkt_lines(tvb, pinfo, tree, hf_git_upload_pack_req);
246
0
}
247
248
static int
249
dissect_git_upload_pack_res(tvbuff_t *tvb, packet_info *pinfo,
250
                            proto_tree *tree, void *data _U_)
251
0
{
252
0
  return dissect_http_pkt_lines(tvb, pinfo, tree, hf_git_upload_pack_res);
253
0
}
254
255
static int
256
dissect_git(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
257
0
{
258
0
  tcp_dissect_pdus(tvb, pinfo, tree, git_desegment, 4, get_git_pdu_len,
259
0
                   dissect_git_pdu, data);
260
0
  return tvb_captured_length(tvb);
261
0
}
262
263
void
264
proto_register_git(void)
265
14
{
266
14
  static hf_register_info hf[] = {
267
14
    { &hf_git_protocol_version,
268
14
      { "Git Protocol Version", "git.version", FT_UINT8, BASE_NONE, VALS(version_vals),
269
14
      0, NULL, HFILL },
270
14
    },
271
14
    { &hf_git_packet_type,
272
14
      { "Git Packet Type", "git.packet_type", FT_UINT8, BASE_NONE, VALS(packet_type_vals),
273
14
      0, NULL, HFILL },
274
14
    },
275
14
    { &hf_git_packet_len,
276
14
      { "Packet length", "git.length", FT_UINT16, BASE_HEX, NULL, 0x0, NULL, HFILL },
277
14
    },
278
14
    { &hf_git_packet_data,
279
14
      { "Packet data", "git.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL },
280
14
    },
281
14
    { &hf_git_sideband_control_code,
282
14
      { "Sideband control code", "git.sideband_control_code", FT_UINT8,
283
14
      BASE_HEX, VALS(sideband_vals), 0, NULL, HFILL },
284
14
    },
285
14
    { &hf_git_upload_pack_adv,
286
14
      { "Upload Pack Advertisement", "git.upload_pack_advertisement",
287
14
      FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL },
288
14
    },
289
14
    { &hf_git_upload_pack_req,
290
14
      { "Upload Pack Request", "git.upload_pack_request",
291
14
      FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL },
292
14
    },
293
14
    { &hf_git_upload_pack_res,
294
14
      { "Upload Pack Result", "git.upload_pack_result",
295
14
      FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL },
296
14
    },
297
14
  };
298
299
14
  static int *ett[] = {
300
14
    &ett_git,
301
14
  };
302
303
14
  static ei_register_info ei[] = {
304
14
    { &ei_git_bad_pkt_len,
305
14
      { "git.bad_pkt_len", PI_PROTOCOL, PI_ERROR,
306
14
        "unrecognized special pkt-len value", EXPFILL }
307
14
    },
308
14
    { &ei_git_malformed,
309
14
      { "git.malformed", PI_MALFORMED, PI_ERROR,
310
14
        "malformed packet", EXPFILL }
311
14
    },
312
14
  };
313
314
14
  module_t *git_module;
315
14
  expert_module_t *expert_git;
316
317
14
  proto_git = proto_register_protocol(PNAME, PSNAME, PFNAME);
318
14
  proto_register_field_array(proto_git, hf, array_length(hf));
319
14
  proto_register_subtree_array(ett, array_length(ett));
320
321
14
  expert_git = expert_register_protocol(proto_git);
322
14
  expert_register_field_array(expert_git, ei, array_length(ei));
323
324
14
  git_handle = register_dissector(PFNAME, dissect_git, proto_git);
325
326
14
  git_module = prefs_register_protocol(proto_git, NULL);
327
328
14
  prefs_register_bool_preference(git_module, "desegment",
329
14
                                 "Reassemble GIT messages spanning multiple TCP segments",
330
14
                                 "Whether the GIT dissector should reassemble messages spanning multiple TCP segments."
331
14
                                 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
332
14
                                 &git_desegment);
333
14
}
334
335
void
336
proto_reg_handoff_git(void)
337
14
{
338
  /*
339
   * Add the dissectors for GIT over HTTP
340
   *
341
   * Reference documentation at
342
   * https://www.kernel.org/pub/software/scm/git/docs//technical/http-protocol.txt
343
   */
344
14
  dissector_handle_t git_upload_pack_adv_handle;
345
14
  dissector_handle_t git_upload_pack_req_handle;
346
14
  dissector_handle_t git_upload_pack_res_handle;
347
348
14
  git_upload_pack_adv_handle = create_dissector_handle(dissect_git_upload_pack_adv,
349
14
                        proto_git);
350
351
14
  git_upload_pack_req_handle = create_dissector_handle(dissect_git_upload_pack_req,
352
14
                        proto_git);
353
354
14
  git_upload_pack_res_handle = create_dissector_handle(dissect_git_upload_pack_res,
355
14
                        proto_git);
356
357
14
  dissector_add_string("media_type",
358
14
                        "application/x-git-upload-pack-advertisement",
359
14
                        git_upload_pack_adv_handle);
360
14
  dissector_add_string("media_type",
361
14
                        "application/x-git-upload-pack-request",
362
14
                        git_upload_pack_req_handle);
363
14
  dissector_add_string("media_type",
364
14
                        "application/x-git-upload-pack-result",
365
14
                        git_upload_pack_res_handle);
366
367
14
  dissector_add_uint_with_preference("tcp.port", TCP_PORT_GIT, git_handle);
368
14
}
369
370
/*
371
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
372
 *
373
 * Local Variables:
374
 * c-basic-offset: 2
375
 * tab-width: 8
376
 * indent-tabs-mode: nil
377
 * End:
378
 *
379
 * ex: set shiftwidth=2 tabstop=8 expandtab:
380
 * :indentSize=2:tabSize=8:noTabs=true:
381
 */