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