/* $OpenBSD: print-nhrp.c,v 1.1 2020/04/15 20:19:25 remi Exp $ */ /* * Copyright (c) 2020 Remi Locherer * * 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 #include #include #include #include #include #include #include #include #include #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); }