]> The Tcpdump Group git mirrors - tcpdump/blob - print-vsock.c
Avoid -E and -M options inconsistencies with no libcrypto
[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 #include <config.h>
27
28 #include "netdissect-stdinc.h"
29 #include <stddef.h>
30
31 #define ND_LONGJMP_FROM_TCHECK
32 #include "netdissect.h"
33 #include "extract.h"
34
35 enum af_vsockmon_transport {
36 AF_VSOCK_TRANSPORT_UNKNOWN = 0,
37 AF_VSOCK_TRANSPORT_NO_INFO = 1, /* No transport information */
38 AF_VSOCK_TRANSPORT_VIRTIO = 2, /* Virtio transport header */
39 };
40
41 static const struct tok vsock_transport[] = {
42 {AF_VSOCK_TRANSPORT_UNKNOWN, "UNKNOWN"},
43 {AF_VSOCK_TRANSPORT_NO_INFO, "NO_INFO"},
44 {AF_VSOCK_TRANSPORT_VIRTIO, "VIRTIO"},
45 { 0, NULL }
46 };
47
48 enum af_vsockmon_op {
49 AF_VSOCK_OP_UNKNOWN = 0,
50 AF_VSOCK_OP_CONNECT = 1,
51 AF_VSOCK_OP_DISCONNECT = 2,
52 AF_VSOCK_OP_CONTROL = 3,
53 AF_VSOCK_OP_PAYLOAD = 4,
54 };
55
56 static const struct tok vsock_op[] = {
57 {AF_VSOCK_OP_UNKNOWN, "UNKNOWN"},
58 {AF_VSOCK_OP_CONNECT, "CONNECT"},
59 {AF_VSOCK_OP_DISCONNECT, "DISCONNECT"},
60 {AF_VSOCK_OP_CONTROL, "CONTROL"},
61 {AF_VSOCK_OP_PAYLOAD, "PAYLOAD"},
62 { 0, NULL }
63 };
64
65 enum virtio_vsock_type {
66 VIRTIO_VSOCK_TYPE_STREAM = 1,
67 };
68
69 static const struct tok virtio_type[] = {
70 {VIRTIO_VSOCK_TYPE_STREAM, "STREAM"},
71 { 0, NULL }
72 };
73
74 enum virtio_vsock_op {
75 VIRTIO_VSOCK_OP_INVALID = 0,
76 VIRTIO_VSOCK_OP_REQUEST = 1,
77 VIRTIO_VSOCK_OP_RESPONSE = 2,
78 VIRTIO_VSOCK_OP_RST = 3,
79 VIRTIO_VSOCK_OP_SHUTDOWN = 4,
80 VIRTIO_VSOCK_OP_RW = 5,
81 VIRTIO_VSOCK_OP_CREDIT_UPDATE = 6,
82 VIRTIO_VSOCK_OP_CREDIT_REQUEST = 7,
83 };
84
85 static const struct tok virtio_op[] = {
86 {VIRTIO_VSOCK_OP_INVALID, "INVALID"},
87 {VIRTIO_VSOCK_OP_REQUEST, "REQUEST"},
88 {VIRTIO_VSOCK_OP_RESPONSE, "RESPONSE"},
89 {VIRTIO_VSOCK_OP_RST, "RST"},
90 {VIRTIO_VSOCK_OP_SHUTDOWN, "SHUTDOWN"},
91 {VIRTIO_VSOCK_OP_RW, "RW"},
92 {VIRTIO_VSOCK_OP_CREDIT_UPDATE, "CREDIT UPDATE"},
93 {VIRTIO_VSOCK_OP_CREDIT_REQUEST, "CREDIT REQUEST"},
94 { 0, NULL }
95 };
96
97 /* All fields are little-endian */
98
99 struct virtio_vsock_hdr {
100 nd_uint64_t src_cid;
101 nd_uint64_t dst_cid;
102 nd_uint32_t src_port;
103 nd_uint32_t dst_port;
104 nd_uint32_t len;
105 nd_uint16_t type; /* enum virtio_vsock_type */
106 nd_uint16_t op; /* enum virtio_vsock_op */
107 nd_uint32_t flags;
108 nd_uint32_t buf_alloc;
109 nd_uint32_t fwd_cnt;
110 };
111
112 struct af_vsockmon_hdr {
113 nd_uint64_t src_cid;
114 nd_uint64_t dst_cid;
115 nd_uint32_t src_port;
116 nd_uint32_t dst_port;
117 nd_uint16_t op; /* enum af_vsockmon_op */
118 nd_uint16_t transport; /* enum af_vosckmon_transport */
119 nd_uint16_t len; /* size of transport header */
120 nd_uint8_t reserved[2];
121 };
122
123 static void
124 vsock_virtio_hdr_print(netdissect_options *ndo, const struct virtio_vsock_hdr *hdr)
125 {
126 uint16_t u16_v;
127 uint32_t u32_v;
128
129 u32_v = GET_LE_U_4(hdr->len);
130 ND_PRINT("len %u", u32_v);
131
132 u16_v = GET_LE_U_2(hdr->type);
133 ND_PRINT(", type %s",
134 tok2str(virtio_type, "Invalid type (%hu)", u16_v));
135
136 u16_v = GET_LE_U_2(hdr->op);
137 ND_PRINT(", op %s",
138 tok2str(virtio_op, "Invalid op (%hu)", u16_v));
139
140 u32_v = GET_LE_U_4(hdr->flags);
141 ND_PRINT(", flags %x", u32_v);
142
143 u32_v = GET_LE_U_4(hdr->buf_alloc);
144 ND_PRINT(", buf_alloc %u", u32_v);
145
146 u32_v = GET_LE_U_4(hdr->fwd_cnt);
147 ND_PRINT(", fwd_cnt %u", u32_v);
148 }
149
150 /*
151 * This size had better fit in a u_int.
152 */
153 static u_int
154 vsock_transport_hdr_size(uint16_t transport)
155 {
156 switch (transport) {
157 case AF_VSOCK_TRANSPORT_VIRTIO:
158 return (u_int)sizeof(struct virtio_vsock_hdr);
159 default:
160 return 0;
161 }
162 }
163
164 /* Returns 0 on success, -1 on truncation */
165 static int
166 vsock_transport_hdr_print(netdissect_options *ndo, uint16_t transport,
167 const u_char *p, const u_int caplen)
168 {
169 u_int transport_size = vsock_transport_hdr_size(transport);
170 const void *hdr;
171
172 if (caplen < sizeof(struct af_vsockmon_hdr) + transport_size) {
173 return -1;
174 }
175
176 hdr = p + sizeof(struct af_vsockmon_hdr);
177 switch (transport) {
178 case AF_VSOCK_TRANSPORT_VIRTIO:
179 ND_PRINT(" (");
180 vsock_virtio_hdr_print(ndo, hdr);
181 ND_PRINT(")");
182 break;
183 default:
184 break;
185 }
186 return 0;
187 }
188
189 static void
190 vsock_hdr_print(netdissect_options *ndo, const u_char *p, const u_int caplen)
191 {
192 const struct af_vsockmon_hdr *hdr = (const struct af_vsockmon_hdr *)p;
193 uint16_t hdr_transport, hdr_op;
194 uint32_t hdr_src_port, hdr_dst_port;
195 uint64_t hdr_src_cid, hdr_dst_cid;
196 u_int total_hdr_size;
197 int ret = 0;
198
199 hdr_transport = GET_LE_U_2(hdr->transport);
200 ND_PRINT("%s",
201 tok2str(vsock_transport, "Invalid transport (%u)",
202 hdr_transport));
203
204 /* If verbose level is more than 0 print transport details */
205 if (ndo->ndo_vflag) {
206 ret = vsock_transport_hdr_print(ndo, hdr_transport, p, caplen);
207 if (ret == 0)
208 ND_PRINT("\n\t");
209 } else
210 ND_PRINT(" ");
211
212 hdr_src_cid = GET_LE_U_8(hdr->src_cid);
213 hdr_dst_cid = GET_LE_U_8(hdr->dst_cid);
214 hdr_src_port = GET_LE_U_4(hdr->src_port);
215 hdr_dst_port = GET_LE_U_4(hdr->dst_port);
216 hdr_op = GET_LE_U_2(hdr->op);
217 ND_PRINT("%" PRIu64 ".%u > %" PRIu64 ".%u %s, length %u",
218 hdr_src_cid, hdr_src_port,
219 hdr_dst_cid, hdr_dst_port,
220 tok2str(vsock_op, " invalid op (%u)", hdr_op),
221 caplen);
222
223 if (ret < 0)
224 goto trunc;
225
226 /* If debug level is more than 1 print payload contents */
227 /* This size had better fit in a u_int */
228 total_hdr_size = (u_int)sizeof(struct af_vsockmon_hdr) +
229 vsock_transport_hdr_size(hdr_transport);
230 if (ndo->ndo_vflag > 1 && hdr_op == AF_VSOCK_OP_PAYLOAD) {
231 if (caplen > total_hdr_size) {
232 const u_char *payload = p + total_hdr_size;
233
234 ND_PRINT("\n");
235 print_unknown_data(ndo, payload, "\t",
236 caplen - total_hdr_size);
237 } else
238 goto trunc;
239 }
240 return;
241
242 trunc:
243 nd_print_trunc(ndo);
244 }
245
246 void
247 vsock_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h,
248 const u_char *cp)
249 {
250 ndo->ndo_protocol = "vsock";
251
252 ND_TCHECK_LEN(cp, sizeof(struct af_vsockmon_hdr));
253 ndo->ndo_ll_hdr_len += sizeof(struct af_vsockmon_hdr);
254 vsock_hdr_print(ndo, cp, h->caplen);
255 }