1251127Sdelphij/* 2251127Sdelphij * This file implements decoding of ZeroMQ network protocol(s). 3251127Sdelphij * 4251127Sdelphij * 5251127Sdelphij * Copyright (c) 2013 The TCPDUMP project 6251127Sdelphij * All rights reserved. 7251127Sdelphij * 8251127Sdelphij * Redistribution and use in source and binary forms, with or without 9251127Sdelphij * modification, are permitted provided that the following conditions 10251127Sdelphij * are met: 11251127Sdelphij * 1. Redistributions of source code must retain the above copyright 12251127Sdelphij * notice, this list of conditions and the following disclaimer. 13251127Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 14251127Sdelphij * notice, this list of conditions and the following disclaimer in the 15251127Sdelphij * documentation and/or other materials provided with the distribution. 16251127Sdelphij * 17251127Sdelphij * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18251127Sdelphij * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19251127Sdelphij * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20251127Sdelphij * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21251127Sdelphij * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22251127Sdelphij * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23251127Sdelphij * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24251127Sdelphij * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25251127Sdelphij * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26251127Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27251127Sdelphij * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28251127Sdelphij * POSSIBILITY OF SUCH DAMAGE. 29251127Sdelphij */ 30251127Sdelphij 31251127Sdelphij#ifdef HAVE_CONFIG_H 32251127Sdelphij#include "config.h" 33251127Sdelphij#endif 34251127Sdelphij 35251127Sdelphij#include <tcpdump-stdinc.h> 36251127Sdelphij 37251127Sdelphij#include <stdio.h> 38251127Sdelphij 39251127Sdelphij#include "interface.h" 40251127Sdelphij#include "extract.h" 41251127Sdelphij 42251127Sdelphij/* Maximum number of ZMTP/1.0 frame body bytes (without the flags) to dump in 43251127Sdelphij * hex and ASCII under a single "-v" flag. 44251127Sdelphij */ 45251127Sdelphij#define VBYTES 128 46251127Sdelphij 47251127Sdelphij/* 48251127Sdelphij * Below is an excerpt from the "13/ZMTP" specification: 49251127Sdelphij * 50251127Sdelphij * A ZMTP message consists of 1 or more frames. 51251127Sdelphij * 52251127Sdelphij * A ZMTP frame consists of a length, followed by a flags field and a frame 53251127Sdelphij * body of (length - 1) octets. Note: the length includes the flags field, so 54251127Sdelphij * an empty frame has a length of 1. 55251127Sdelphij * 56251127Sdelphij * For frames with a length of 1 to 254 octets, the length SHOULD BE encoded 57251127Sdelphij * as a single octet. The minimum valid length of a frame is 1 octet, thus a 58251127Sdelphij * length of 0 is invalid and such frames SHOULD be discarded silently. 59251127Sdelphij * 60251127Sdelphij * For frames with lengths of 255 and greater, the length SHALL BE encoded as 61251127Sdelphij * a single octet with the value 255, followed by the length encoded as a 62251127Sdelphij * 64-bit unsigned integer in network byte order. For frames with lengths of 63251127Sdelphij * 1 to 254 octets this encoding MAY be also used. 64251127Sdelphij * 65251127Sdelphij * The flags field consists of a single octet containing various control 66251127Sdelphij * flags. Bit 0 is the least significant bit. 67251127Sdelphij * 68251127Sdelphij * - Bit 0 (MORE): More frames to follow. A value of 0 indicates that there 69251127Sdelphij * are no more frames to follow. A value of 1 indicates that more frames 70251127Sdelphij * will follow. On messages consisting of a single frame the MORE flag MUST 71251127Sdelphij * be 0. 72251127Sdelphij * 73251127Sdelphij * - Bits 1-7: Reserved. Bits 1-7 are reserved for future use and SHOULD be 74251127Sdelphij * zero. 75251127Sdelphij */ 76251127Sdelphij 77251127Sdelphijstatic const u_char * 78251127Sdelphijzmtp1_print_frame(const u_char *cp, const u_char *ep) { 79251127Sdelphij u_int64_t body_len_declared, body_len_captured, header_len; 80251127Sdelphij u_int8_t flags; 81251127Sdelphij 82251127Sdelphij printf("\n\t"); 83251127Sdelphij TCHECK2(*cp, 1); /* length/0xFF */ 84251127Sdelphij 85251127Sdelphij if (cp[0] != 0xFF) { 86251127Sdelphij header_len = 1; /* length */ 87251127Sdelphij body_len_declared = cp[0]; 88251127Sdelphij if (body_len_declared == 0) 89251127Sdelphij return cp + header_len; /* skip to next frame */ 90251127Sdelphij printf(" frame flags+body (8-bit) length %"PRIu8"", cp[0]); 91251127Sdelphij TCHECK2(*cp, header_len + 1); /* length, flags */ 92251127Sdelphij flags = cp[1]; 93251127Sdelphij } else { 94251127Sdelphij header_len = 1 + 8; /* 0xFF, length */ 95251127Sdelphij printf(" frame flags+body (64-bit) length"); 96251127Sdelphij TCHECK2(*cp, header_len); /* 0xFF, length */ 97251127Sdelphij body_len_declared = EXTRACT_64BITS(cp + 1); 98251127Sdelphij if (body_len_declared == 0) 99251127Sdelphij return cp + header_len; /* skip to next frame */ 100251127Sdelphij printf(" %"PRIu64"", body_len_declared); 101251127Sdelphij TCHECK2(*cp, header_len + 1); /* 0xFF, length, flags */ 102251127Sdelphij flags = cp[9]; 103251127Sdelphij } 104251127Sdelphij 105251127Sdelphij body_len_captured = ep - cp - header_len; 106251127Sdelphij if (body_len_declared > body_len_captured) 107251127Sdelphij printf(" (%"PRIu64" captured)", body_len_captured); 108251127Sdelphij printf(", flags 0x%02"PRIx8"", flags); 109251127Sdelphij 110251127Sdelphij if (vflag) { 111251127Sdelphij u_int64_t body_len_printed = MIN(body_len_captured, body_len_declared); 112251127Sdelphij 113251127Sdelphij printf(" (%s|%s|%s|%s|%s|%s|%s|%s)", 114251127Sdelphij flags & 0x80 ? "MBZ" : "-", 115251127Sdelphij flags & 0x40 ? "MBZ" : "-", 116251127Sdelphij flags & 0x20 ? "MBZ" : "-", 117251127Sdelphij flags & 0x10 ? "MBZ" : "-", 118251127Sdelphij flags & 0x08 ? "MBZ" : "-", 119251127Sdelphij flags & 0x04 ? "MBZ" : "-", 120251127Sdelphij flags & 0x02 ? "MBZ" : "-", 121251127Sdelphij flags & 0x01 ? "MORE" : "-"); 122251127Sdelphij 123251127Sdelphij if (vflag == 1) 124251127Sdelphij body_len_printed = MIN(VBYTES + 1, body_len_printed); 125251127Sdelphij if (body_len_printed > 1) { 126251127Sdelphij printf(", first %"PRIu64" byte(s) of body:", body_len_printed - 1); 127251127Sdelphij hex_and_ascii_print("\n\t ", cp + header_len + 1, body_len_printed - 1); 128251127Sdelphij printf("\n"); 129251127Sdelphij } 130251127Sdelphij } 131251127Sdelphij 132251127Sdelphij TCHECK2(*cp, header_len + body_len_declared); /* Next frame within the buffer ? */ 133251127Sdelphij return cp + header_len + body_len_declared; 134251127Sdelphij 135251127Sdelphijtrunc: 136251127Sdelphij printf(" [|zmtp1]"); 137251127Sdelphij return ep; 138251127Sdelphij} 139251127Sdelphij 140251127Sdelphijvoid 141251127Sdelphijzmtp1_print(const u_char *cp, u_int len) { 142251127Sdelphij const u_char *ep = MIN(snapend, cp + len); 143251127Sdelphij 144251127Sdelphij printf(": ZMTP/1.0"); 145251127Sdelphij while (cp < ep) 146251127Sdelphij cp = zmtp1_print_frame(cp, ep); 147251127Sdelphij} 148251127Sdelphij 149