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