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