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