/src/wireshark/epan/dissectors/packet-vsock.c
Line | Count | Source |
1 | | /* packet-vsock.c |
2 | | * Routines for AF_VSOCK dissection |
3 | | * Copyright 2016, Gerard Garcia <ggarcia@deic.uab.cat> |
4 | | * |
5 | | * Header definition: |
6 | | * https://github.com/GerardGarcia/linux/blob/vsockmon/include/uapi/linux/vsockmon.h |
7 | | * |
8 | | * Wireshark - Network traffic analyzer |
9 | | * By Gerald Combs <gerald@wireshark.org> |
10 | | * Copyright 1998 Gerald Combs |
11 | | * |
12 | | * SPDX-License-Identifier: GPL-2.0-or-later |
13 | | */ |
14 | | |
15 | | /* |
16 | | * The AF_VSOCK socket allows zero-configuration communication between guests |
17 | | * and hypervisors using the standard socket API. |
18 | | */ |
19 | | |
20 | | #include <config.h> |
21 | | #include <epan/packet.h> |
22 | | #include <wsutil/pint.h> |
23 | | #include <epan/address_types.h> |
24 | | #include <wiretap/wtap.h> |
25 | | |
26 | | void proto_register_vsock(void); |
27 | | void proto_reg_handoff_vsock(void); |
28 | | |
29 | | static int proto_vsock; |
30 | | static int vsock_address_type = -1; |
31 | | static dissector_handle_t vsock_handle; |
32 | | |
33 | | /* Generic header related fields */ |
34 | | static int hf_vsock_src_cid; |
35 | | static int hf_vsock_src_port; |
36 | | static int hf_vsock_dst_cid; |
37 | | static int hf_vsock_dst_port; |
38 | | static int hf_vsock_op; |
39 | | static int hf_vsock_t; |
40 | | static int hf_vsock_t_len; |
41 | | static int hf_vsock_reserved; |
42 | | static int hf_vsock_payload; |
43 | | |
44 | | /* Virtio related fields */ |
45 | | static int hf_virtio_src_cid; |
46 | | static int hf_virtio_dst_cid; |
47 | | static int hf_virtio_src_port; |
48 | | static int hf_virtio_dst_port; |
49 | | static int hf_virtio_len; |
50 | | static int hf_virtio_type; |
51 | | static int hf_virtio_op; |
52 | | static int hf_virtio_flags; |
53 | | static int hf_virtio_buf_alloc; |
54 | | static int hf_virtio_fwd_cnt; |
55 | | |
56 | | static int ett_vsock; |
57 | | static int ett_virtio; |
58 | | |
59 | | static const value_string af_vsockmon_op_names[] = { |
60 | | { 0, "Unknown" }, |
61 | | { 1, "Connect" }, |
62 | | { 2, "Disconnect" }, |
63 | | { 3, "Control" }, |
64 | | { 4, "Payload" }, |
65 | | { 0, NULL } |
66 | | }; |
67 | | |
68 | | enum af_vsockmon_t { |
69 | | AF_VSOCK_T_UNKNOWN = 0, |
70 | | AF_VSOCK_T_NO_INFO = 1, |
71 | | AF_VSOCK_T_VIRTIO = 2 |
72 | | }; |
73 | | |
74 | | static const value_string af_vsockmon_t_names[] = { |
75 | | { 0, "Unknown" }, |
76 | | { 1, "No info" }, |
77 | | { 2, "Virtio" }, |
78 | | { 0 , NULL } |
79 | | }; |
80 | | |
81 | | static const value_string virtio_vsock_type_names[] = { |
82 | | { 1, "Stream"}, |
83 | | { 0, NULL } |
84 | | }; |
85 | | |
86 | | static const value_string virtio_vsock_op_names[] = { |
87 | | { 0, "Invalid" }, |
88 | | { 1, "Request" }, |
89 | | { 2, "Response" }, |
90 | | { 3, "Rst" }, |
91 | | { 4, "Shutdown" }, |
92 | | { 5, "RW" }, |
93 | | { 6, "Credit update" }, |
94 | | { 7, "Credit response" }, |
95 | | { 0 , NULL } |
96 | | }; |
97 | | |
98 | 1 | #define VSOCK_MIN_LENGTH 32 |
99 | | |
100 | | static int vsock_addr_to_str(const address* addr, char *buf, int buf_len) |
101 | 0 | { |
102 | 0 | const uint8_t *addrp = (const uint8_t *)addr->data; |
103 | |
|
104 | 0 | if(pletohu64(&addrp[0])==2){ |
105 | 0 | (void) g_strlcpy(buf, "host", buf_len); |
106 | 0 | } else { |
107 | 0 | snprintf(buf, buf_len, "%" PRIu64, pletohu64(&addrp[0])); |
108 | 0 | } |
109 | |
|
110 | 0 | return (int)(strlen(buf)+1); |
111 | 0 | } |
112 | | |
113 | | static int vsock_addr_str_len(const address* addr _U_) |
114 | 0 | { |
115 | | /* 2^64 unsigned int len */ |
116 | 0 | return 19; |
117 | 0 | } |
118 | | |
119 | | static int |
120 | | dissect_vsock(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, |
121 | | void *data _U_) |
122 | 1 | { |
123 | 1 | proto_item *ti, *virtio_ti; |
124 | 1 | proto_tree *vsock_tree, *virtio_tree; |
125 | | |
126 | 1 | uint32_t t_len, payload_len, virtio_buf_alloc, op, type, |
127 | 1 | virtio_fwd_cnt, virtio_op, virtio_type; |
128 | 1 | uint16_t payload_offset = 0, offset = 0; |
129 | 1 | char *op_name, *t_name; |
130 | | |
131 | 1 | if (tvb_reported_length(tvb) < VSOCK_MIN_LENGTH) |
132 | 1 | return 0; |
133 | | |
134 | | /* Clear column information before start parsing */ |
135 | 0 | col_clear(pinfo->cinfo, COL_INFO); |
136 | | |
137 | | /* Create top tree */ |
138 | 0 | ti = proto_tree_add_item(tree, proto_vsock, tvb, 0, -1, ENC_NA); |
139 | 0 | vsock_tree = proto_item_add_subtree(ti, ett_vsock); |
140 | | |
141 | | /* Parse generic header part */ |
142 | 0 | proto_tree_add_item(vsock_tree, hf_vsock_src_cid, tvb, offset, 8, ENC_LITTLE_ENDIAN); |
143 | 0 | set_address_tvb(&pinfo->src, vsock_address_type, 8, tvb, offset); |
144 | 0 | offset += 8; |
145 | |
|
146 | 0 | proto_tree_add_item(vsock_tree, hf_vsock_dst_cid, tvb, offset, 8, ENC_LITTLE_ENDIAN); |
147 | 0 | set_address_tvb(&pinfo->dst, vsock_address_type, 8, tvb, offset); |
148 | 0 | offset += 8; |
149 | |
|
150 | 0 | proto_tree_add_item_ret_uint(vsock_tree, hf_vsock_src_port, tvb, offset, 4, ENC_LITTLE_ENDIAN, &pinfo->srcport); |
151 | 0 | offset += 4; |
152 | |
|
153 | 0 | proto_tree_add_item_ret_uint(vsock_tree, hf_vsock_dst_port, tvb, offset, 4, ENC_LITTLE_ENDIAN, &pinfo->destport); |
154 | 0 | offset += 4; |
155 | |
|
156 | 0 | proto_tree_add_item_ret_uint(vsock_tree, hf_vsock_op, tvb, offset, 2, ENC_LITTLE_ENDIAN, &op); |
157 | 0 | offset += 2; |
158 | |
|
159 | 0 | proto_tree_add_item_ret_uint(vsock_tree, hf_vsock_t, tvb, offset, 2, ENC_LITTLE_ENDIAN, &type); |
160 | 0 | offset += 2; |
161 | |
|
162 | 0 | proto_tree_add_item_ret_uint(vsock_tree, hf_vsock_t_len, tvb, offset, 2, ENC_LITTLE_ENDIAN, &t_len); |
163 | 0 | offset += 2; |
164 | |
|
165 | 0 | proto_tree_add_item(vsock_tree, hf_vsock_reserved, tvb, offset, 2, ENC_NA); |
166 | 0 | offset += 2; |
167 | |
|
168 | 0 | payload_offset = offset + t_len; |
169 | |
|
170 | 0 | op_name = val_to_str(pinfo->pool, op, af_vsockmon_op_names, "Unknown (%d)"); |
171 | 0 | t_name = val_to_str(pinfo->pool, type, af_vsockmon_t_names, "Unknown (%d)"); |
172 | | /* Append summary information to top tree */ |
173 | 0 | proto_item_append_text(ti, ", Op: %s, Transport: %s", op_name, t_name); |
174 | | |
175 | | /* Fill columns */ |
176 | 0 | col_add_fstr(pinfo->cinfo, COL_INFO, "[%s] %s", op_name, t_name); |
177 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "vSocket"); |
178 | | |
179 | | /* Create subtree if there is transport information */ |
180 | 0 | switch (type) { |
181 | 0 | case AF_VSOCK_T_UNKNOWN: |
182 | 0 | case AF_VSOCK_T_NO_INFO: |
183 | 0 | break; |
184 | 0 | case AF_VSOCK_T_VIRTIO: |
185 | 0 | virtio_tree = proto_tree_add_subtree(vsock_tree, tvb, offset, 44, ett_virtio, &virtio_ti, "Virtio transport header"); |
186 | |
|
187 | 0 | proto_tree_add_item(virtio_tree, hf_virtio_src_cid, tvb, offset, 8, ENC_LITTLE_ENDIAN); |
188 | 0 | offset += 8; |
189 | 0 | proto_tree_add_item(virtio_tree, hf_virtio_dst_cid, tvb, offset, 8, ENC_LITTLE_ENDIAN); |
190 | 0 | offset += 8; |
191 | 0 | proto_tree_add_item(virtio_tree, hf_virtio_src_port, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
192 | 0 | offset += 4; |
193 | 0 | proto_tree_add_item(virtio_tree, hf_virtio_dst_port, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
194 | 0 | offset += 4; |
195 | 0 | proto_tree_add_item(virtio_tree, hf_virtio_len, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
196 | 0 | offset += 4; |
197 | |
|
198 | 0 | proto_tree_add_item_ret_uint(virtio_tree, hf_virtio_type, tvb, offset, 2, ENC_LITTLE_ENDIAN, &virtio_type); |
199 | 0 | offset += 2; |
200 | |
|
201 | 0 | proto_tree_add_item_ret_uint(virtio_tree, hf_virtio_op, tvb, offset, 2, ENC_LITTLE_ENDIAN, &virtio_op); |
202 | 0 | offset += 2; |
203 | |
|
204 | 0 | proto_tree_add_item(virtio_tree, hf_virtio_flags, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
205 | 0 | offset += 4; |
206 | |
|
207 | 0 | proto_tree_add_item_ret_uint(virtio_tree, hf_virtio_buf_alloc, tvb, offset, 4, ENC_LITTLE_ENDIAN, &virtio_buf_alloc); |
208 | 0 | offset += 4; |
209 | |
|
210 | 0 | proto_tree_add_item_ret_uint(virtio_tree, hf_virtio_fwd_cnt, tvb, offset, 4, ENC_LITTLE_ENDIAN, &virtio_fwd_cnt); |
211 | | /*offset += 4;*/ |
212 | | |
213 | | /* Append virtio information */ |
214 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ": %s, Op: %s, Buf alloc: %u, Fwd cnt: %u", |
215 | 0 | val_to_str(pinfo->pool, virtio_type, virtio_vsock_type_names, "Unknown (%d)"), |
216 | 0 | val_to_str(pinfo->pool, virtio_op, virtio_vsock_op_names, "Unknown (%d)"), |
217 | 0 | virtio_buf_alloc, virtio_fwd_cnt); |
218 | 0 | break; |
219 | 0 | } |
220 | | |
221 | | |
222 | | /* Append payload */ |
223 | 0 | payload_len = tvb_reported_length_remaining(tvb, payload_offset); |
224 | 0 | if (payload_len) |
225 | 0 | proto_tree_add_bytes_format(vsock_tree, hf_vsock_payload, tvb, payload_offset, payload_len, |
226 | 0 | NULL, "Payload (%uB)", payload_len); |
227 | |
|
228 | 0 | return tvb_reported_length(tvb); |
229 | 0 | } |
230 | | |
231 | | void |
232 | | proto_register_vsock(void) |
233 | 14 | { |
234 | 14 | static hf_register_info hf[] = { |
235 | 14 | { &hf_vsock_src_cid, |
236 | 14 | {"Source cid", "vsock.src_cid", FT_UINT64, BASE_DEC, NULL, |
237 | 14 | 0x0, NULL, HFILL }}, |
238 | 14 | { &hf_vsock_dst_cid, |
239 | 14 | {"Destination cid", "vsock.dst_cid", FT_UINT64, BASE_DEC, NULL, |
240 | 14 | 0x0, NULL, HFILL }}, |
241 | 14 | { &hf_vsock_src_port, |
242 | 14 | {"Source port", "vsock.src_port", FT_UINT32, BASE_DEC, NULL, |
243 | 14 | 0x0, NULL, HFILL }}, |
244 | 14 | { &hf_vsock_dst_port, |
245 | 14 | {"Destination port", "vsock.dst_port", FT_UINT32, BASE_DEC, NULL, |
246 | 14 | 0x0, NULL, HFILL }}, |
247 | 14 | { &hf_vsock_op, |
248 | 14 | {"Operation", "vsock.op", FT_UINT16, BASE_DEC, VALS(af_vsockmon_op_names), |
249 | 14 | 0x0, NULL, HFILL }}, |
250 | 14 | { &hf_vsock_t, |
251 | 14 | {"Transport", "vsock.trans", FT_UINT16, BASE_DEC, VALS(af_vsockmon_t_names), |
252 | 14 | 0x0, NULL, HFILL }}, |
253 | 14 | { &hf_vsock_t_len, |
254 | 14 | {"Transport length", "vsock.trans_len", FT_UINT16, BASE_DEC, NULL, |
255 | 14 | 0x0, NULL, HFILL }}, |
256 | 14 | { &hf_vsock_reserved, |
257 | 14 | {"Reserved", "vsock.reserved", FT_BYTES, BASE_NONE, NULL, |
258 | 14 | 0x0, NULL, HFILL }}, |
259 | 14 | { &hf_vsock_payload, |
260 | 14 | { "Payload", "vsock.payload", FT_BYTES, BASE_NONE, NULL, |
261 | 14 | 0x0, NULL, HFILL}}, |
262 | 14 | { &hf_virtio_src_cid, |
263 | 14 | {"Source cid", "vsock.virtio.src_cid", FT_UINT64, BASE_DEC, NULL, |
264 | 14 | 0x0, NULL, HFILL }}, |
265 | 14 | { &hf_virtio_dst_cid, |
266 | 14 | {"Destination cid", "vsock.virtio.dst_cid", FT_UINT64, BASE_DEC, NULL, |
267 | 14 | 0x0, NULL, HFILL }}, |
268 | 14 | { &hf_virtio_src_port, |
269 | 14 | {"Source port", "vsock.virtio.src_prot", FT_UINT32, BASE_DEC, NULL, |
270 | 14 | 0x0, NULL, HFILL }}, |
271 | 14 | { &hf_virtio_dst_port, |
272 | 14 | {"Destination port", "vsock.virtio.dst_prot", FT_UINT32, BASE_DEC, NULL, |
273 | 14 | 0x0, NULL, HFILL }}, |
274 | 14 | { &hf_virtio_len, |
275 | 14 | {"Length", "vsock.virtio.len", FT_UINT32, BASE_DEC, NULL, |
276 | 14 | 0x0, NULL, HFILL }}, |
277 | 14 | { &hf_virtio_type, |
278 | 14 | {"Type", "vsock.virtio.type", FT_UINT16, BASE_DEC, VALS(virtio_vsock_type_names), |
279 | 14 | 0x0, NULL, HFILL }}, |
280 | 14 | { &hf_virtio_op, |
281 | 14 | {"Operation", "vsock.virtio.op", FT_UINT16, BASE_DEC, VALS(virtio_vsock_op_names), |
282 | 14 | 0x0, NULL, HFILL }}, |
283 | 14 | { &hf_virtio_flags, |
284 | 14 | {"Flags", "vsock.virtio.flags", FT_UINT32, BASE_HEX, NULL, |
285 | 14 | 0x0, NULL, HFILL }}, |
286 | 14 | { &hf_virtio_buf_alloc, |
287 | 14 | {"Buf alloc", "vsock.virtio.buf_alloc", FT_UINT32, BASE_DEC, NULL, |
288 | 14 | 0x0, NULL, HFILL }}, |
289 | 14 | { &hf_virtio_fwd_cnt, |
290 | 14 | {"Fwd cnt", "vsock.virtio.fwd_cnt", FT_UINT32, BASE_DEC, NULL, |
291 | 14 | 0x0, NULL, HFILL }} |
292 | 14 | }; |
293 | 14 | static int *ett[] = { |
294 | 14 | &ett_vsock, |
295 | 14 | &ett_virtio |
296 | 14 | }; |
297 | | |
298 | 14 | vsock_address_type = address_type_dissector_register("AT_VSOCK", "vSocket Address", |
299 | 14 | vsock_addr_to_str, vsock_addr_str_len, NULL, NULL, NULL, NULL, NULL); |
300 | | |
301 | 14 | proto_vsock = proto_register_protocol("vSocket", "vsock", "vsock"); |
302 | 14 | proto_register_field_array(proto_vsock, hf, array_length(hf)); |
303 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
304 | | |
305 | 14 | vsock_handle = register_dissector("vsock", dissect_vsock, proto_vsock); |
306 | 14 | } |
307 | | |
308 | | void |
309 | | proto_reg_handoff_vsock(void) |
310 | 14 | { |
311 | 14 | dissector_add_uint("wtap_encap", WTAP_ENCAP_VSOCK, vsock_handle); |
312 | 14 | } |
313 | | |
314 | | /* |
315 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
316 | | * |
317 | | * Local variables: |
318 | | * c-basic-offset: 4 |
319 | | * tab-width: 8 |
320 | | * indent-tabs-mode: nil |
321 | | * End: |
322 | | * |
323 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
324 | | * :indentSize=4:tabSize=8:noTabs=true: |
325 | | */ |