On Tue, Apr 14, 2020 at 01:49:32PM +1000, David Gwynne wrote:
>
>
> > On 13 Apr 2020, at 19:03, Remi Locherer <[email protected]> wrote:
> >
> > Hi,
> >
> > I recently looked into NHRP (RFC 2332) and noticed that our tcpdump does
> > not have a printer for it. So I added support for NHRP to tcpdump.
> >
> > Initially I was surprised: I expected a simpler protocol! But it is from
> > the 90's with all the protocols from then in mind (frame relay, ATM, ...).
> >
> > I tested with public available pcap files and compared the output with
> > wirshark.
> > https://packetlife.net/captures/protocol/nhrp/
> > https://www.networkingwithfish.com/fun-in-the-lab-sniffer-tracing-a-dmvpn-tunnel-startup/
> >
> > The output looks like this:
> >
> > 08:34:45.647483 172.16.25.2 > 172.16.15.2: gre NHRP: reg request, id 7 [tos
> > 0xc0]
> > 08:34:45.671422 172.16.15.2 > 172.16.25.2: gre NHRP: reg reply, id 7 [tos
> > 0xc0]
> >
> > 08:47:16.138679 172.16.15.2 > 172.16.25.2: gre NHRP: res request, id 6 [tos
> > 0xc0]
> > 08:47:16.148863 172.16.25.2 > 172.16.15.2: gre NHRP: res reply, id 6 [tos
> > 0xc0]
> >
> > With -v set:
> >
> > 08:34:45.647483 172.16.25.2 > 172.16.15.2: gre [] 2001 NHRP: reg request,
> > id 7, hopcnt 255, src nbma 172.16.25.2, 192.168.0.2 -> 192.168.0.1 (code 0,
> > pl 255, mtu 1514, htime 7200, pref 0) [tos 0xc0] (ttl 254, id 22, len 116)
> > 08:34:45.671422 172.16.15.2 > 172.16.25.2: gre [] 2001 NHRP: reg reply, id
> > 7, hopcnt 255, src nbma 172.16.25.2, 192.168.0.2 -> 192.168.0.1 (code 0, pl
> > 255, mtu 1514, htime 7200, pref 0) [tos 0xc0] (ttl 255, id 7, len 136)
> >
> > 08:47:16.138679 172.16.15.2 > 172.16.25.2: gre [] 2001 NHRP: res request,
> > id 6, hopcnt 254, src nbma 172.16.45.2, 192.168.0.4 -> 192.168.0.2 (code 0,
> > pl 0, mtu 1514, htime 7200, pref 0) [tos 0xc0] (ttl 254, id 20, len 116)
> > 08:47:16.148863 172.16.25.2 > 172.16.15.2: gre [] 2001 NHRP: res reply, id
> > 6, hopcnt 255, src nbma 172.16.45.2, 192.168.0.4 -> 192.168.0.2 (code 0, pl
> > 32, mtu 1514, htime 7199, pref 0, nbma 172.16.25.2, proto 192.168.0.2) [tos
> > 0xc0] (ttl 255, id 31, len 144)
> >
> > Extensions are not parsed and printed.
> >
> > It would be nice to get pcaps with expamles that use address or protocol
> > combinations other than GRE and IPv4.
> >
> > Comments, OKs?
>
> Can you print the addresses when -v is not set too?
>
> Otherwise I'm keen.
>
Like this?
tcpdump -n:
08:47:16.068855 172.16.25.2 > 172.16.15.2: gre NHRP: res request, id 8, src
nbma 172.16.25.2, 192.168.0.2 -> 192.168.0.4 (code 0) [tos 0xc0]
08:47:16.150679 172.16.15.2 > 172.16.25.2: gre NHRP: res reply, id 8, src nbma
172.16.25.2, 192.168.0.2 -> 192.168.0.4 (code 0, nbma 172.16.45.2, proto
192.168.0.4) [tos 0xc0]
tcpdump -nv:
08:47:16.068855 172.16.25.2 > 172.16.15.2: gre [] 2001 NHRP: res request, id 8,
hopcnt 255, src nbma 172.16.25.2, 192.168.0.2 -> 192.168.0.4 (code 0, pl 0, mtu
1514, htime 7200, pref 0) [tos 0xc0] (ttl 255, id 29, len 96)
08:47:16.150679 172.16.15.2 > 172.16.25.2: gre [] 2001 NHRP: res reply, id 8,
hopcnt 254, src nbma 172.16.25.2, 192.168.0.2 -> 192.168.0.4 (code 0, pl 32,
mtu 1514, htime 7199, pref 0, nbma 172.16.45.2, proto 192.168.0.4) [tos 0xc0]
(ttl 254, id 21, len 164)
Index: Makefile
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/Makefile,v
retrieving revision 1.64
diff -u -p -r1.64 Makefile
--- Makefile 3 Dec 2019 01:43:33 -0000 1.64
+++ Makefile 28 Mar 2020 17:07:22 -0000
@@ -48,7 +48,7 @@ SRCS= tcpdump.c addrtoname.c privsep.c p
print-bgp.c print-ospf6.c print-ripng.c print-rt6.c print-stp.c \
print-etherip.c print-lwres.c print-lldp.c print-cdp.c print-pflog.c \
print-pfsync.c pf_print_state.c print-ofp.c ofp_map.c \
- print-udpencap.c print-carp.c \
+ print-udpencap.c print-carp.c print-nhrp.c \
print-802_11.c print-iapp.c print-mpls.c print-slow.c print-usbpcap.c \
gmt2local.c savestr.c setsignal.c in_cksum.c
Index: interface.h
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/interface.h,v
retrieving revision 1.83
diff -u -p -r1.83 interface.h
--- interface.h 3 Dec 2019 01:43:33 -0000 1.83
+++ interface.h 28 Mar 2020 17:07:22 -0000
@@ -217,6 +217,7 @@ extern void ppp_ether_if_print(u_char *,
extern void gre_print(const u_char *, u_int);
extern void vxlan_print(const u_char *, u_int);
extern void nsh_print(const u_char *, u_int);
+extern void nhrp_print(const u_char *, u_int);
extern void icmp_print(const u_char *, u_int, const u_char *);
extern void ieee802_11_if_print(u_char *, const struct pcap_pkthdr *,
const u_char *);
Index: print-ether.c
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/print-ether.c,v
retrieving revision 1.37
diff -u -p -r1.37 print-ether.c
--- print-ether.c 24 Jan 2020 22:46:36 -0000 1.37
+++ print-ether.c 28 Mar 2020 17:07:22 -0000
@@ -303,6 +303,13 @@ recurse:
ether_pbb_print(p, length, caplen);
return (1);
+#ifndef ETHERTYPE_NHRP
+#define ETHERTYPE_NHRP 0x2001
+#endif
+ case ETHERTYPE_NHRP:
+ nhrp_print(p, length);
+ return (1);
+
#ifdef PPP
case ETHERTYPE_PPPOEDISC:
case ETHERTYPE_PPPOE:
Index: print-gre.c
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/print-gre.c,v
retrieving revision 1.30
diff -u -p -r1.30 print-gre.c
--- print-gre.c 24 Jan 2020 22:46:36 -0000 1.30
+++ print-gre.c 28 Mar 2020 17:07:22 -0000
@@ -289,6 +289,12 @@ gre_print_0(const u_char *p, u_int lengt
case 0x2000:
cdp_print(p, length, l, 0);
break;
+#ifndef ETHERTYPE_NHRP
+#define ETHERTYPE_NHRP 0x2001
+#endif
+ case ETHERTYPE_NHRP:
+ nhrp_print(p, length);
+ break;
default:
printf("unknown-proto-%04x", proto);
}
Index: print-nhrp.c
===================================================================
RCS file: print-nhrp.c
diff -N print-nhrp.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ print-nhrp.c 14 Apr 2020 10:02:02 -0000
@@ -0,0 +1,287 @@
+/* $OpenBSD:$ */
+
+/*
+ * Copyright (c) 2020 Remi Locherer <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * RFC 2332 NBMA Next Hop Resolution Protocol (NHRP)
+ */
+
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+
+#include <net/ethertypes.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "addrtoname.h"
+#include "afnum.h"
+#include "interface.h"
+#include "extract.h"
+
+#define NHRP_VER_RFC2332 1
+
+#define NHRP_PKG_RESOLUTION_REQUEST 1
+#define NHRP_PKG_RESOLUTION_REPLY 2
+#define NHRP_PKG_REGISTRATION_REQUEST 3
+#define NHRP_PKG_REGISTRATION_REPLY 4
+#define NHRP_PKG_PURGE_REQUEST 5
+#define NHRP_PKG_PURGE_REPLY 6
+#define NHRP_PKG_ERROR_INDICATION 7
+
+
+struct nhrp_header {
+ /* fixed header part */
+ u_int16_t afn; /* link layer address */
+ u_int16_t pro_type; /* protocol type (short form) */
+ u_int8_t pro_snap[5]; /* protocol type (long form) */
+ u_int8_t hopcnt; /* hop count */
+ u_int16_t pktsz; /* length of the NHRP packet (octets) */
+ u_int16_t chksum; /* IP checksum over the entier packet */
+ u_int16_t extoff; /* extension offset */
+ u_int8_t op_version; /* version of address mapping and
+ management protocol */
+ u_int8_t op_type; /* NHRP packet type */
+ u_int8_t shtl; /* type and length of src NBMA addr */
+ u_int8_t sstl; /* type and length of src NBMA
+ subaddress */
+ /* mandatory header part */
+ u_int8_t spl; /* src proto len */
+ u_int8_t dpl; /* dst proto len */
+ u_int16_t flags; /* flags */
+ union {
+ u_int32_t id; /* request id */
+ struct { /* error code */
+ u_int16_t code;
+ u_int16_t offset;
+ } err;
+ } u;
+};
+
+struct nhrp_cie {
+ /* client information entrie */
+ u_int8_t code;
+ u_int8_t plen;
+ u_int16_t unused;
+ u_int16_t mtu;
+ u_int16_t htime;
+ u_int8_t cli_addr_tl;
+ u_int8_t cli_saddr_tl;
+ u_int8_t cli_proto_tl;
+ u_int8_t pref;
+};
+
+static const u_char * nhrp_print_cie(const u_char *, u_int16_t, u_int16_t);
+
+
+void
+nhrp_print(const u_char *p, u_int length)
+{
+ struct nhrp_header *hdr;
+ const u_char *nhrpext, *nhrpend;
+
+ printf("NHRP: ");
+
+ if ((snapend - p) < sizeof(*hdr))
+ goto trunc;
+
+ hdr = (struct nhrp_header *)p;
+
+ if (hdr->op_version != NHRP_VER_RFC2332) {
+ printf("unknown-version-%02x", hdr->op_version);
+ return;
+
+ }
+
+ nhrpext = p + EXTRACT_16BITS(&hdr->extoff);
+ nhrpend = p + EXTRACT_16BITS(&hdr->pktsz);
+
+ switch (hdr->op_type) {
+ case NHRP_PKG_RESOLUTION_REQUEST:
+ printf("res request, ");
+ break;
+ case NHRP_PKG_RESOLUTION_REPLY:
+ printf("res reply, ");
+ break;
+ case NHRP_PKG_REGISTRATION_REQUEST:
+ printf("reg request, ");
+ break;
+ case NHRP_PKG_REGISTRATION_REPLY:
+ printf("reg reply, ");
+ break;
+ case NHRP_PKG_PURGE_REQUEST:
+ printf("purge request, ");
+ break;
+ case NHRP_PKG_PURGE_REPLY:
+ printf("purge reply, ");
+ break;
+ case NHRP_PKG_ERROR_INDICATION:
+ printf("error %u", hdr->u.err.code);
+ return;
+ default:
+ printf("unknown-op-type-%04x, ", hdr->op_type);
+ break;
+ }
+
+ printf("id %u", EXTRACT_32BITS(&hdr->u.id));
+
+ if (vflag) {
+ printf(", hopcnt %u", hdr->hopcnt);
+
+ /* most significat bit must be 0 */
+ if (hdr->shtl & 0x80)
+ printf(" (shtl bit 7 set)");
+
+ /* check 2nd most significant bit */
+ if (hdr->shtl & 0x40)
+ printf(" (nbma E.154)");
+ }
+
+ p += sizeof(*hdr);
+ if ((snapend - p) < hdr->shtl)
+ goto trunc;
+
+ if (hdr->shtl) {
+ switch (EXTRACT_16BITS(&hdr->afn)) {
+ case AFNUM_INET:
+ printf(", src nbma %s", ipaddr_string(p));
+ break;
+ case AFNUM_INET6:
+ printf(", src nbma %s", ip6addr_string(p));
+ break;
+ case AFNUM_802:
+ printf(", src nbma %s", etheraddr_string(p));
+ break;
+ default:
+ printf(", unknown-nbma-addr-family-%04x",
+ EXTRACT_16BITS(&hdr->afn));
+ break;
+ }
+ }
+
+ p += hdr->shtl;
+ if ((snapend - p) < (hdr->spl + hdr->dpl))
+ goto trunc;
+
+ switch (EXTRACT_16BITS(&hdr->pro_type)) {
+ case ETHERTYPE_IP:
+ printf(", %s -> %s",
+ ipaddr_string(p),
+ ipaddr_string(p + hdr->spl));
+ break;
+ case ETHERTYPE_IPV6:
+ printf(", %s -> %s",
+ ip6addr_string(p),
+ ip6addr_string(p + hdr->spl));
+ break;
+ default:
+ printf(", proto type %04x",
+ EXTRACT_16BITS(&hdr->pro_type));
+ break;
+ }
+
+ p += hdr->spl + hdr->dpl;
+
+ do {
+ p = nhrp_print_cie(p, hdr->afn, hdr->pro_type);
+ if (p == 0)
+ goto trunc;
+ } while ((hdr->extoff && (p < nhrpext)) ||
+ ((!hdr->extoff && (p < nhrpend))));
+
+ return;
+
+trunc:
+ printf(" [|nhrp]");
+
+}
+
+static const u_char *
+nhrp_print_cie(const u_char *data, u_int16_t afn, u_int16_t pro_type)
+{
+ struct nhrp_cie *cie;
+ int family, type;
+
+ if ((snapend - data) < sizeof(*cie))
+ return (0);
+
+ cie = (struct nhrp_cie *)data;
+
+ family = EXTRACT_16BITS(&afn);
+ type = EXTRACT_16BITS(&pro_type);
+
+ printf(" (code %d", cie->code);
+ if (vflag)
+ printf(", pl %d, mtu %d, htime %d, pref %d", cie->plen,
+ EXTRACT_16BITS(&cie->mtu), EXTRACT_16BITS(&cie->htime),
+ cie->pref);
+
+ /* check 2nd most significant bit */
+ if (cie->cli_addr_tl & 0x40)
+ printf(", nbma E.154");
+
+ data += sizeof(*cie);
+ if ((snapend - data) < cie->cli_addr_tl)
+ return (0);
+
+ if (cie->cli_addr_tl) {
+ switch (family) {
+ case AFNUM_INET:
+ printf(", nbma %s", ipaddr_string(data));
+ break;
+ case AFNUM_INET6:
+ printf(", nbma %s", ip6addr_string(data));
+ break;
+ case AFNUM_802:
+ printf(", nbma %s", etheraddr_string(data));
+ break;
+ default:
+ printf(", unknown-nbma-addr-family-%04x", family);
+ break;
+ }
+ }
+ if (cie->cli_saddr_tl)
+ printf(", unknown-nbma-saddr-family");
+
+ data += cie->cli_addr_tl + cie->cli_saddr_tl;
+ if ((snapend - data) < cie->cli_proto_tl)
+ return (0);
+
+ if (cie->cli_proto_tl) {
+ switch (type) {
+ case ETHERTYPE_IP:
+ printf(", proto %s", ipaddr_string(data));
+ break;
+ case ETHERTYPE_IPV6:
+ printf(", proto %s", ip6addr_string(data));
+ break;
+ default:
+ printf(", unknown-proto-family-%04x", type);
+ break;
+ }
+ }
+
+ printf(")");
+
+ return (data + cie->cli_proto_tl);
+}