xref: /openbsd-src/usr.sbin/tcpdump/print-nhrp.c (revision 3a50f0a93a2072911d0ba6ababa815fb04bf9a71)
1*3a50f0a9Sjmc /*	$OpenBSD: print-nhrp.c,v 1.2 2022/12/28 21:30:19 jmc Exp $ */
2a66f6432Sremi 
3a66f6432Sremi /*
4a66f6432Sremi  * Copyright (c) 2020 Remi Locherer <remi@openbsd.org>
5a66f6432Sremi  *
6a66f6432Sremi  * Permission to use, copy, modify, and distribute this software for any
7a66f6432Sremi  * purpose with or without fee is hereby granted, provided that the above
8a66f6432Sremi  * copyright notice and this permission notice appear in all copies.
9a66f6432Sremi  *
10a66f6432Sremi  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11a66f6432Sremi  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12a66f6432Sremi  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13a66f6432Sremi  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14a66f6432Sremi  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15a66f6432Sremi  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16a66f6432Sremi  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a66f6432Sremi  */
18a66f6432Sremi 
19a66f6432Sremi /*
20a66f6432Sremi  * RFC 2332 NBMA Next Hop Resolution Protocol (NHRP)
21a66f6432Sremi  */
22a66f6432Sremi 
23a66f6432Sremi #include <sys/time.h>
24a66f6432Sremi #include <sys/uio.h>
25a66f6432Sremi #include <sys/socket.h>
26a66f6432Sremi 
27a66f6432Sremi #include <netinet/in.h>
28a66f6432Sremi #include <netinet/ip.h>
29a66f6432Sremi #include <arpa/inet.h>
30a66f6432Sremi 
31a66f6432Sremi #include <net/ethertypes.h>
32a66f6432Sremi 
33a66f6432Sremi #include <stdio.h>
34a66f6432Sremi #include <string.h>
35a66f6432Sremi #include <ctype.h>
36a66f6432Sremi 
37a66f6432Sremi #include "addrtoname.h"
38a66f6432Sremi #include "afnum.h"
39a66f6432Sremi #include "interface.h"
40a66f6432Sremi #include "extract.h"
41a66f6432Sremi 
42a66f6432Sremi #define NHRP_VER_RFC2332		1
43a66f6432Sremi 
44a66f6432Sremi #define NHRP_PKG_RESOLUTION_REQUEST	1
45a66f6432Sremi #define NHRP_PKG_RESOLUTION_REPLY	2
46a66f6432Sremi #define NHRP_PKG_REGISTRATION_REQUEST	3
47a66f6432Sremi #define NHRP_PKG_REGISTRATION_REPLY	4
48a66f6432Sremi #define NHRP_PKG_PURGE_REQUEST		5
49a66f6432Sremi #define NHRP_PKG_PURGE_REPLY		6
50a66f6432Sremi #define NHRP_PKG_ERROR_INDICATION	7
51a66f6432Sremi 
52a66f6432Sremi 
53a66f6432Sremi struct nhrp_header {
54a66f6432Sremi 	/* fixed header part */
55a66f6432Sremi 	u_int16_t	afn;		/* link layer address */
56a66f6432Sremi 	u_int16_t	pro_type;	/* protocol type (short form) */
57a66f6432Sremi 	u_int8_t	pro_snap[5];	/* protocol type (long form) */
58a66f6432Sremi 	u_int8_t	hopcnt;		/* hop count */
59a66f6432Sremi 	u_int16_t	pktsz;		/* length of the NHRP packet (octets) */
60a66f6432Sremi 	u_int16_t	chksum;		/* IP checksum over the entier packet */
61a66f6432Sremi 	u_int16_t	extoff;		/* extension offset */
62a66f6432Sremi 	u_int8_t	op_version;	/* version of address mapping and
63a66f6432Sremi 					   management protocol */
64a66f6432Sremi 	u_int8_t	op_type;	/* NHRP packet type */
65a66f6432Sremi 	u_int8_t	shtl;		/* type and length of src NBMA addr */
66a66f6432Sremi 	u_int8_t	sstl;		/* type and length of src NBMA
67a66f6432Sremi 					   subaddress */
68a66f6432Sremi 	/* mandatory header part */
69a66f6432Sremi 	u_int8_t	spl;		/* src proto len */
70a66f6432Sremi 	u_int8_t	dpl;		/* dst proto len */
71a66f6432Sremi 	u_int16_t	flags;		/* flags */
72a66f6432Sremi         union {
73a66f6432Sremi 		u_int32_t	id;	/* request id */
74a66f6432Sremi 		struct {		/* error code */
75a66f6432Sremi 			u_int16_t	code;
76a66f6432Sremi 			u_int16_t	offset;
77a66f6432Sremi 		} err;
78a66f6432Sremi 	} u;
79a66f6432Sremi };
80a66f6432Sremi 
81a66f6432Sremi struct nhrp_cie {
82a66f6432Sremi 	/* client information entrie */
83a66f6432Sremi 	u_int8_t	code;
84a66f6432Sremi 	u_int8_t	plen;
85a66f6432Sremi 	u_int16_t	unused;
86a66f6432Sremi 	u_int16_t	mtu;
87a66f6432Sremi 	u_int16_t	htime;
88a66f6432Sremi 	u_int8_t	cli_addr_tl;
89a66f6432Sremi 	u_int8_t	cli_saddr_tl;
90a66f6432Sremi 	u_int8_t	cli_proto_tl;
91a66f6432Sremi 	u_int8_t	pref;
92a66f6432Sremi };
93a66f6432Sremi 
94a66f6432Sremi static const u_char *	nhrp_print_cie(const u_char *, u_int16_t, u_int16_t);
95a66f6432Sremi 
96a66f6432Sremi 
97a66f6432Sremi void
nhrp_print(const u_char * p,u_int length)98a66f6432Sremi nhrp_print(const u_char *p, u_int length)
99a66f6432Sremi {
100a66f6432Sremi 	struct nhrp_header	*hdr;
101a66f6432Sremi 	const u_char		*nhrpext, *nhrpend;
102a66f6432Sremi 
103a66f6432Sremi 	printf("NHRP: ");
104a66f6432Sremi 
105a66f6432Sremi 	if ((snapend - p) < sizeof(*hdr))
106a66f6432Sremi 		goto trunc;
107a66f6432Sremi 
108a66f6432Sremi 	hdr = (struct nhrp_header *)p;
109a66f6432Sremi 
110a66f6432Sremi 	if (hdr->op_version != NHRP_VER_RFC2332) {
111a66f6432Sremi 		printf("unknown-version-%02x", hdr->op_version);
112a66f6432Sremi 		return;
113a66f6432Sremi 
114a66f6432Sremi 	}
115a66f6432Sremi 
116a66f6432Sremi 	nhrpext = p + EXTRACT_16BITS(&hdr->extoff);
117a66f6432Sremi 	nhrpend = p + EXTRACT_16BITS(&hdr->pktsz);
118a66f6432Sremi 
119a66f6432Sremi 	switch (hdr->op_type) {
120a66f6432Sremi 	case NHRP_PKG_RESOLUTION_REQUEST:
121a66f6432Sremi 		printf("res request, ");
122a66f6432Sremi 		break;
123a66f6432Sremi 	case NHRP_PKG_RESOLUTION_REPLY:
124a66f6432Sremi 		printf("res reply, ");
125a66f6432Sremi 		break;
126a66f6432Sremi 	case NHRP_PKG_REGISTRATION_REQUEST:
127a66f6432Sremi 		printf("reg request, ");
128a66f6432Sremi 		break;
129a66f6432Sremi 	case NHRP_PKG_REGISTRATION_REPLY:
130a66f6432Sremi 		printf("reg reply, ");
131a66f6432Sremi 		break;
132a66f6432Sremi 	case NHRP_PKG_PURGE_REQUEST:
133a66f6432Sremi 		printf("purge request, ");
134a66f6432Sremi 		break;
135a66f6432Sremi 	case NHRP_PKG_PURGE_REPLY:
136a66f6432Sremi 		printf("purge reply, ");
137a66f6432Sremi 		break;
138a66f6432Sremi 	case NHRP_PKG_ERROR_INDICATION:
139a66f6432Sremi 		printf("error %u", hdr->u.err.code);
140a66f6432Sremi 		return;
141a66f6432Sremi 	default:
142a66f6432Sremi 		printf("unknown-op-type-%04x, ", hdr->op_type);
143a66f6432Sremi 		break;
144a66f6432Sremi 	}
145a66f6432Sremi 
146a66f6432Sremi 	printf("id %u", EXTRACT_32BITS(&hdr->u.id));
147a66f6432Sremi 
148a66f6432Sremi 	if (vflag) {
149a66f6432Sremi 		printf(", hopcnt %u", hdr->hopcnt);
150a66f6432Sremi 
151*3a50f0a9Sjmc 		/* most significant bit must be 0 */
152a66f6432Sremi 		if (hdr->shtl & 0x80)
153a66f6432Sremi 			printf(" (shtl bit 7 set)");
154a66f6432Sremi 
155a66f6432Sremi 		/* check 2nd most significant bit */
156a66f6432Sremi 		if (hdr->shtl & 0x40)
157a66f6432Sremi 			printf(" (nbma E.154)");
158a66f6432Sremi 	}
159a66f6432Sremi 
160a66f6432Sremi 	p += sizeof(*hdr);
161a66f6432Sremi 	if ((snapend - p) < hdr->shtl)
162a66f6432Sremi 		goto trunc;
163a66f6432Sremi 
164a66f6432Sremi 	if (hdr->shtl) {
165a66f6432Sremi 		switch (EXTRACT_16BITS(&hdr->afn)) {
166a66f6432Sremi 		case AFNUM_INET:
167a66f6432Sremi 			printf(", src nbma %s", ipaddr_string(p));
168a66f6432Sremi 			break;
169a66f6432Sremi 		case AFNUM_INET6:
170a66f6432Sremi 			printf(", src nbma %s", ip6addr_string(p));
171a66f6432Sremi 			break;
172a66f6432Sremi 		case AFNUM_802:
173a66f6432Sremi 			printf(", src nbma %s", etheraddr_string(p));
174a66f6432Sremi 			break;
175a66f6432Sremi 		default:
176a66f6432Sremi 			printf(", unknown-nbma-addr-family-%04x",
177a66f6432Sremi 			    EXTRACT_16BITS(&hdr->afn));
178a66f6432Sremi 			break;
179a66f6432Sremi 		}
180a66f6432Sremi 	}
181a66f6432Sremi 
182a66f6432Sremi 	p += hdr->shtl;
183a66f6432Sremi 	if ((snapend - p) < (hdr->spl + hdr->dpl))
184a66f6432Sremi 		goto trunc;
185a66f6432Sremi 
186a66f6432Sremi 	switch (EXTRACT_16BITS(&hdr->pro_type)) {
187a66f6432Sremi 	case ETHERTYPE_IP:
188a66f6432Sremi 		printf(", %s -> %s",
189a66f6432Sremi 		    ipaddr_string(p),
190a66f6432Sremi 		    ipaddr_string(p + hdr->spl));
191a66f6432Sremi 		break;
192a66f6432Sremi 	case ETHERTYPE_IPV6:
193a66f6432Sremi 		printf(", %s -> %s",
194a66f6432Sremi 		    ip6addr_string(p),
195a66f6432Sremi 		    ip6addr_string(p + hdr->spl));
196a66f6432Sremi 		break;
197a66f6432Sremi 	default:
198a66f6432Sremi 		printf(", proto type %04x",
199a66f6432Sremi 		    EXTRACT_16BITS(&hdr->pro_type));
200a66f6432Sremi 		break;
201a66f6432Sremi 	}
202a66f6432Sremi 
203a66f6432Sremi 	p += hdr->spl + hdr->dpl;
204a66f6432Sremi 
205a66f6432Sremi 	do {
206a66f6432Sremi 		p = nhrp_print_cie(p, hdr->afn, hdr->pro_type);
207a66f6432Sremi 		if (p == 0)
208a66f6432Sremi 			goto trunc;
209a66f6432Sremi 	} while ((hdr->extoff && (p < nhrpext)) ||
210a66f6432Sremi 		    ((!hdr->extoff && (p < nhrpend))));
211a66f6432Sremi 
212a66f6432Sremi 	return;
213a66f6432Sremi 
214a66f6432Sremi trunc:
215a66f6432Sremi 	printf(" [|nhrp]");
216a66f6432Sremi 
217a66f6432Sremi }
218a66f6432Sremi 
219a66f6432Sremi static const u_char *
nhrp_print_cie(const u_char * data,u_int16_t afn,u_int16_t pro_type)220a66f6432Sremi nhrp_print_cie(const u_char *data, u_int16_t afn, u_int16_t pro_type)
221a66f6432Sremi {
222a66f6432Sremi 	struct nhrp_cie		*cie;
223a66f6432Sremi 	int			 family, type;
224a66f6432Sremi 
225a66f6432Sremi 	if ((snapend - data) < sizeof(*cie))
226a66f6432Sremi 		return (0);
227a66f6432Sremi 
228a66f6432Sremi 	cie = (struct nhrp_cie *)data;
229a66f6432Sremi 
230a66f6432Sremi 	family = EXTRACT_16BITS(&afn);
231a66f6432Sremi 	type = EXTRACT_16BITS(&pro_type);
232a66f6432Sremi 
233a66f6432Sremi 	printf(" (code %d", cie->code);
234a66f6432Sremi 	if (vflag)
235a66f6432Sremi 		printf(", pl %d, mtu %d, htime %d, pref %d", cie->plen,
236a66f6432Sremi 		    EXTRACT_16BITS(&cie->mtu), EXTRACT_16BITS(&cie->htime),
237a66f6432Sremi 		    cie->pref);
238a66f6432Sremi 
239a66f6432Sremi 	/* check 2nd most significant bit */
240a66f6432Sremi 	if (cie->cli_addr_tl & 0x40)
241a66f6432Sremi 		printf(", nbma E.154");
242a66f6432Sremi 
243a66f6432Sremi 	data += sizeof(*cie);
244a66f6432Sremi 	if ((snapend - data) < cie->cli_addr_tl)
245a66f6432Sremi 		return (0);
246a66f6432Sremi 
247a66f6432Sremi 	if (cie->cli_addr_tl) {
248a66f6432Sremi 		switch (family) {
249a66f6432Sremi 		case AFNUM_INET:
250a66f6432Sremi 			printf(", nbma %s", ipaddr_string(data));
251a66f6432Sremi 			break;
252a66f6432Sremi 		case AFNUM_INET6:
253a66f6432Sremi 			printf(", nbma %s", ip6addr_string(data));
254a66f6432Sremi 			break;
255a66f6432Sremi 		case AFNUM_802:
256a66f6432Sremi 			printf(", nbma %s", etheraddr_string(data));
257a66f6432Sremi 			break;
258a66f6432Sremi 		default:
259a66f6432Sremi 			printf(", unknown-nbma-addr-family-%04x", family);
260a66f6432Sremi 			break;
261a66f6432Sremi 		}
262a66f6432Sremi 	}
263a66f6432Sremi 	if (cie->cli_saddr_tl)
264a66f6432Sremi 		printf(", unknown-nbma-saddr-family");
265a66f6432Sremi 
266a66f6432Sremi 	data += cie->cli_addr_tl + cie->cli_saddr_tl;
267a66f6432Sremi 	if ((snapend - data) < cie->cli_proto_tl)
268a66f6432Sremi 		return (0);
269a66f6432Sremi 
270a66f6432Sremi 	if (cie->cli_proto_tl) {
271a66f6432Sremi 		switch (type) {
272a66f6432Sremi 		case ETHERTYPE_IP:
273a66f6432Sremi 			printf(", proto %s", ipaddr_string(data));
274a66f6432Sremi 			break;
275a66f6432Sremi 		case ETHERTYPE_IPV6:
276a66f6432Sremi 			printf(", proto %s", ip6addr_string(data));
277a66f6432Sremi 			break;
278a66f6432Sremi 		default:
279a66f6432Sremi 			printf(", unknown-proto-family-%04x", type);
280a66f6432Sremi 			break;
281a66f6432Sremi 		}
282a66f6432Sremi 	}
283a66f6432Sremi 
284a66f6432Sremi 	printf(")");
285a66f6432Sremi 
286a66f6432Sremi 	return (data + cie->cli_proto_tl);
287a66f6432Sremi }
288