]> The Tcpdump Group git mirrors - tcpdump/blob - print-vsock.c
gre: add support for MikroTik Ethernet-over-IP hack.
[tcpdump] / print-vsock.c
1 /*
2 * Copyright (c) 2016 Gerard Garcia <nouboh@gmail.com>
3 * Copyright (c) 2017 Red Hat, Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 * 3. The names of the authors may not be used to endorse or promote
16 * products derived from this software without specific prior
17 * written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 */
23
24 /* \summary: Linux vsock printer */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include "netdissect-stdinc.h"
31 #include <stddef.h>
32
33 #define ND_LONGJMP_FROM_TCHECK
34 #include "netdissect.h"
35 #include "extract.h"
36
37 enum af_vsockmon_transport {
38 AF_VSOCK_TRANSPORT_UNKNOWN = 0,
39 AF_VSOCK_TRANSPORT_NO_INFO = 1, /* No transport information */
40 AF_VSOCK_TRANSPORT_VIRTIO = 2, /* Virtio transport header */
41 };
42
43 static const struct tok vsock_transport[] = {
44 {AF_VSOCK_TRANSPORT_UNKNOWN, "UNKNOWN"},
45 {AF_VSOCK_TRANSPORT_NO_INFO, "NO_INFO"},
46 {AF_VSOCK_TRANSPORT_VIRTIO, "VIRTIO"},
47 { 0, NULL }
48 };
49
50 enum af_vsockmon_op {
51 AF_VSOCK_OP_UNKNOWN = 0,
52 AF_VSOCK_OP_CONNECT = 1,
53 AF_VSOCK_OP_DISCONNECT = 2,
54 AF_VSOCK_OP_CONTROL = 3,
55 AF_VSOCK_OP_PAYLOAD = 4,
56 };
57
58 static const struct tok vsock_op[] = {
59 {AF_VSOCK_OP_UNKNOWN, "UNKNOWN"},
60 {AF_VSOCK_OP_CONNECT, "CONNECT"},
61 {AF_VSOCK_OP_DISCONNECT, "DISCONNECT"},
62 {AF_VSOCK_OP_CONTROL, "CONTROL"},
63 {AF_VSOCK_OP_PAYLOAD, "PAYLOAD"},
64 { 0, NULL }
65 };
66
67 enum virtio_vsock_type {
68 VIRTIO_VSOCK_TYPE_STREAM = 1,
69 };
70
71 static const struct tok virtio_type[] = {
72 {VIRTIO_VSOCK_TYPE_STREAM, "STREAM"},
73 { 0, NULL }
74 };
75
76 enum virtio_vsock_op {
77 VIRTIO_VSOCK_OP_INVALID = 0,
78 VIRTIO_VSOCK_OP_REQUEST = 1,
79 VIRTIO_VSOCK_OP_RESPONSE = 2,
80 VIRTIO_VSOCK_OP_RST = 3,
81 VIRTIO_VSOCK_OP_SHUTDOWN = 4,
82 VIRTIO_VSOCK_OP_RW = 5,
83 VIRTIO_VSOCK_OP_CREDIT_UPDATE = 6,
84 VIRTIO_VSOCK_OP_CREDIT_REQUEST = 7,
85 };
86
87 static const struct tok virtio_op[] = {
88 {VIRTIO_VSOCK_OP_INVALID, "INVALID"},
89 {VIRTIO_VSOCK_OP_REQUEST, "REQUEST"},
90 {VIRTIO_VSOCK_OP_RESPONSE, "RESPONSE"},
91 {VIRTIO_VSOCK_OP_RST, "RST"},
92 {VIRTIO_VSOCK_OP_SHUTDOWN, "SHUTDOWN"},
93 {VIRTIO_VSOCK_OP_RW, "RW"},
94 {VIRTIO_VSOCK_OP_CREDIT_UPDATE, "CREDIT UPDATE"},
95 {VIRTIO_VSOCK_OP_CREDIT_REQUEST, "CREDIT REQUEST"},
96 { 0, NULL }
97 };
98
99 /* All fields are little-endian */
100
101 struct virtio_vsock_hdr {
102 nd_uint64_t src_cid;
103 nd_uint64_t dst_cid;
104 nd_uint32_t src_port;
105 nd_uint32_t dst_port;
106 nd_uint32_t len;
107 nd_uint16_t type; /* enum virtio_vsock_type */
108 nd_uint16_t op; /* enum virtio_vsock_op */
109 nd_uint32_t flags;
110 nd_uint32_t buf_alloc;
111 nd_uint32_t fwd_cnt;
112 };
113
114 struct af_vsockmon_hdr {
115 nd_uint64_t src_cid;
116 nd_uint64_t dst_cid;
117 nd_uint32_t src_port;
118 nd_uint32_t dst_port;
119 nd_uint16_t op; /* enum af_vsockmon_op */
120 nd_uint16_t transport; /* enum af_vosckmon_transport */
121 nd_uint16_t len; /* size of transport header */
122 nd_uint8_t reserved[2];
123 };
124
125 static void
126 vsock_virtio_hdr_print(netdissect_options *ndo, const struct virtio_vsock_hdr *hdr)
127 {
128 uint16_t u16_v;
129 uint32_t u32_v;
130
131 u32_v = GET_LE_U_4(hdr->len);
132 ND_PRINT("len %u", u32_v);
133
134 u16_v = GET_LE_U_2(hdr->type);
135 ND_PRINT(", type %s",
136 tok2str(virtio_type, "Invalid type (%hu)", u16_v));
137
138 u16_v = GET_LE_U_2(hdr->op);
139 ND_PRINT(", op %s",
140 tok2str(virtio_op, "Invalid op (%hu)", u16_v));
141
142 u32_v = GET_LE_U_4(hdr->flags);
143 ND_PRINT(", flags %x", u32_v);
144
145 u32_v = GET_LE_U_4(hdr->buf_alloc);
146 ND_PRINT(", buf_alloc %u", u32_v);
147
148 u32_v = GET_LE_U_4(hdr->fwd_cnt);
149 ND_PRINT(", fwd_cnt %u", u32_v);
150 }
151
152 /*
153 * This size had better fit in a u_int.
154 */
155 static u_int
156 vsock_transport_hdr_size(uint16_t transport)
157 {
158 switch (transport) {
159 case AF_VSOCK_TRANSPORT_VIRTIO:
160 return (u_int)sizeof(struct virtio_vsock_hdr);
161 default:
162 return 0;
163 }
164 }
165
166 /* Returns 0 on success, -1 on truncation */
167 static int
168 vsock_transport_hdr_print(netdissect_options *ndo, uint16_t transport,
169 const u_char *p, const u_int caplen)
170 {
171 u_int transport_size = vsock_transport_hdr_size(transport);
172 const void *hdr;
173
174 if (caplen < sizeof(struct af_vsockmon_hdr) + transport_size) {
175 return -1;
176 }
177
178 hdr = p + sizeof(struct af_vsockmon_hdr);
179 switch (transport) {
180 case AF_VSOCK_TRANSPORT_VIRTIO:
181 ND_PRINT(" (");
182 vsock_virtio_hdr_print(ndo, hdr);
183 ND_PRINT(")");
184 break;
185 default:
186 break;
187 }
188 return 0;
189 }
190
191 static void
192 vsock_hdr_print(netdissect_options *ndo, const u_char *p, const u_int caplen)
193 {
194 const struct af_vsockmon_hdr *hdr = (const struct af_vsockmon_hdr *)p;
195 uint16_t hdr_transport, hdr_op;
196 uint32_t hdr_src_port, hdr_dst_port;
197 uint64_t hdr_src_cid, hdr_dst_cid;
198 u_int total_hdr_size;
199 int ret = 0;
200
201 hdr_transport = GET_LE_U_2(hdr->transport);
202 ND_PRINT("%s",
203 tok2str(vsock_transport, "Invalid transport (%u)",
204 hdr_transport));
205
206 /* If verbose level is more than 0 print transport details */
207 if (ndo->ndo_vflag) {
208 ret = vsock_transport_hdr_print(ndo, hdr_transport, p, caplen);
209 if (ret == 0)
210 ND_PRINT("\n\t");
211 } else
212 ND_PRINT(" ");
213
214 hdr_src_cid = GET_LE_U_8(hdr->src_cid);
215 hdr_dst_cid = GET_LE_U_8(hdr->dst_cid);
216 hdr_src_port = GET_LE_U_4(hdr->src_port);
217 hdr_dst_port = GET_LE_U_4(hdr->dst_port);
218 hdr_op = GET_LE_U_2(hdr->op);
219 ND_PRINT("%" PRIu64 ".%u > %" PRIu64 ".%u %s, length %u",
220 hdr_src_cid, hdr_src_port,
221 hdr_dst_cid, hdr_dst_port,
222 tok2str(vsock_op, " invalid op (%u)", hdr_op),
223 caplen);
224
225 if (ret < 0)
226 goto trunc;
227
228 /* If debug level is more than 1 print payload contents */
229 /* This size had better fit in a u_int */
230 total_hdr_size = (u_int)sizeof(struct af_vsockmon_hdr) +
231 vsock_transport_hdr_size(hdr_transport);
232 if (ndo->ndo_vflag > 1 && hdr_op == AF_VSOCK_OP_PAYLOAD) {
233 if (caplen > total_hdr_size) {
234 const u_char *payload = p + total_hdr_size;
235
236 ND_PRINT("\n");
237 print_unknown_data(ndo, payload, "\t",
238 caplen - total_hdr_size);
239 } else
240 goto trunc;
241 }
242 return;
243
244 trunc:
245 nd_print_trunc(ndo);
246 }
247
248 void
249 vsock_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h,
250 const u_char *cp)
251 {
252 ndo->ndo_protocol = "vsock";
253
254 ND_TCHECK_LEN(cp, sizeof(struct af_vsockmon_hdr));
255 ndo->ndo_ll_hdr_len += sizeof(struct af_vsockmon_hdr);
256 vsock_hdr_print(ndo, cp, h->caplen);
257 }