]> The Tcpdump Group git mirrors - tcpdump/commitdiff
ZeroMQ initial support (ZMTP/1.0 framing)
authorDenis Ovsienko <[email protected]>
Sat, 9 Feb 2013 13:36:24 +0000 (17:36 +0400)
committerDenis Ovsienko <[email protected]>
Mon, 11 Feb 2013 11:16:35 +0000 (15:16 +0400)
This change adds support for ZMTP/1.0 (ZeroMQ Message Transport Protocol
1.0) framing in TCP packets, as defined in http://rfc.zeromq.org/spec:13
and implemented in zeromq library.

Since there is no assigned port number for ZeroMQ, the user is left
responsible for making only the related TCP packets captured and
enforcing ZMTP/1.0 decoding through the "-T zmtp1" option.

Each ZMTP/1.0 frame of a packet will produce a single additional line of
output. The "-v" flag will add up to 8 lines (128 bytes) worth of
hex+ASCII dump of the frame body, and "-vv" and higher will dump the
full frame body, however long.

Beware that this code handles neither IP fragmentation nor TCP
segmentation and will incorrectly decode segments not starting at a
frame boundary.

The included sample capture stands for a short ZeroMQ session between a
REQ/REP socket pair doing 3 anonymous 2-way exchanges. It was produced
using version 2.1.9 of zeromq library patched to fix its bug #293, so
that all MBZ bits of the flags field are set to 0.

Makefile.in
interface.h
netdissect.h
print-tcp.c
print-zeromq.c [new file with mode: 0644]
tcpdump.1.in
tcpdump.c
tests/TESTLIST
tests/zmtp1.out [new file with mode: 0644]
tests/zmtp1.pcap [new file with mode: 0644]

index 3b589dc749aa9fa57c3fba686fd346b98a9d4894..16b45ecbb259bc7a48ea9910690e4ff2d22303b6 100644 (file)
@@ -93,7 +93,7 @@ CSRC =        addrtoname.c af.c checksum.c cpack.c gmpls.c oui.c gmt2local.c ipproto.c
        print-symantec.c print-syslog.c print-tcp.c print-telnet.c print-tftp.c \
        print-timed.c print-tipc.c print-token.c print-udld.c print-udp.c \
        print-usb.c print-vjc.c print-vqp.c print-vrrp.c print-vtp.c \
-       print-wb.c print-zephyr.c signature.c setsignal.c tcpdump.c util.c
+       print-wb.c print-zephyr.c print-zeromq.c signature.c setsignal.c tcpdump.c util.c
 
 LIBNETDISSECT_SRC=print-isakmp.c
 LIBNETDISSECT_OBJ=$(LIBNETDISSECT_SRC:.c=.o)
index ebc75e1573798e388c5c7edf8b7edc71fd91a25c..57d4636dd72884f50d31696c53036ea46392f1b0 100644 (file)
@@ -72,6 +72,7 @@ extern char *strsep(char **, const char *);
 #define PT_AODV                9       /* Ad-hoc On-demand Distance Vector Protocol */
 #define PT_CARP                10      /* Common Address Redundancy Protocol */
 #define PT_RADIUS      11      /* RADIUS authentication Protocol */
+#define PT_ZMTP1       12      /* ZeroMQ Message Transport Protocol 1.0 */
 
 #ifndef min
 #define min(a,b) ((a)>(b)?(b):(a))
@@ -311,6 +312,7 @@ extern void forces_print(const u_char *, u_int);
 extern void mpls_print(const u_char *, u_int);
 extern void mpls_lsp_ping_print(const u_char *, u_int);
 extern void zephyr_print(const u_char *, int);
+extern void zmtp1_print(const u_char *, u_int);
 extern void hsrp_print(const u_char *, u_int);
 extern void bfd_print(const u_char *, u_int, u_int);
 extern void sip_print(const u_char *, u_int);
