]> The Tcpdump Group git mirrors - tcpdump/blob - print-nhrp.c
pflog: Include <limits.h> for UINT_MAX
[tcpdump] / print-nhrp.c
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 /* \summary: NHRP printer */
20
21 /*
22 * RFC 2332 NBMA Next Hop Resolution Protocol (NHRP)
23 * I-D draft-detienne-dmvpn-01 (expired)
24 */
25
26 #include <config.h>
27
28 #include "netdissect-stdinc.h"
29
30 #define ND_LONGJMP_FROM_TCHECK
31 #include "netdissect.h"
32 #include "addrtoname.h"
33 #include "af.h"
34 #include "ethertype.h"
35 #include "extract.h"
36
37 #define NHRP_VER_RFC2332 1
38
39 #define NHRP_PKT_RESOLUTION_REQUEST 1
40 #define NHRP_PKT_RESOLUTION_REPLY 2
41 #define NHRP_PKT_REGISTRATION_REQUEST 3
42 #define NHRP_PKT_REGISTRATION_REPLY 4
43 #define NHRP_PKT_PURGE_REQUEST 5
44 #define NHRP_PKT_PURGE_REPLY 6
45 #define NHRP_PKT_ERROR_INDICATION 7
46 #define NHRP_PKT_TRAFFIC_INDICATION 8 /* draft-detienne-dmvpn-01 */
47
48 static const struct tok pkt_types[] = {
49 { NHRP_PKT_RESOLUTION_REQUEST, "res request" },
50 { NHRP_PKT_RESOLUTION_REPLY, "res reply" },
51 { NHRP_PKT_REGISTRATION_REQUEST, "reg request" },
52 { NHRP_PKT_REGISTRATION_REPLY, "reg reply" },
53 { NHRP_PKT_PURGE_REQUEST, "purge request" },
54 { NHRP_PKT_PURGE_REPLY, "purge reply" },
55 { NHRP_PKT_ERROR_INDICATION, "error indication" },
56 { NHRP_PKT_TRAFFIC_INDICATION, "traffic indication" },
57 { 0, NULL }
58 };
59
60 /*
61 * Fixed header part.
62 */
63 struct nhrp_fixed_header {
64 nd_uint16_t afn; /* link layer address */
65 nd_uint16_t pro_type; /* protocol type (short form) */
66 nd_uint8_t pro_snap[5]; /* protocol type (long form) */
67 nd_uint8_t hopcnt; /* hop count */
68 nd_uint16_t pktsz; /* length of the NHRP packet (octets) */
69 nd_uint16_t chksum; /* IP checksum over the entier packet */
70 nd_uint16_t extoff; /* extension offset */
71 nd_uint8_t op_version; /* version of address mapping and
72 management protocol */
73 nd_uint8_t op_type; /* NHRP packet type */
74 nd_uint8_t shtl; /* type and length of src NBMA addr */
75 nd_uint8_t sstl; /* type and length of src NBMA
76 subaddress */
77 };
78
79 /*
80 * Mandatory header part. This is the beginning of the mandatory
81 * header; it's followed by addresses and client information entries.
82 *
83 * The mandatory header part formats are similar for
84 * all NHRP packets; the only difference is that NHRP_PKT_ERROR_INDICATION
85 * has a 16-bit error code and a 16-bit error packet offset, and
86 * NHRP_PKT_TRAFFIC_INDICATION has a 16-bit traffic code and a 16-bit unused
87 * field, rather than a 32-bit request ID.
88 */
89 struct nhrp_mand_header {
90 nd_uint8_t spl; /* src proto len */
91 nd_uint8_t dpl; /* dst proto len */
92 nd_uint16_t flags; /* flags */
93 union {
94 nd_uint32_t id; /* request id */
95 struct { /* error code */
96 nd_uint16_t code;
97 nd_uint16_t offset;
98 } err;
99 struct { /* error code */
100 nd_uint16_t traffic_code;
101 nd_uint16_t unused;
102 } tind;
103 } u;
104 };
105
106 static const struct tok err_code_types[] = {
107 { 1, "unrecognized extension" },
108 { 3, "NHRP loop detected" },
109 { 6, "protocol address unreachable" },
110 { 7, "protocol error" },
111 { 8, "NHRP SDU size exceeded" },
112 { 9, "invalid extension" },
113 { 10, "invalid NHRP resolution reply received" },
114 { 11, "authentication failure" },
115 { 15, "hop count exceeded" },
116 { 0, NULL }
117 };
118
119 static const struct tok traffic_code_types[] = {
120 { 0, "NHRP traffic redirect/indirection" },
121 { 0, NULL }
122 };
123
124 #define NHRP_FIXED_HEADER_LEN 20
125
126 struct nhrp_cie {
127 /* client information entry */
128 nd_uint8_t code;
129 nd_uint8_t plen;
130 nd_uint16_t unused;
131 nd_uint16_t mtu;
132 nd_uint16_t htime;
133 nd_uint8_t cli_addr_tl;
134 nd_uint8_t cli_saddr_tl;
135 nd_uint8_t cli_proto_tl;
136 nd_uint8_t pref;
137 };
138
139 static u_int nhrp_print_cie(netdissect_options *ndo, const u_char *, uint16_t, uint16_t, uint16_t);
140
141 /*
142 * Get string for IPv4 address pointed to by addr if addrlen is 4;
143 * otherwise, get it as a string for the sequence of hex bytes.
144 */
145 static const char *
146 nhrp_ipv4_addr_string(netdissect_options *ndo, const u_char *addr, u_int addrlen)
147 {
148 if (addrlen == 4)
149 return (GET_IPADDR_STRING(addr));
150 else
151 return (GET_LINKADDR_STRING(addr, LINKADDR_OTHER, addrlen));
152 }
153 #define NHRP_IPv4_ADDR_STRING(addr, addrlen) \
154 nhrp_ipv4_addr_string(ndo, (addr), (addrlen))
155
156 /*
157 * Get string for IPv6 address pointed to by addr if addrlen is 16;
158 * otherwise, get it as a string for the sequence of hex bytes.
159 */
160 static const char *
161 nhrp_ipv6_addr_string(netdissect_options *ndo, const u_char *addr, u_int addrlen)
162 {
163 if (addrlen == 16)
164 return (GET_IP6ADDR_STRING(addr));
165 else
166 return (GET_LINKADDR_STRING(addr, LINKADDR_OTHER, addrlen));
167 }
168 #define NHRP_IPv6_ADDR_STRING(addr, addrlen) \
169 nhrp_ipv6_addr_string(ndo, (addr), (addrlen))
170
171 /*
172 * Get string for MAC address pointed to by addr if addrlen is 6;
173 * otherwise, get it as a string for the sequence of hex bytes.
174 */
175 static const char *
176 nhrp_mac_addr_string(netdissect_options *ndo, const u_char *addr, u_int addrlen)
177 {
178 if (addrlen == 6)
179 return (GET_MAC48_STRING(addr));
180 else
181 return (GET_LINKADDR_STRING(addr, LINKADDR_OTHER, addrlen));
182 }
183 #define NHRP_MAC_ADDR_STRING(addr, addrlen) \
184 nhrp_mac_addr_string(ndo, (addr), (addrlen))
185
186 void
187 nhrp_print(netdissect_options *ndo, const u_char *bp, u_int length)
188 {
189 const struct nhrp_fixed_header *fixed_hdr;
190 uint16_t afn;
191 uint16_t pro_type;
192 uint16_t pktsz;
193 uint16_t extoff;
194 uint8_t op_version;
195 uint8_t op_type;
196 uint8_t shtl, sstl;
197 const struct nhrp_mand_header *mand_hdr;
198 uint16_t mand_part_len;
199 uint8_t spl, dpl;
200
201 ndo->ndo_protocol = "nhrp";
202 nd_print_protocol_caps(ndo);
203 ND_PRINT(": ");
204
205 fixed_hdr = (const struct nhrp_fixed_header *)bp;
206
207 ND_ICHECK_ZU(length, <, sizeof(*fixed_hdr));
208 op_version = GET_U_1(fixed_hdr->op_version);
209 if (op_version != NHRP_VER_RFC2332) {
210 ND_PRINT("unknown-version-%02x", op_version);
211 return;
212 }
213
214 afn = GET_BE_U_2(fixed_hdr->afn);
215 pro_type = GET_BE_U_2(fixed_hdr->pro_type);
216
217 pktsz = GET_BE_U_2(fixed_hdr->pktsz);
218 ND_ICHECKMSG_ZU("pktsz", pktsz, <, sizeof(*fixed_hdr));
219 extoff = GET_BE_U_2(fixed_hdr->extoff);
220
221 op_type = GET_U_1(fixed_hdr->op_type);
222 ND_PRINT("%s", tok2str(pkt_types, "unknown-op-type-%04x", op_type));
223
224 /*
225 * Mandatory part length.
226 * We already know that pktsz is large enough for the fixed
227 * header and the fixed part of the mandatory header.
228 */
229 if (extoff == 0) {
230 mand_part_len = pktsz - sizeof(*fixed_hdr);
231 } else {
232 ND_ICHECKMSG_U("extoff", extoff, >, pktsz);
233 ND_ICHECKMSG_ZU("extoff", extoff, <, sizeof(*fixed_hdr));
234 mand_part_len = extoff - sizeof(*fixed_hdr);
235 }
236 length -= sizeof(*fixed_hdr);
237 if (mand_part_len > length)
238 mand_part_len = (uint16_t)length;
239
240 /* We start looking at the mandatory header here. */
241 ND_TCHECK_LEN(bp, sizeof(*fixed_hdr));
242 bp += sizeof(*fixed_hdr);
243 length -= sizeof(*fixed_hdr);
244 ND_ICHECK_ZU(mand_part_len, <, sizeof(*mand_hdr));
245 ND_TCHECK_LEN(bp, sizeof(*mand_hdr));
246 mand_hdr = (const struct nhrp_mand_header *)bp;
247
248 switch (op_type) {
249 case NHRP_PKT_RESOLUTION_REQUEST:
250 case NHRP_PKT_RESOLUTION_REPLY:
251 case NHRP_PKT_REGISTRATION_REQUEST:
252 case NHRP_PKT_REGISTRATION_REPLY:
253 case NHRP_PKT_PURGE_REQUEST:
254 case NHRP_PKT_PURGE_REPLY:
255 ND_PRINT(", id %u", GET_BE_U_4(mand_hdr->u.id));
256 break;
257 case NHRP_PKT_ERROR_INDICATION:
258 ND_PRINT(", error <%s>", tok2str(err_code_types, "unknown-err-code-%u", GET_BE_U_2(mand_hdr->u.err.code)));
259 break;
260 case NHRP_PKT_TRAFFIC_INDICATION:
261 ND_PRINT(", code <%s>", tok2str(traffic_code_types, "unknown-traffic-code-%u", GET_BE_U_2(mand_hdr->u.tind.traffic_code)));
262 break;
263 }
264
265 shtl = GET_U_1(fixed_hdr->shtl);
266 sstl = GET_U_1(fixed_hdr->sstl);
267
268 if (ndo->ndo_vflag) {
269 ND_PRINT(", hopcnt %u", GET_U_1(fixed_hdr->hopcnt));
270
271 /* most significant bit must be 0 */
272 if (shtl & 0x80)
273 ND_PRINT(" (shtl bit 7 set)");
274
275 /* check 2nd most significant bit */
276 if (shtl & 0x40)
277 ND_PRINT(" (nbma E.154)");
278 }
279
280 /* Mandatory header part */
281 spl = GET_U_1(mand_hdr->spl);
282 dpl = GET_U_1(mand_hdr->dpl);
283 bp += sizeof(*mand_hdr); /* Skip to the addresses */
284 mand_part_len -= sizeof(*mand_hdr);
285
286 /* Source NBMA Address, if any. */
287 if (shtl != 0) {
288 ND_ICHECK_U(mand_part_len, <, shtl);
289 switch (afn) {
290 case AFNUM_IP:
291 ND_PRINT(", src nbma %s", NHRP_IPv4_ADDR_STRING(bp, shtl));
292 break;
293 case AFNUM_IP6:
294 ND_PRINT(", src nbma %s", NHRP_IPv6_ADDR_STRING(bp, shtl));
295 break;
296 case AFNUM_802:
297 ND_PRINT(", src nbma %s", NHRP_MAC_ADDR_STRING(bp, shtl));
298 break;
299 default:
300 ND_PRINT(", unknown-nbma-addr-family-%04x (%s)",
301 afn, GET_LINKADDR_STRING(bp, LINKADDR_OTHER, shtl));
302 break;
303 }
304 bp += shtl;
305 mand_part_len -= shtl;
306 }
307
308 /* Skip the Source NBMA SubAddress, if any */
309 if (sstl != 0) {
310 ND_ICHECK_U(mand_part_len, <, sstl);
311 ND_TCHECK_LEN(bp, sstl);
312 bp += sstl;
313 mand_part_len -= sstl;
314 }
315
316 ND_PRINT(", ");
317 /* Source Protocol Address */
318 if (spl != 0) {
319 ND_ICHECK_U(mand_part_len, <, spl);
320 switch (pro_type) {
321 case ETHERTYPE_IP:
322 ND_PRINT("%s ", NHRP_IPv4_ADDR_STRING(bp, spl));
323 break;
324 case ETHERTYPE_IPV6:
325 ND_PRINT("%s ", NHRP_IPv6_ADDR_STRING(bp, spl));
326 break;
327 default:
328 ND_PRINT("proto type %04x ", pro_type);
329 ND_PRINT("%s ", GET_LINKADDR_STRING(bp, LINKADDR_OTHER, spl));
330 break;
331 }
332 bp += spl;
333 mand_part_len -= spl;
334 }
335 ND_PRINT("->");
336 /* Destination Protocol Address */
337 if (dpl != 0) {
338 ND_ICHECK_U(mand_part_len, <, dpl);
339 switch (pro_type) {
340 case ETHERTYPE_IP:
341 ND_PRINT(" %s", NHRP_IPv4_ADDR_STRING(bp, dpl));
342 break;
343 case ETHERTYPE_IPV6:
344 ND_PRINT(" %s", NHRP_IPv6_ADDR_STRING(bp, dpl));
345 break;
346 default:
347 ND_PRINT(" %s", GET_LINKADDR_STRING(bp, LINKADDR_OTHER, dpl));
348 break;
349 }
350 bp += dpl;
351 mand_part_len -= dpl;
352 }
353
354 switch (op_type) {
355 case NHRP_PKT_RESOLUTION_REQUEST:
356 case NHRP_PKT_RESOLUTION_REPLY:
357 case NHRP_PKT_REGISTRATION_REQUEST:
358 case NHRP_PKT_REGISTRATION_REPLY:
359 case NHRP_PKT_PURGE_REQUEST:
360 case NHRP_PKT_PURGE_REPLY:
361 /* Client Information Entries */
362 while (mand_part_len != 0) {
363 u_int cie_len;
364
365 /*
366 * cie_len is guaranteed by nhrp_print_cie()
367 * to be <= mand_part_len.
368 */
369 cie_len = nhrp_print_cie(ndo, bp, mand_part_len,
370 afn, pro_type);
371 bp += cie_len;
372 mand_part_len -= (uint16_t)cie_len;
373 }
374 break;
375 case NHRP_PKT_ERROR_INDICATION:
376 /* Contents of NHRP Packet in error */
377 break;
378 default:
379 break;
380 }
381 return;
382
383 invalid:
384 nd_print_invalid(ndo);
385 }
386
387 static u_int
388 nhrp_print_cie(netdissect_options *ndo, const u_char *data, uint16_t mand_part_len,
389 uint16_t afn, uint16_t pro_type)
390 {
391 const struct nhrp_cie *cie;
392 u_int cie_len;
393 uint8_t cli_addr_tl;
394 uint8_t cli_saddr_tl;
395 uint8_t cli_proto_tl;
396
397 cie = (const struct nhrp_cie *)data;
398 cie_len = 0;
399 ND_ICHECKMSG_ZU("remaining mandatory part length",
400 mand_part_len, <, sizeof(*cie));
401
402 ND_PRINT(" (code %d", GET_U_1(cie->code));
403 if (ndo->ndo_vflag)
404 ND_PRINT(", pl %d, mtu %d, htime %d, pref %d",
405 GET_U_1(cie->plen),
406 GET_BE_U_2(cie->mtu),
407 GET_BE_U_2(cie->htime),
408 GET_U_1(cie->pref));
409
410 cli_addr_tl = GET_U_1(cie->cli_addr_tl);
411 cli_saddr_tl = GET_U_1(cie->cli_saddr_tl);
412 cli_proto_tl = GET_U_1(cie->cli_proto_tl);
413
414 /* check 2nd most significant bit */
415 if (cli_addr_tl & 0x40)
416 ND_PRINT(", nbma E.154");
417
418 data += sizeof(*cie);
419 cie_len += sizeof(*cie);
420 mand_part_len -= sizeof(*cie);
421
422 if (cli_addr_tl) {
423 ND_ICHECKMSG_U("remaining mandatory part length",
424 mand_part_len, <, cli_addr_tl);
425 switch (afn) {
426 case AFNUM_IP:
427 ND_PRINT(", nbma %s", NHRP_IPv4_ADDR_STRING(data, cli_addr_tl));
428 break;
429 case AFNUM_IP6:
430 ND_PRINT(", nbma %s", NHRP_IPv6_ADDR_STRING(data, cli_addr_tl));
431 break;
432 case AFNUM_802:
433 ND_PRINT(", nbma %s", NHRP_MAC_ADDR_STRING(data, cli_addr_tl));
434 break;
435 default:
436 ND_PRINT(", unknown-nbma-addr-family-%04x (%s)",
437 afn, GET_LINKADDR_STRING(data, LINKADDR_OTHER, cli_addr_tl));
438 break;
439 }
440 data += cli_addr_tl;
441 cie_len += cli_addr_tl;
442 mand_part_len -= cli_addr_tl;
443 }
444
445 if (cli_saddr_tl) {
446 ND_ICHECKMSG_U("remaining mandatory part length",
447 mand_part_len, <, cli_addr_tl);
448 ND_PRINT(", unknown-nbma-saddr-family");
449 ND_TCHECK_LEN(data, cli_saddr_tl);
450 data += cli_saddr_tl;
451 cie_len += cli_saddr_tl;
452 mand_part_len -= cli_saddr_tl;
453 }
454
455 if (cli_proto_tl) {
456 ND_ICHECKMSG_U("remaining mandatory part length",
457 mand_part_len, <, cli_proto_tl);
458 switch (pro_type) {
459 case ETHERTYPE_IP:
460 ND_PRINT(", proto %s", NHRP_IPv4_ADDR_STRING(data, cli_proto_tl));
461 break;
462 case ETHERTYPE_IPV6:
463 ND_PRINT(", proto %s", NHRP_IPv6_ADDR_STRING(data, cli_proto_tl));
464 break;
465 default:
466 ND_PRINT(", unknown-proto-family-%04x (%s)",
467 pro_type, GET_LINKADDR_STRING(data, LINKADDR_OTHER, cli_proto_tl));
468 break;
469 }
470 cie_len += cli_proto_tl;
471 mand_part_len -= cli_proto_tl;
472 }
473
474 ND_PRINT(")");
475
476 return (cie_len);
477
478 invalid:
479 nd_print_invalid(ndo);
480
481 /*
482 * We get here because this CIE goes past the remaining length,
483 * of the mandatory part. We've reported that error; we now
484 * assign the insufficiently-large remaining piece of the
485 * mandatory part to this CIE, so that this CIE finishes up
486 * the mandatory part, and the loop processing the CIEs
487 * terminates. There cannot be any CIEs after this one.
488 */
489 cie_len += mand_part_len;
490 return (cie_len);
491 }