mirror of
https://github.com/the-tcpdump-group/tcpdump.git
synced 2024-11-23 01:53:55 +08:00
94a3708f00
Builds using Autotools or CMake generate config.h, thus remove the '#ifdef HAVE_CONFIG_H'/'#endif'. Remove also the 'add_definitions(-DHAVE_CONFIG_H)' in CMakeLists.txt.
492 lines
14 KiB
C
492 lines
14 KiB
C
/* $OpenBSD: print-nhrp.c,v 1.2 2022/12/28 21:30:19 jmc Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 2020 Remi Locherer <remi@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.
|
|
*/
|
|
|
|
/* \summary: NHRP printer */
|
|
|
|
/*
|
|
* RFC 2332 NBMA Next Hop Resolution Protocol (NHRP)
|
|
* I-D draft-detienne-dmvpn-01 (expired)
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include "netdissect-stdinc.h"
|
|
|
|
#define ND_LONGJMP_FROM_TCHECK
|
|
#include "netdissect.h"
|
|
#include "addrtoname.h"
|
|
#include "af.h"
|
|
#include "ethertype.h"
|
|
#include "extract.h"
|
|
|
|
#define NHRP_VER_RFC2332 1
|
|
|
|
#define NHRP_PKT_RESOLUTION_REQUEST 1
|
|
#define NHRP_PKT_RESOLUTION_REPLY 2
|
|
#define NHRP_PKT_REGISTRATION_REQUEST 3
|
|
#define NHRP_PKT_REGISTRATION_REPLY 4
|
|
#define NHRP_PKT_PURGE_REQUEST 5
|
|
#define NHRP_PKT_PURGE_REPLY 6
|
|
#define NHRP_PKT_ERROR_INDICATION 7
|
|
#define NHRP_PKT_TRAFFIC_INDICATION 8 /* draft-detienne-dmvpn-01 */
|
|
|
|
static const struct tok pkt_types[] = {
|
|
{ NHRP_PKT_RESOLUTION_REQUEST, "res request" },
|
|
{ NHRP_PKT_RESOLUTION_REPLY, "res reply" },
|
|
{ NHRP_PKT_REGISTRATION_REQUEST, "reg request" },
|
|
{ NHRP_PKT_REGISTRATION_REPLY, "reg reply" },
|
|
{ NHRP_PKT_PURGE_REQUEST, "purge request" },
|
|
{ NHRP_PKT_PURGE_REPLY, "purge reply" },
|
|
{ NHRP_PKT_ERROR_INDICATION, "error indication" },
|
|
{ NHRP_PKT_TRAFFIC_INDICATION, "traffic indication" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
/*
|
|
* Fixed header part.
|
|
*/
|
|
struct nhrp_fixed_header {
|
|
nd_uint16_t afn; /* link layer address */
|
|
nd_uint16_t pro_type; /* protocol type (short form) */
|
|
nd_uint8_t pro_snap[5]; /* protocol type (long form) */
|
|
nd_uint8_t hopcnt; /* hop count */
|
|
nd_uint16_t pktsz; /* length of the NHRP packet (octets) */
|
|
nd_uint16_t chksum; /* IP checksum over the entier packet */
|
|
nd_uint16_t extoff; /* extension offset */
|
|
nd_uint8_t op_version; /* version of address mapping and
|
|
management protocol */
|
|
nd_uint8_t op_type; /* NHRP packet type */
|
|
nd_uint8_t shtl; /* type and length of src NBMA addr */
|
|
nd_uint8_t sstl; /* type and length of src NBMA
|
|
subaddress */
|
|
};
|
|
|
|
/*
|
|
* Mandatory header part. This is the beginning of the mandatory
|
|
* header; it's followed by addresses and client information entries.
|
|
*
|
|
* The mandatory header part formats are similar for
|
|
* all NHRP packets; the only difference is that NHRP_PKT_ERROR_INDICATION
|
|
* has a 16-bit error code and a 16-bit error packet offset, and
|
|
* NHRP_PKT_TRAFFIC_INDICATION has a 16-bit traffic code and a 16-bit unused
|
|
* field, rather than a 32-bit request ID.
|
|
*/
|
|
struct nhrp_mand_header {
|
|
nd_uint8_t spl; /* src proto len */
|
|
nd_uint8_t dpl; /* dst proto len */
|
|
nd_uint16_t flags; /* flags */
|
|
union {
|
|
nd_uint32_t id; /* request id */
|
|
struct { /* error code */
|
|
nd_uint16_t code;
|
|
nd_uint16_t offset;
|
|
} err;
|
|
struct { /* error code */
|
|
nd_uint16_t traffic_code;
|
|
nd_uint16_t unused;
|
|
} tind;
|
|
} u;
|
|
};
|
|
|
|
static const struct tok err_code_types[] = {
|
|
{ 1, "unrecognized extension" },
|
|
{ 3, "NHRP loop detected" },
|
|
{ 6, "protocol address unreachable" },
|
|
{ 7, "protocol error" },
|
|
{ 8, "NHRP SDU size exceeded" },
|
|
{ 9, "invalid extension" },
|
|
{ 10, "invalid NHRP resolution reply received" },
|
|
{ 11, "authentication failure" },
|
|
{ 15, "hop count exceeded" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const struct tok traffic_code_types[] = {
|
|
{ 0, "NHRP traffic redirect/indirection" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
#define NHRP_FIXED_HEADER_LEN 20
|
|
|
|
struct nhrp_cie {
|
|
/* client information entry */
|
|
nd_uint8_t code;
|
|
nd_uint8_t plen;
|
|
nd_uint16_t unused;
|
|
nd_uint16_t mtu;
|
|
nd_uint16_t htime;
|
|
nd_uint8_t cli_addr_tl;
|
|
nd_uint8_t cli_saddr_tl;
|
|
nd_uint8_t cli_proto_tl;
|
|
nd_uint8_t pref;
|
|
};
|
|
|
|
static u_int nhrp_print_cie(netdissect_options *ndo, const u_char *, uint16_t, uint16_t, uint16_t);
|
|
|
|
/*
|
|
* Get string for IPv4 address pointed to by addr if addrlen is 4;
|
|
* otherwise, get it as a string for the sequence of hex bytes.
|
|
*/
|
|
static const char *
|
|
nhrp_ipv4_addr_string(netdissect_options *ndo, const u_char *addr, u_int addrlen)
|
|
{
|
|
if (addrlen == 4)
|
|
return (GET_IPADDR_STRING(addr));
|
|
else
|
|
return (GET_LINKADDR_STRING(addr, LINKADDR_OTHER, addrlen));
|
|
}
|
|
#define NHRP_IPv4_ADDR_STRING(addr, addrlen) \
|
|
nhrp_ipv4_addr_string(ndo, (addr), (addrlen))
|
|
|
|
/*
|
|
* Get string for IPv6 address pointed to by addr if addrlen is 16;
|
|
* otherwise, get it as a string for the sequence of hex bytes.
|
|
*/
|
|
static const char *
|
|
nhrp_ipv6_addr_string(netdissect_options *ndo, const u_char *addr, u_int addrlen)
|
|
{
|
|
if (addrlen == 16)
|
|
return (GET_IP6ADDR_STRING(addr));
|
|
else
|
|
return (GET_LINKADDR_STRING(addr, LINKADDR_OTHER, addrlen));
|
|
}
|
|
#define NHRP_IPv6_ADDR_STRING(addr, addrlen) \
|
|
nhrp_ipv6_addr_string(ndo, (addr), (addrlen))
|
|
|
|
/*
|
|
* Get string for MAC address pointed to by addr if addrlen is 6;
|
|
* otherwise, get it as a string for the sequence of hex bytes.
|
|
*/
|
|
static const char *
|
|
nhrp_mac_addr_string(netdissect_options *ndo, const u_char *addr, u_int addrlen)
|
|
{
|
|
if (addrlen == 6)
|
|
return (GET_MAC48_STRING(addr));
|
|
else
|
|
return (GET_LINKADDR_STRING(addr, LINKADDR_OTHER, addrlen));
|
|
}
|
|
#define NHRP_MAC_ADDR_STRING(addr, addrlen) \
|
|
nhrp_mac_addr_string(ndo, (addr), (addrlen))
|
|
|
|
void
|
|
nhrp_print(netdissect_options *ndo, const u_char *bp, u_int length)
|
|
{
|
|
const struct nhrp_fixed_header *fixed_hdr;
|
|
uint16_t afn;
|
|
uint16_t pro_type;
|
|
uint16_t pktsz;
|
|
uint16_t extoff;
|
|
uint8_t op_version;
|
|
uint8_t op_type;
|
|
uint8_t shtl, sstl;
|
|
const struct nhrp_mand_header *mand_hdr;
|
|
uint16_t mand_part_len;
|
|
uint8_t spl, dpl;
|
|
|
|
ndo->ndo_protocol = "nhrp";
|
|
nd_print_protocol_caps(ndo);
|
|
ND_PRINT(": ");
|
|
|
|
fixed_hdr = (const struct nhrp_fixed_header *)bp;
|
|
|
|
ND_ICHECK_ZU(length, <, sizeof(*fixed_hdr));
|
|
op_version = GET_U_1(fixed_hdr->op_version);
|
|
if (op_version != NHRP_VER_RFC2332) {
|
|
ND_PRINT("unknown-version-%02x", op_version);
|
|
return;
|
|
}
|
|
|
|
afn = GET_BE_U_2(fixed_hdr->afn);
|
|
pro_type = GET_BE_U_2(fixed_hdr->pro_type);
|
|
|
|
pktsz = GET_BE_U_2(fixed_hdr->pktsz);
|
|
ND_ICHECKMSG_ZU("pktsz", pktsz, <, sizeof(*fixed_hdr));
|
|
extoff = GET_BE_U_2(fixed_hdr->extoff);
|
|
|
|
op_type = GET_U_1(fixed_hdr->op_type);
|
|
ND_PRINT("%s", tok2str(pkt_types, "unknown-op-type-%04x", op_type));
|
|
|
|
/*
|
|
* Mandatory part length.
|
|
* We already know that pktsz is large enough for the fixed
|
|
* header and the fixed part of the mandatory header.
|
|
*/
|
|
if (extoff == 0) {
|
|
mand_part_len = pktsz - sizeof(*fixed_hdr);
|
|
} else {
|
|
ND_ICHECKMSG_U("extoff", extoff, >, pktsz);
|
|
ND_ICHECKMSG_ZU("extoff", extoff, <, sizeof(*fixed_hdr));
|
|
mand_part_len = extoff - sizeof(*fixed_hdr);
|
|
}
|
|
length -= sizeof(*fixed_hdr);
|
|
if (mand_part_len > length)
|
|
mand_part_len = (uint16_t)length;
|
|
|
|
/* We start looking at the mandatory header here. */
|
|
ND_TCHECK_LEN(bp, sizeof(*fixed_hdr));
|
|
bp += sizeof(*fixed_hdr);
|
|
length -= sizeof(*fixed_hdr);
|
|
ND_ICHECK_ZU(mand_part_len, <, sizeof(*mand_hdr));
|
|
ND_TCHECK_LEN(bp, sizeof(*mand_hdr));
|
|
mand_hdr = (const struct nhrp_mand_header *)bp;
|
|
|
|
switch (op_type) {
|
|
case NHRP_PKT_RESOLUTION_REQUEST:
|
|
case NHRP_PKT_RESOLUTION_REPLY:
|
|
case NHRP_PKT_REGISTRATION_REQUEST:
|
|
case NHRP_PKT_REGISTRATION_REPLY:
|
|
case NHRP_PKT_PURGE_REQUEST:
|
|
case NHRP_PKT_PURGE_REPLY:
|
|
ND_PRINT(", id %u", GET_BE_U_4(mand_hdr->u.id));
|
|
break;
|
|
case NHRP_PKT_ERROR_INDICATION:
|
|
ND_PRINT(", error <%s>", tok2str(err_code_types, "unknown-err-code-%u", GET_BE_U_2(mand_hdr->u.err.code)));
|
|
break;
|
|
case NHRP_PKT_TRAFFIC_INDICATION:
|
|
ND_PRINT(", code <%s>", tok2str(traffic_code_types, "unknown-traffic-code-%u", GET_BE_U_2(mand_hdr->u.tind.traffic_code)));
|
|
break;
|
|
}
|
|
|
|
shtl = GET_U_1(fixed_hdr->shtl);
|
|
sstl = GET_U_1(fixed_hdr->sstl);
|
|
|
|
if (ndo->ndo_vflag) {
|
|
ND_PRINT(", hopcnt %u", GET_U_1(fixed_hdr->hopcnt));
|
|
|
|
/* most significant bit must be 0 */
|
|
if (shtl & 0x80)
|
|
ND_PRINT(" (shtl bit 7 set)");
|
|
|
|
/* check 2nd most significant bit */
|
|
if (shtl & 0x40)
|
|
ND_PRINT(" (nbma E.154)");
|
|
}
|
|
|
|
/* Mandatory header part */
|
|
spl = GET_U_1(mand_hdr->spl);
|
|
dpl = GET_U_1(mand_hdr->dpl);
|
|
bp += sizeof(*mand_hdr); /* Skip to the addresses */
|
|
mand_part_len -= sizeof(*mand_hdr);
|
|
|
|
/* Source NBMA Address, if any. */
|
|
if (shtl != 0) {
|
|
ND_ICHECK_U(mand_part_len, <, shtl);
|
|
switch (afn) {
|
|
case AFNUM_IP:
|
|
ND_PRINT(", src nbma %s", NHRP_IPv4_ADDR_STRING(bp, shtl));
|
|
break;
|
|
case AFNUM_IP6:
|
|
ND_PRINT(", src nbma %s", NHRP_IPv6_ADDR_STRING(bp, shtl));
|
|
break;
|
|
case AFNUM_802:
|
|
ND_PRINT(", src nbma %s", NHRP_MAC_ADDR_STRING(bp, shtl));
|
|
break;
|
|
default:
|
|
ND_PRINT(", unknown-nbma-addr-family-%04x (%s)",
|
|
afn, GET_LINKADDR_STRING(bp, LINKADDR_OTHER, shtl));
|
|
break;
|
|
}
|
|
bp += shtl;
|
|
mand_part_len -= shtl;
|
|
}
|
|
|
|
/* Skip the Source NBMA SubAddress, if any */
|
|
if (sstl != 0) {
|
|
ND_ICHECK_U(mand_part_len, <, sstl);
|
|
ND_TCHECK_LEN(bp, sstl);
|
|
bp += sstl;
|
|
mand_part_len -= sstl;
|
|
}
|
|
|
|
ND_PRINT(", ");
|
|
/* Source Protocol Address */
|
|
if (spl != 0) {
|
|
ND_ICHECK_U(mand_part_len, <, spl);
|
|
switch (pro_type) {
|
|
case ETHERTYPE_IP:
|
|
ND_PRINT("%s ", NHRP_IPv4_ADDR_STRING(bp, spl));
|
|
break;
|
|
case ETHERTYPE_IPV6:
|
|
ND_PRINT("%s ", NHRP_IPv6_ADDR_STRING(bp, spl));
|
|
break;
|
|
default:
|
|
ND_PRINT("proto type %04x ", pro_type);
|
|
ND_PRINT("%s ", GET_LINKADDR_STRING(bp, LINKADDR_OTHER, spl));
|
|
break;
|
|
}
|
|
bp += spl;
|
|
mand_part_len -= spl;
|
|
}
|
|
ND_PRINT("->");
|
|
/* Destination Protocol Address */
|
|
if (dpl != 0) {
|
|
ND_ICHECK_U(mand_part_len, <, dpl);
|
|
switch (pro_type) {
|
|
case ETHERTYPE_IP:
|
|
ND_PRINT(" %s", NHRP_IPv4_ADDR_STRING(bp, dpl));
|
|
break;
|
|
case ETHERTYPE_IPV6:
|
|
ND_PRINT(" %s", NHRP_IPv6_ADDR_STRING(bp, dpl));
|
|
break;
|
|
default:
|
|
ND_PRINT(" %s", GET_LINKADDR_STRING(bp, LINKADDR_OTHER, dpl));
|
|
break;
|
|
}
|
|
bp += dpl;
|
|
mand_part_len -= dpl;
|
|
}
|
|
|
|
switch (op_type) {
|
|
case NHRP_PKT_RESOLUTION_REQUEST:
|
|
case NHRP_PKT_RESOLUTION_REPLY:
|
|
case NHRP_PKT_REGISTRATION_REQUEST:
|
|
case NHRP_PKT_REGISTRATION_REPLY:
|
|
case NHRP_PKT_PURGE_REQUEST:
|
|
case NHRP_PKT_PURGE_REPLY:
|
|
/* Client Information Entries */
|
|
while (mand_part_len != 0) {
|
|
u_int cie_len;
|
|
|
|
/*
|
|
* cie_len is guaranteed by nhrp_print_cie()
|
|
* to be <= mand_part_len.
|
|
*/
|
|
cie_len = nhrp_print_cie(ndo, bp, mand_part_len,
|
|
afn, pro_type);
|
|
bp += cie_len;
|
|
mand_part_len -= (uint16_t)cie_len;
|
|
}
|
|
break;
|
|
case NHRP_PKT_ERROR_INDICATION:
|
|
/* Contents of NHRP Packet in error */
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return;
|
|
|
|
invalid:
|
|
nd_print_invalid(ndo);
|
|
}
|
|
|
|
static u_int
|
|
nhrp_print_cie(netdissect_options *ndo, const u_char *data, uint16_t mand_part_len,
|
|
uint16_t afn, uint16_t pro_type)
|
|
{
|
|
const struct nhrp_cie *cie;
|
|
u_int cie_len;
|
|
uint8_t cli_addr_tl;
|
|
uint8_t cli_saddr_tl;
|
|
uint8_t cli_proto_tl;
|
|
|
|
cie = (const struct nhrp_cie *)data;
|
|
cie_len = 0;
|
|
ND_ICHECKMSG_ZU("remaining mandatory part length",
|
|
mand_part_len, <, sizeof(*cie));
|
|
|
|
ND_PRINT(" (code %d", GET_U_1(cie->code));
|
|
if (ndo->ndo_vflag)
|
|
ND_PRINT(", pl %d, mtu %d, htime %d, pref %d",
|
|
GET_U_1(cie->plen),
|
|
GET_BE_U_2(cie->mtu),
|
|
GET_BE_U_2(cie->htime),
|
|
GET_U_1(cie->pref));
|
|
|
|
cli_addr_tl = GET_U_1(cie->cli_addr_tl);
|
|
cli_saddr_tl = GET_U_1(cie->cli_saddr_tl);
|
|
cli_proto_tl = GET_U_1(cie->cli_proto_tl);
|
|
|
|
/* check 2nd most significant bit */
|
|
if (cli_addr_tl & 0x40)
|
|
ND_PRINT(", nbma E.154");
|
|
|
|
data += sizeof(*cie);
|
|
cie_len += sizeof(*cie);
|
|
mand_part_len -= sizeof(*cie);
|
|
|
|
if (cli_addr_tl) {
|
|
ND_ICHECKMSG_U("remaining mandatory part length",
|
|
mand_part_len, <, cli_addr_tl);
|
|
switch (afn) {
|
|
case AFNUM_IP:
|
|
ND_PRINT(", nbma %s", NHRP_IPv4_ADDR_STRING(data, cli_addr_tl));
|
|
break;
|
|
case AFNUM_IP6:
|
|
ND_PRINT(", nbma %s", NHRP_IPv6_ADDR_STRING(data, cli_addr_tl));
|
|
break;
|
|
case AFNUM_802:
|
|
ND_PRINT(", nbma %s", NHRP_MAC_ADDR_STRING(data, cli_addr_tl));
|
|
break;
|
|
default:
|
|
ND_PRINT(", unknown-nbma-addr-family-%04x (%s)",
|
|
afn, GET_LINKADDR_STRING(data, LINKADDR_OTHER, cli_addr_tl));
|
|
break;
|
|
}
|
|
data += cli_addr_tl;
|
|
cie_len += cli_addr_tl;
|
|
mand_part_len -= cli_addr_tl;
|
|
}
|
|
|
|
if (cli_saddr_tl) {
|
|
ND_ICHECKMSG_U("remaining mandatory part length",
|
|
mand_part_len, <, cli_addr_tl);
|
|
ND_PRINT(", unknown-nbma-saddr-family");
|
|
ND_TCHECK_LEN(data, cli_saddr_tl);
|
|
data += cli_saddr_tl;
|
|
cie_len += cli_saddr_tl;
|
|
mand_part_len -= cli_saddr_tl;
|
|
}
|
|
|
|
if (cli_proto_tl) {
|
|
ND_ICHECKMSG_U("remaining mandatory part length",
|
|
mand_part_len, <, cli_proto_tl);
|
|
switch (pro_type) {
|
|
case ETHERTYPE_IP:
|
|
ND_PRINT(", proto %s", NHRP_IPv4_ADDR_STRING(data, cli_proto_tl));
|
|
break;
|
|
case ETHERTYPE_IPV6:
|
|
ND_PRINT(", proto %s", NHRP_IPv6_ADDR_STRING(data, cli_proto_tl));
|
|
break;
|
|
default:
|
|
ND_PRINT(", unknown-proto-family-%04x (%s)",
|
|
pro_type, GET_LINKADDR_STRING(data, LINKADDR_OTHER, cli_proto_tl));
|
|
break;
|
|
}
|
|
cie_len += cli_proto_tl;
|
|
mand_part_len -= cli_proto_tl;
|
|
}
|
|
|
|
ND_PRINT(")");
|
|
|
|
return (cie_len);
|
|
|
|
invalid:
|
|
nd_print_invalid(ndo);
|
|
|
|
/*
|
|
* We get here because this CIE goes past the remaining length,
|
|
* of the mandatory part. We've reported that error; we now
|
|
* assign the insufficiently-large remaining piece of the
|
|
* mandatory part to this CIE, so that this CIE finishes up
|
|
* the mandatory part, and the loop processing the CIEs
|
|
* terminates. There cannot be any CIEs after this one.
|
|
*/
|
|
cie_len += mand_part_len;
|
|
return (cie_len);
|
|
}
|