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