On Tue, Apr 14, 2020 at 01:49:32PM +1000, David Gwynne wrote:
> 
> 
> > On 13 Apr 2020, at 19:03, Remi Locherer <remi.loche...@relo.ch> 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 <r...@openbsd.org>
+ *
+ * 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);
+}

Reply via email to