> On 14 Apr 2020, at 8:15 pm, Remi Locherer <remi.loche...@relo.ch> wrote:
>
> 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?
yes. ok by me.
> 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);
> +}