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); +}