index 1bf62f9c43dcd82fbb193165e8c0d981ad14ca08..f187fd5d9db912693e615d27d578a6b41b5d3a82 100644 (file)
@@ -181,6 +181,7 @@ struct netdissect_options {
 #define PT_AODV                9       /* Ad-hoc On-demand Distance Vector Protocol */
 #define PT_CARP                10      /* Common Address Redundancy Protocol */
 #define PT_RADIUS      11      /* RADIUS authentication Protocol */
+#define PT_ZMTP1       12      /* ZeroMQ Message Transport Protocol 1.0 */
 
 #ifndef min
 #define min(a,b) ((a)>(b)?(b):(a))
index 88b461576df9a2cfe8d12d74ca87f91faff141cd..3b0a13541afce82b1da3b26b144efd4678c8fc2f 100644 (file)
@@ -639,6 +639,15 @@ tcp_print(register const u_char *bp, register u_int length,
                 return;
         } 
 
+        if (packettype) {
+                switch (packettype) {
+                case PT_ZMTP1:
+                        zmtp1_print(bp, length);
+                        break;
+                }
+                return;
+        }
+
         if (sport == TELNET_PORT || dport == TELNET_PORT) {
                 if (!qflag && vflag)
                         telnet_print(bp, length);
diff --git a/print-zeromq.c b/print-zeromq.c
new file mode 100644 (file)
index 0000000..d5ac4bd
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * This file implements decoding of ZeroMQ network protocol(s).
+ *
+ *
+ * Copyright (c) 2013 The TCPDUMP project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <tcpdump-stdinc.h>
+
+#include <stdio.h>
+
+#include "interface.h"
+#include "extract.h"
+
+/* Maximum number of ZMTP/1.0 frame body bytes (without the flags) to dump in
+ * hex and ASCII under a single "-v" flag.
+ */
+#define VBYTES 128
+
+/*
+ * Below is an excerpt from the "13/ZMTP" specification:
+ *
+ * A ZMTP message consists of 1 or more frames.
+ *
+ * A ZMTP frame consists of a length, followed by a flags field and a frame
+ * body of (length - 1) octets. Note: the length includes the flags field, so
+ * an empty frame has a length of 1.
+ *
+ * For frames with a length of 1 to 254 octets, the length SHOULD BE encoded
+ * as a single octet. The minimum valid length of a frame is 1 octet, thus a
+ * length of 0 is invalid and such frames SHOULD be discarded silently.
+ *
+ * For frames with lengths of 255 and greater, the length SHALL BE encoded as
+ * a single octet with the value 255, followed by the length encoded as a
+ * 64-bit unsigned integer in network byte order. For frames with lengths of
+ * 1 to 254 octets this encoding MAY be also used.
+ *
+ * The flags field consists of a single octet containing various control
+ * flags. Bit 0 is the least significant bit.
+ *
+ * - Bit 0 (MORE): More frames to follow. A value of 0 indicates that there
+ *   are no more frames to follow. A value of 1 indicates that more frames
+ *   will follow. On messages consisting of a single frame the MORE flag MUST
+ *   be 0.
+ *
+ * - Bits 1-7: Reserved. Bits 1-7 are reserved for future use and SHOULD be
+ *   zero.
+ */
+
+static const u_char *
+zmtp1_print_frame(const u_char *cp, const u_char *ep) {
+       u_int64_t body_len_declared, body_len_captured, header_len;
+       u_int8_t flags;
+
+       printf("\n\t");
+       TCHECK2(*cp, 1); /* length/0xFF */
+
+       if (cp[0] != 0xFF) {
+               header_len = 1; /* length */
+               body_len_declared = cp[0];
+               if (body_len_declared == 0)
+                       return cp + header_len; /* skip to next frame */
+               printf(" frame flags+body  (8-bit) length %"PRIu8"", cp[0]);
+               TCHECK2(*cp, header_len + 1); /* length, flags */
+               flags = cp[1];
+       } else {
+               header_len = 1 + 8; /* 0xFF, length */
+               printf(" frame flags+body (64-bit) length");
+               TCHECK2(*cp, header_len); /* 0xFF, length */
+               body_len_declared = EXTRACT_64BITS(cp + 1);
+               if (body_len_declared == 0)
+                       return cp + header_len; /* skip to next frame */
+               printf(" %"PRIu64"", body_len_declared);
+               TCHECK2(*cp, header_len + 1); /* 0xFF, length, flags */
+               flags = cp[9];
+       }
+
+       body_len_captured = ep - cp - header_len;
+       if (body_len_declared > body_len_captured)
+               printf(" (%"PRIu64" captured)", body_len_captured);
+       printf(", flags 0x%02"PRIx8"", flags);
+
+       if (vflag) {
+               u_int64_t body_len_printed = MIN(body_len_captured, body_len_declared);
+
+               printf(" (%s|%s|%s|%s|%s|%s|%s|%s)",
+                       flags & 0x80 ? "MBZ" : "-",
+                       flags & 0x40 ? "MBZ" : "-",
+                       flags & 0x20 ? "MBZ" : "-",
+                       flags & 0x10 ? "MBZ" : "-",
+                       flags & 0x08 ? "MBZ" : "-",
+                       flags & 0x04 ? "MBZ" : "-",
+                       flags & 0x02 ? "MBZ" : "-",
+                       flags & 0x01 ? "MORE" : "-");
+
+               if (vflag == 1)
+                       body_len_printed = MIN(VBYTES + 1, body_len_printed);
+               if (body_len_printed > 1) {
+                       printf(", first %"PRIu64" byte(s) of body:", body_len_printed - 1);
+                       hex_and_ascii_print("\n\t ", cp + header_len + 1, body_len_printed - 1);
+                       printf("\n");
+               }
+       }
+
+       TCHECK2(*cp, header_len + body_len_declared); /* Next frame within the buffer ? */
+       return cp + header_len + body_len_declared;
+
+trunc:
+       printf(" [|zmtp1]");
+       return ep;
+}
+
+void
+zmtp1_print(const u_char *cp, u_int len) {
+       const u_char *ep = MIN(snapend, cp + len);
+
+       printf(": ZMTP/1.0");
+       while (cp < ep)
+               cp = zmtp1_print_frame(cp, ep);
+}
+
index b9e2b8e7b4ce004556ca630d119e650899906db7..d22232614f6eb9324d286f30de8b95a0bdf67f28 100644 (file)
@@ -526,8 +526,9 @@ Currently known types are
 \fBsnmp\fR (Simple Network Management Protocol),
 \fBtftp\fR (Trivial File Transfer Protocol),
 \fBvat\fR (Visual Audio Tool),
+\fBwb\fR (distributed White Board),
 and
-\fBwb\fR (distributed White Board).
+\fBzmtp1\fR (ZeroMQ Message Transport Protocol 1.0).
 .TP
 .B \-t
 \fIDon't\fP print a timestamp on each dump line.
index 49029b8988ab6486fdf4627fc41fe356673dd0a5..ad07df6f4a97c45fd1877a72123f8438b6959576 100644 (file)
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -1011,6 +1011,8 @@ main(int argc, char **argv)
                                packettype = PT_CARP;
                        else if (strcasecmp(optarg, "radius") == 0)
                                packettype = PT_RADIUS;
+                       else if (strcasecmp(optarg, "zmtp1") == 0)
+                               packettype = PT_ZMTP1;
                        else
                                error("unknown packet type `%s'", optarg);
                        break;
index 408034316cd2b10f1e6709a16f9e575ac8e51396..d0084923c945f69e776fa4fe9934b97394414338 100644 (file)
@@ -80,3 +80,6 @@ dhcpv6-aftr-name      dhcpv6-AFTR-Name-RFC6334.pcap   dhcpv6-AFTR-Name-RFC6334.out    -t -
 dhcpv6-ia-na   dhcpv6-ia-na.pcap       dhcpv6-ia-na.out        -t -v
 dhcpv6-ia-pd   dhcpv6-ia-pd.pcap       dhcpv6-ia-pd.out        -t -v
 dhcpv6-ia-ta   dhcpv6-ia-ta.pcap       dhcpv6-ia-ta.out        -t -v
+
+# ZeroMQ tests
+zmtp1v         zmtp1.pcap              zmtp1.out       -t -v -T zmtp1
diff --git a/tests/zmtp1.out b/tests/zmtp1.out
new file mode 100644 (file)
index 0000000..5b52877
--- /dev/null
@@ -0,0 +1,73 @@
+IP (tos 0x0, ttl 64, id 17993, offset 0, flags [DF], proto TCP (6), length 60)
+    127.0.0.1.55358 > 127.0.0.1.33000: Flags [S], cksum 0xfe30 (incorrect -> 0x1a9d), seq 2523978814, win 32792, options [mss 16396,sackOK,TS val 245537399 ecr 0,nop,wscale 7], length 0
+IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
+    127.0.0.1.33000 > 127.0.0.1.55358: Flags [S.], cksum 0xfe30 (incorrect -> 0x31b6), seq 3988083230, ack 2523978815, win 32768, options [mss 16396,sackOK,TS val 245537399 ecr 245537399,nop,wscale 7], length 0
+IP (tos 0x0, ttl 64, id 17994, offset 0, flags [DF], proto TCP (6), length 52)
+    127.0.0.1.55358 > 127.0.0.1.33000: Flags [.], cksum 0xfe28 (incorrect -> 0x19da), ack 1, win 257, options [nop,nop,TS val 245537399 ecr 245537399], length 0
+IP (tos 0x0, ttl 64, id 17995, offset 0, flags [DF], proto TCP (6), length 54)
+    127.0.0.1.55358 > 127.0.0.1.33000: Flags [P.], cksum 0xfe2a (incorrect -> 0x18d0), seq 1:3, ack 1, win 257, options [nop,nop,TS val 245537399 ecr 245537399], length 2: ZMTP/1.0
+        frame flags+body  (8-bit) length 1, flags 0x00 (-|-|-|-|-|-|-|-)
+IP (tos 0x0, ttl 64, id 51304, offset 0, flags [DF], proto TCP (6), length 52)
+    127.0.0.1.33000 > 127.0.0.1.55358: Flags [.], cksum 0xfe28 (incorrect -> 0x19d9), ack 3, win 256, options [nop,nop,TS val 245537399 ecr 245537399], length 0
+IP (tos 0x0, ttl 64, id 51305, offset 0, flags [DF], proto TCP (6), length 54)
+    127.0.0.1.33000 > 127.0.0.1.55358: Flags [P.], cksum 0xfe2a (incorrect -> 0x18cf), seq 1:3, ack 3, win 256, options [nop,nop,TS val 245537399 ecr 245537399], length 2: ZMTP/1.0
+        frame flags+body  (8-bit) length 1, flags 0x00 (-|-|-|-|-|-|-|-)
+IP (tos 0x0, ttl 64, id 17996, offset 0, flags [DF], proto TCP (6), length 52)
+    127.0.0.1.55358 > 127.0.0.1.33000: Flags [.], cksum 0xfe28 (incorrect -> 0x19d6), ack 3, win 257, options [nop,nop,TS val 245537399 ecr 245537399], length 0
+IP (tos 0x0, ttl 64, id 17997, offset 0, flags [DF], proto TCP (6), length 148)
+    127.0.0.1.55358 > 127.0.0.1.33000: Flags [P.], cksum 0xfe88 (incorrect -> 0x11da), seq 3:99, ack 3, win 257, options [nop,nop,TS val 245537399 ecr 245537399], length 96: ZMTP/1.0
+        frame flags+body  (8-bit) length 1, flags 0x01 (-|-|-|-|-|-|-|MORE)
+        frame flags+body  (8-bit) length 93, flags 0x00 (-|-|-|-|-|-|-|-), first 92 byte(s) of body:
+        0x0000:  5468 6973 2069 7320 6120 7368 6f72 7420  This.is.a.short.
+        0x0010:  4153 4349 4920 6d65 7373 6167 6520 666f  ASCII.message.fo
+        0x0020:  6c6c 6f77 6564 2062 7920 6120 7368 6f72  llowed.by.a.shor
+        0x0030:  7420 6269 6e61 7279 206d 6573 7361 6765  t.binary.message
+        0x0040:  2061 6e64 2061 206c 6f6e 6765 7220 4153  .and.a.longer.AS
+        0x0050:  4349 4920 6d65 7373 6167 652e            CII.message.
+
+IP (tos 0x0, ttl 64, id 51306, offset 0, flags [DF], proto TCP (6), length 84)
+    127.0.0.1.33000 > 127.0.0.1.55358: Flags [P.], cksum 0xfe48 (incorrect -> 0xc80f), seq 3:35, ack 99, win 256, options [nop,nop,TS val 245537399 ecr 245537399], length 32: ZMTP/1.0
+        frame flags+body  (8-bit) length 1, flags 0x01 (-|-|-|-|-|-|-|MORE)
+        frame flags+body  (8-bit) length 29, flags 0x00 (-|-|-|-|-|-|-|-), first 28 byte(s) of body:
+        0x0000:  5468 6973 2069 7320 6120 7368 6f72 7420  This.is.a.short.
+        0x0010:  4153 4349 4920 7265 706c 792e            ASCII.reply.
+
+IP (tos 0x0, ttl 64, id 17998, offset 0, flags [DF], proto TCP (6), length 72)
+    127.0.0.1.55358 > 127.0.0.1.33000: Flags [P.], cksum 0xfe3c (incorrect -> 0xcef8), seq 99:119, ack 35, win 257, options [nop,nop,TS val 245537399 ecr 245537399], length 20: ZMTP/1.0
+        frame flags+body  (8-bit) length 1, flags 0x01 (-|-|-|-|-|-|-|MORE)
+        frame flags+body  (8-bit) length 17, flags 0x00 (-|-|-|-|-|-|-|-), first 16 byte(s) of body:
+        0x0000:  0001 0203 0405 0607 0809 0a0b 0c0d 0e0f  ................
+
+IP (tos 0x0, ttl 64, id 51307, offset 0, flags [DF], proto TCP (6), length 84)
+    127.0.0.1.33000 > 127.0.0.1.55358: Flags [P.], cksum 0xfe48 (incorrect -> 0xc7da), seq 35:67, ack 119, win 256, options [nop,nop,TS val 245537400 ecr 245537399], length 32: ZMTP/1.0
+        frame flags+body  (8-bit) length 1, flags 0x01 (-|-|-|-|-|-|-|MORE)
+        frame flags+body  (8-bit) length 29, flags 0x00 (-|-|-|-|-|-|-|-), first 28 byte(s) of body:
+        0x0000:  5468 6973 2069 7320 6120 7368 6f72 7420  This.is.a.short.
+        0x0010:  4153 4349 4920 7265 706c 792e            ASCII.reply.
+
+IP (tos 0x0, ttl 64, id 17999, offset 0, flags [DF], proto TCP (6), length 603)
+    127.0.0.1.55358 > 127.0.0.1.33000: Flags [P.], cksum 0x0050 (incorrect -> 0xafc1), seq 119:670, ack 67, win 257, options [nop,nop,TS val 245537400 ecr 245537400], length 551: ZMTP/1.0
+        frame flags+body  (8-bit) length 1, flags 0x01 (-|-|-|-|-|-|-|MORE)
+        frame flags+body (64-bit) length 540, flags 0x00 (-|-|-|-|-|-|-|-), first 128 byte(s) of body:
+        0x0000:  5468 6520 7175 6963 6b20 6272 6f77 6e20  The.quick.brown.
+        0x0010:  666f 7820 6a75 6d70 7320 6f76 6572 2074  fox.jumps.over.t
+        0x0020:  6865 206c 617a 7920 646f 672e 2054 6865  he.lazy.dog..The
+        0x0030:  2071 7569 636b 2062 726f 776e 2066 6f78  .quick.brown.fox
+        0x0040:  206a 756d 7073 206f 7665 7220 7468 6520  .jumps.over.the.
+        0x0050:  6c61 7a79 2064 6f67 2e20 5468 6520 7175  lazy.dog..The.qu
+        0x0060:  6963 6b20 6272 6f77 6e20 666f 7820 6a75  ick.brown.fox.ju
+        0x0070:  6d70 7320 6f76 6572 2074 6865 206c 617a  mps.over.the.laz
+
+IP (tos 0x0, ttl 64, id 51308, offset 0, flags [DF], proto TCP (6), length 84)
+    127.0.0.1.33000 > 127.0.0.1.55358: Flags [P.], cksum 0xfe48 (incorrect -> 0xc592), seq 67:99, ack 670, win 256, options [nop,nop,TS val 245537400 ecr 245537400], length 32: ZMTP/1.0
+        frame flags+body  (8-bit) length 1, flags 0x01 (-|-|-|-|-|-|-|MORE)
+        frame flags+body  (8-bit) length 29, flags 0x00 (-|-|-|-|-|-|-|-), first 28 byte(s) of body:
+        0x0000:  5468 6973 2069 7320 6120 7368 6f72 7420  This.is.a.short.
+        0x0010:  4153 4349 4920 7265 706c 792e            ASCII.reply.
+
+IP (tos 0x0, ttl 64, id 18000, offset 0, flags [DF], proto TCP (6), length 52)
+    127.0.0.1.55358 > 127.0.0.1.33000: Flags [F.], cksum 0xfe28 (incorrect -> 0x16d8), seq 670, ack 99, win 257, options [nop,nop,TS val 245537400 ecr 245537400], length 0
+IP (tos 0x0, ttl 64, id 51309, offset 0, flags [DF], proto TCP (6), length 52)
+    127.0.0.1.33000 > 127.0.0.1.55358: Flags [F.], cksum 0xfe28 (incorrect -> 0x16d8), seq 99, ack 671, win 256, options [nop,nop,TS val 245537400 ecr 245537400], length 0
+IP (tos 0x0, ttl 64, id 18001, offset 0, flags [DF], proto TCP (6), length 52)
+    127.0.0.1.55358 > 127.0.0.1.33000: Flags [.], cksum 0xfe28 (incorrect -> 0x16d7), ack 100, win 257, options [nop,nop,TS val 245537400 ecr 245537400], length 0
diff --git a/tests/zmtp1.pcap b/tests/zmtp1.pcap
new file mode 100644 (file)
index 0000000..55aebea
Binary files /dev/null and b/tests/zmtp1.pcap differ