[BACK]Return to print-nhrp.c CVS log [TXT][DIR] Up to [local] / src / usr.sbin / tcpdump

File: [local] / src / usr.sbin / tcpdump / print-nhrp.c (download)

Revision 1.2, Wed Dec 28 21:30:19 2022 UTC (17 months, 1 week ago) by jmc
Branch: MAIN
CVS Tags: OPENBSD_7_5_BASE, OPENBSD_7_5, OPENBSD_7_4_BASE, OPENBSD_7_4, OPENBSD_7_3_BASE, OPENBSD_7_3, HEAD
Changes since 1.1: +2 -2 lines

spelling fixes; from paul tagliamonte
any parts of his diff not taken are noted on tech

/*	$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.
 */

/*
 * 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 significant 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);
}