1 /* $OpenBSD: print-nhrp.c,v 1.2 2022/12/28 21:30:19 jmc Exp $ */
4 * Copyright (c) 2020 Remi Locherer <remi@openbsd.org>
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.
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.
19 /* \summary: NHRP printer */
22 * RFC 2332 NBMA Next Hop Resolution Protocol (NHRP)
23 * I-D draft-detienne-dmvpn-01 (expired)
30 #include "netdissect-stdinc.h"
32 #define ND_LONGJMP_FROM_TCHECK
33 #include "netdissect.h"
34 #include "addrtoname.h"
36 #include "ethertype.h"
39 #define NHRP_VER_RFC2332 1
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 */
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" },
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
82 * Mandatory header part. This is the beginning of the mandatory
83 * header; it's followed by addresses and client information entries.
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.
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 */
96 nd_uint32_t id
; /* request id */
97 struct { /* error code */
101 struct { /* error code */
102 nd_uint16_t traffic_code
;
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" },
121 static const struct tok traffic_code_types
[] = {
122 { 0, "NHRP traffic redirect/indirection" },
126 #define NHRP_FIXED_HEADER_LEN 20
129 /* client information entry */
135 nd_uint8_t cli_addr_tl
;
136 nd_uint8_t cli_saddr_tl
;
137 nd_uint8_t cli_proto_tl
;
141 static u_int
nhrp_print_cie(netdissect_options
*ndo
, const u_char
*, uint16_t, uint16_t, uint16_t);
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.
148 nhrp_ipv4_addr_string(netdissect_options
*ndo
, const u_char
*addr
, u_int addrlen
)
151 return (GET_IPADDR_STRING(addr
));
153 return (GET_LINKADDR_STRING(addr
, LINKADDR_OTHER
, addrlen
));
155 #define NHRP_IPv4_ADDR_STRING(addr, addrlen) \
156 nhrp_ipv4_addr_string(ndo, (addr), (addrlen))
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.
163 nhrp_ipv6_addr_string(netdissect_options
*ndo
, const u_char
*addr
, u_int addrlen
)
166 return (GET_IP6ADDR_STRING(addr
));
168 return (GET_LINKADDR_STRING(addr
, LINKADDR_OTHER
, addrlen
));
170 #define NHRP_IPv6_ADDR_STRING(addr, addrlen) \
171 nhrp_ipv6_addr_string(ndo, (addr), (addrlen))
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.
178 nhrp_mac_addr_string(netdissect_options
*ndo
, const u_char
*addr
, u_int addrlen
)
181 return (GET_MAC48_STRING(addr
));
183 return (GET_LINKADDR_STRING(addr
, LINKADDR_OTHER
, addrlen
));
185 #define NHRP_MAC_ADDR_STRING(addr, addrlen) \
186 nhrp_mac_addr_string(ndo, (addr), (addrlen))
189 nhrp_print(netdissect_options
*ndo
, const u_char
*bp
, u_int length
)
191 const struct nhrp_fixed_header
*fixed_hdr
;
199 const struct nhrp_mand_header
*mand_hdr
;
200 uint16_t mand_part_len
;
203 ndo
->ndo_protocol
= "nhrp";
204 nd_print_protocol_caps(ndo
);
207 fixed_hdr
= (const struct nhrp_fixed_header
*)bp
;
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
);
216 afn
= GET_BE_U_2(fixed_hdr
->afn
);
217 pro_type
= GET_BE_U_2(fixed_hdr
->pro_type
);
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
);
223 op_type
= GET_U_1(fixed_hdr
->op_type
);
224 ND_PRINT("%s", tok2str(pkt_types
, "unknown-op-type-%04x", op_type
));
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.
232 mand_part_len
= pktsz
- sizeof(*fixed_hdr
);
234 ND_ICHECKMSG_U("extoff", extoff
, >, pktsz
);
235 ND_ICHECKMSG_ZU("extoff", extoff
, <, sizeof(*fixed_hdr
));
236 mand_part_len
= extoff
- sizeof(*fixed_hdr
);
238 length
-= sizeof(*fixed_hdr
);
239 if (mand_part_len
> length
)
240 mand_part_len
= (uint16_t)length
;
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
;
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
));
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
)));
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
)));
267 shtl
= GET_U_1(fixed_hdr
->shtl
);
268 sstl
= GET_U_1(fixed_hdr
->sstl
);
270 if (ndo
->ndo_vflag
) {
271 ND_PRINT(", hopcnt %u", GET_U_1(fixed_hdr
->hopcnt
));
273 /* most significant bit must be 0 */
275 ND_PRINT(" (shtl bit 7 set)");
277 /* check 2nd most significant bit */
279 ND_PRINT(" (nbma E.154)");
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
);
288 /* Source NBMA Address, if any. */
290 ND_ICHECK_U(mand_part_len
, <, shtl
);
293 ND_PRINT(", src nbma %s", NHRP_IPv4_ADDR_STRING(bp
, shtl
));
296 ND_PRINT(", src nbma %s", NHRP_IPv6_ADDR_STRING(bp
, shtl
));
299 ND_PRINT(", src nbma %s", NHRP_MAC_ADDR_STRING(bp
, shtl
));
302 ND_PRINT(", unknown-nbma-addr-family-%04x (%s)",
303 afn
, GET_LINKADDR_STRING(bp
, LINKADDR_OTHER
, shtl
));
307 mand_part_len
-= shtl
;
310 /* Skip the Source NBMA SubAddress, if any */
312 ND_ICHECK_U(mand_part_len
, <, sstl
);
313 ND_TCHECK_LEN(bp
, sstl
);
315 mand_part_len
-= sstl
;
319 /* Source Protocol Address */
321 ND_ICHECK_U(mand_part_len
, <, spl
);
324 ND_PRINT("%s ", NHRP_IPv4_ADDR_STRING(bp
, spl
));
327 ND_PRINT("%s ", NHRP_IPv6_ADDR_STRING(bp
, spl
));
330 ND_PRINT("proto type %04x ", pro_type
);
331 ND_PRINT("%s ", GET_LINKADDR_STRING(bp
, LINKADDR_OTHER
, spl
));
335 mand_part_len
-= spl
;
338 /* Destination Protocol Address */
340 ND_ICHECK_U(mand_part_len
, <, dpl
);
343 ND_PRINT(" %s", NHRP_IPv4_ADDR_STRING(bp
, dpl
));
346 ND_PRINT(" %s", NHRP_IPv6_ADDR_STRING(bp
, dpl
));
349 ND_PRINT(" %s", GET_LINKADDR_STRING(bp
, LINKADDR_OTHER
, dpl
));
353 mand_part_len
-= dpl
;
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) {
368 * cie_len is guaranteed by nhrp_print_cie()
369 * to be <= mand_part_len.
371 cie_len
= nhrp_print_cie(ndo
, bp
, mand_part_len
,
374 mand_part_len
-= (uint16_t)cie_len
;
377 case NHRP_PKT_ERROR_INDICATION
:
378 /* Contents of NHRP Packet in error */
386 nd_print_invalid(ndo
);
390 nhrp_print_cie(netdissect_options
*ndo
, const u_char
*data
, uint16_t mand_part_len
,
391 uint16_t afn
, uint16_t pro_type
)
393 const struct nhrp_cie
*cie
;
396 uint8_t cli_saddr_tl
;
397 uint8_t cli_proto_tl
;
399 cie
= (const struct nhrp_cie
*)data
;
401 ND_ICHECKMSG_ZU("remaining mandatory part length",
402 mand_part_len
, <, sizeof(*cie
));
404 ND_PRINT(" (code %d", GET_U_1(cie
->code
));
406 ND_PRINT(", pl %d, mtu %d, htime %d, pref %d",
408 GET_BE_U_2(cie
->mtu
),
409 GET_BE_U_2(cie
->htime
),
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
);
416 /* check 2nd most significant bit */
417 if (cli_addr_tl
& 0x40)
418 ND_PRINT(", nbma E.154");
420 data
+= sizeof(*cie
);
421 cie_len
+= sizeof(*cie
);
422 mand_part_len
-= sizeof(*cie
);
425 ND_ICHECKMSG_U("remaining mandatory part length",
426 mand_part_len
, <, cli_addr_tl
);
429 ND_PRINT(", nbma %s", NHRP_IPv4_ADDR_STRING(data
, cli_addr_tl
));
432 ND_PRINT(", nbma %s", NHRP_IPv6_ADDR_STRING(data
, cli_addr_tl
));
435 ND_PRINT(", nbma %s", NHRP_MAC_ADDR_STRING(data
, cli_addr_tl
));
438 ND_PRINT(", unknown-nbma-addr-family-%04x (%s)",
439 afn
, GET_LINKADDR_STRING(data
, LINKADDR_OTHER
, cli_addr_tl
));
443 cie_len
+= cli_addr_tl
;
444 mand_part_len
-= cli_addr_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
;
458 ND_ICHECKMSG_U("remaining mandatory part length",
459 mand_part_len
, <, cli_proto_tl
);
462 ND_PRINT(", proto %s", NHRP_IPv4_ADDR_STRING(data
, cli_proto_tl
));
465 ND_PRINT(", proto %s", NHRP_IPv6_ADDR_STRING(data
, cli_proto_tl
));
468 ND_PRINT(", unknown-proto-family-%04x (%s)",
469 pro_type
, GET_LINKADDR_STRING(data
, LINKADDR_OTHER
, cli_proto_tl
));
472 cie_len
+= cli_proto_tl
;
473 mand_part_len
-= cli_proto_tl
;
481 nd_print_invalid(ndo
);
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.
491 cie_len
+= mand_part_len
;