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"
37 #include "interface.h"
40 #define NHRP_VER_RFC2332 1
42 #define NHRP_PKT_RESOLUTION_REQUEST 1
43 #define NHRP_PKT_RESOLUTION_REPLY 2
44 #define NHRP_PKT_REGISTRATION_REQUEST 3
45 #define NHRP_PKT_REGISTRATION_REPLY 4
46 #define NHRP_PKT_PURGE_REQUEST 5
47 #define NHRP_PKT_PURGE_REPLY 6
48 #define NHRP_PKT_ERROR_INDICATION 7
49 #define NHRP_PKT_TRAFFIC_INDICATION 8 /* draft-detienne-dmvpn-01 */
51 static const struct tok pkt_types
[] = {
52 { NHRP_PKT_RESOLUTION_REQUEST
, "res request" },
53 { NHRP_PKT_RESOLUTION_REPLY
, "res reply" },
54 { NHRP_PKT_REGISTRATION_REQUEST
, "reg request" },
55 { NHRP_PKT_REGISTRATION_REPLY
, "reg reply" },
56 { NHRP_PKT_PURGE_REQUEST
, "purge request" },
57 { NHRP_PKT_PURGE_REPLY
, "purge reply" },
58 { NHRP_PKT_ERROR_INDICATION
, "error indication" },
59 { NHRP_PKT_TRAFFIC_INDICATION
, "traffic indication" },
66 struct nhrp_fixed_header
{
67 nd_uint16_t afn
; /* link layer address */
68 nd_uint16_t pro_type
; /* protocol type (short form) */
69 nd_uint8_t pro_snap
[5]; /* protocol type (long form) */
70 nd_uint8_t hopcnt
; /* hop count */
71 nd_uint16_t pktsz
; /* length of the NHRP packet (octets) */
72 nd_uint16_t chksum
; /* IP checksum over the entier packet */
73 nd_uint16_t extoff
; /* extension offset */
74 nd_uint8_t op_version
; /* version of address mapping and
75 management protocol */
76 nd_uint8_t op_type
; /* NHRP packet type */
77 nd_uint8_t shtl
; /* type and length of src NBMA addr */
78 nd_uint8_t sstl
; /* type and length of src NBMA
83 * Mandatory header part. This is the beginning of the mandatory
84 * header; it's followed by addresses and client information entries.
86 * The mandatory header part formats are similar for
87 * all NHRP packets; the only difference is that NHRP_PKT_ERROR_INDICATION
88 * has a 16-bit error code and a 16-bit error packet offset, and
89 * NHRP_PKT_TRAFFIC_INDICATION has a 16-bit traffic code and a 16-bit unused
90 * field, rather than a 32-bit request ID.
92 struct nhrp_mand_header
{
93 nd_uint8_t spl
; /* src proto len */
94 nd_uint8_t dpl
; /* dst proto len */
95 nd_uint16_t flags
; /* flags */
97 nd_uint32_t id
; /* request id */
98 struct { /* error code */
102 struct { /* error code */
103 nd_uint16_t traffic_code
;
109 static const struct tok err_code_types
[] = {
110 { 1, "unrecognized extension" },
111 { 3, "NHRP loop detected" },
112 { 6, "protocol address unreachable" },
113 { 7, "protocol error" },
114 { 8, "NHRP SDU size exceeded" },
115 { 9, "invalid extension" },
116 { 10, "invalid NHRP resolution reply received" },
117 { 11, "authentication failure" },
118 { 15, "hop count exceeded" },
122 static const struct tok traffic_code_types
[] = {
123 { 0, "NHRP traffic redirect/indirection" },
127 #define NHRP_FIXED_HEADER_LEN 20
130 /* client information entry */
136 nd_uint8_t cli_addr_tl
;
137 nd_uint8_t cli_saddr_tl
;
138 nd_uint8_t cli_proto_tl
;
142 static u_int
nhrp_print_cie(netdissect_options
*ndo
, const u_char
*, uint16_t, uint16_t, uint16_t);
145 * Get string for IPv4 address pointed to by addr if addrlen is 4;
146 * otherwise, get it as a string for the sequence of hex bytes.
149 nhrp_ipv4_addr_string(netdissect_options
*ndo
, const u_char
*addr
, u_int addrlen
)
152 return (GET_IPADDR_STRING(addr
));
154 return (GET_LINKADDR_STRING(addr
, LINKADDR_OTHER
, addrlen
));
156 #define NHRP_IPv4_ADDR_STRING(addr, addrlen) \
157 nhrp_ipv4_addr_string(ndo, (addr), (addrlen))
160 * Get string for IPv6 address pointed to by addr if addrlen is 16;
161 * otherwise, get it as a string for the sequence of hex bytes.
164 nhrp_ipv6_addr_string(netdissect_options
*ndo
, const u_char
*addr
, u_int addrlen
)
167 return (GET_IP6ADDR_STRING(addr
));
169 return (GET_LINKADDR_STRING(addr
, LINKADDR_OTHER
, addrlen
));
171 #define NHRP_IPv6_ADDR_STRING(addr, addrlen) \
172 nhrp_ipv6_addr_string(ndo, (addr), (addrlen))
175 * Get string for MAC address pointed to by addr if addrlen is 6;
176 * otherwise, get it as a string for the sequence of hex bytes.
179 nhrp_mac_addr_string(netdissect_options
*ndo
, const u_char
*addr
, u_int addrlen
)
182 return (GET_ETHERADDR_STRING(addr
));
184 return (GET_LINKADDR_STRING(addr
, LINKADDR_OTHER
, addrlen
));
186 #define NHRP_MAC_ADDR_STRING(addr, addrlen) \
187 nhrp_mac_addr_string(ndo, (addr), (addrlen))
190 nhrp_print(netdissect_options
*ndo
, const u_char
*bp
, u_int length
)
192 const struct nhrp_fixed_header
*fixed_hdr
;
200 const struct nhrp_mand_header
*mand_hdr
;
201 uint16_t mand_part_len
;
204 ndo
->ndo_protocol
= "nhrp";
205 nd_print_protocol_caps(ndo
);
208 fixed_hdr
= (const struct nhrp_fixed_header
*)bp
;
210 ND_ICHECK_ZU(length
, <, sizeof(*fixed_hdr
));
211 op_version
= GET_U_1(fixed_hdr
->op_version
);
212 if (op_version
!= NHRP_VER_RFC2332
) {
213 ND_PRINT("unknown-version-%02x", op_version
);
217 afn
= GET_BE_U_2(fixed_hdr
->afn
);
218 pro_type
= GET_BE_U_2(fixed_hdr
->pro_type
);
220 pktsz
= GET_BE_U_2(fixed_hdr
->pktsz
);
221 ND_ICHECKMSG_ZU("pktsz", pktsz
, <, sizeof(*fixed_hdr
));
222 extoff
= GET_BE_U_2(fixed_hdr
->extoff
);
224 op_type
= GET_U_1(fixed_hdr
->op_type
);
225 ND_PRINT("%s", tok2str(pkt_types
, "unknown-op-type-%04x", op_type
));
228 * Mandatory part length.
229 * We already know that pktsz is large enough for the fixed
230 * header and the fixed part of the mandatory header.
233 mand_part_len
= pktsz
- sizeof(*fixed_hdr
);
235 ND_ICHECKMSG_U("extoff", extoff
, >, pktsz
);
236 ND_ICHECKMSG_ZU("extoff", extoff
, <, sizeof(*fixed_hdr
));
237 mand_part_len
= extoff
- sizeof(*fixed_hdr
);
239 length
-= sizeof(*fixed_hdr
);
240 if (mand_part_len
> length
)
241 mand_part_len
= (uint16_t)length
;
243 /* We start looking at the mandatory header here. */
244 ND_TCHECK_LEN(bp
, sizeof(*fixed_hdr
));
245 bp
+= sizeof(*fixed_hdr
);
246 length
-= sizeof(*fixed_hdr
);
247 ND_ICHECK_ZU(mand_part_len
, <, sizeof(*mand_hdr
));
248 ND_TCHECK_LEN(bp
, sizeof(*mand_hdr
));
249 mand_hdr
= (const struct nhrp_mand_header
*)bp
;
252 case NHRP_PKT_RESOLUTION_REQUEST
:
253 case NHRP_PKT_RESOLUTION_REPLY
:
254 case NHRP_PKT_REGISTRATION_REQUEST
:
255 case NHRP_PKT_REGISTRATION_REPLY
:
256 case NHRP_PKT_PURGE_REQUEST
:
257 case NHRP_PKT_PURGE_REPLY
:
258 ND_PRINT(", id %u", GET_BE_U_4(mand_hdr
->u
.id
));
260 case NHRP_PKT_ERROR_INDICATION
:
261 ND_PRINT(", error <%s>", tok2str(err_code_types
, "unknown-err-code-%u", GET_BE_U_2(mand_hdr
->u
.err
.code
)));
263 case NHRP_PKT_TRAFFIC_INDICATION
:
264 ND_PRINT(", code <%s>", tok2str(traffic_code_types
, "unknown-traffic-code-%u", GET_BE_U_2(mand_hdr
->u
.tind
.traffic_code
)));
268 shtl
= GET_U_1(fixed_hdr
->shtl
);
269 sstl
= GET_U_1(fixed_hdr
->sstl
);
271 if (ndo
->ndo_vflag
) {
272 ND_PRINT(", hopcnt %u", GET_U_1(fixed_hdr
->hopcnt
));
274 /* most significant bit must be 0 */
276 ND_PRINT(" (shtl bit 7 set)");
278 /* check 2nd most significant bit */
280 ND_PRINT(" (nbma E.154)");
283 /* Mandatory header part */
284 spl
= GET_U_1(mand_hdr
->spl
);
285 dpl
= GET_U_1(mand_hdr
->dpl
);
286 bp
+= sizeof(*mand_hdr
); /* Skip to the addresses */
287 mand_part_len
-= sizeof(*mand_hdr
);
289 /* Source NBMA Address, if any. */
291 ND_ICHECK_U(mand_part_len
, <, shtl
);
294 ND_PRINT(", src nbma %s", NHRP_IPv4_ADDR_STRING(bp
, shtl
));
297 ND_PRINT(", src nbma %s", NHRP_IPv6_ADDR_STRING(bp
, shtl
));
300 ND_PRINT(", src nbma %s", NHRP_MAC_ADDR_STRING(bp
, shtl
));
303 ND_PRINT(", unknown-nbma-addr-family-%04x (%s)",
304 afn
, GET_LINKADDR_STRING(bp
, LINKADDR_OTHER
, shtl
));
308 mand_part_len
-= shtl
;
311 /* Skip the Source NBMA SubAddress, if any */
313 ND_ICHECK_U(mand_part_len
, <, sstl
);
314 ND_TCHECK_LEN(bp
, sstl
);
316 mand_part_len
-= sstl
;
320 /* Source Protocol Address */
322 ND_ICHECK_U(mand_part_len
, <, spl
);
325 ND_PRINT("%s ", NHRP_IPv4_ADDR_STRING(bp
, spl
));
328 ND_PRINT("%s ", NHRP_IPv6_ADDR_STRING(bp
, spl
));
331 ND_PRINT("proto type %04x ", pro_type
);
332 ND_PRINT("%s ", GET_LINKADDR_STRING(bp
, LINKADDR_OTHER
, spl
));
336 mand_part_len
-= spl
;
339 /* Destination Protocol Address */
341 ND_ICHECK_U(mand_part_len
, <, dpl
);
344 ND_PRINT(" %s", NHRP_IPv4_ADDR_STRING(bp
, dpl
));
347 ND_PRINT(" %s", NHRP_IPv6_ADDR_STRING(bp
, dpl
));
350 ND_PRINT(" %s", GET_LINKADDR_STRING(bp
, LINKADDR_OTHER
, dpl
));
354 mand_part_len
-= dpl
;
358 case NHRP_PKT_RESOLUTION_REQUEST
:
359 case NHRP_PKT_RESOLUTION_REPLY
:
360 case NHRP_PKT_REGISTRATION_REQUEST
:
361 case NHRP_PKT_REGISTRATION_REPLY
:
362 case NHRP_PKT_PURGE_REQUEST
:
363 case NHRP_PKT_PURGE_REPLY
:
364 /* Client Information Entries */
365 while (mand_part_len
!= 0) {
369 * cie_len is guaranteed by nhrp_print_cie()
370 * to be <= mand_part_len.
372 cie_len
= nhrp_print_cie(ndo
, bp
, mand_part_len
,
375 mand_part_len
-= (uint16_t)cie_len
;
378 case NHRP_PKT_ERROR_INDICATION
:
379 /* Contents of NHRP Packet in error */
387 nd_print_invalid(ndo
);
391 nhrp_print_cie(netdissect_options
*ndo
, const u_char
*data
, uint16_t mand_part_len
,
392 uint16_t afn
, uint16_t pro_type
)
394 const struct nhrp_cie
*cie
;
397 uint8_t cli_saddr_tl
;
398 uint8_t cli_proto_tl
;
400 cie
= (const struct nhrp_cie
*)data
;
402 ND_ICHECKMSG_ZU("remaining mandatory part length",
403 mand_part_len
, <, sizeof(*cie
));
405 ND_PRINT(" (code %d", GET_U_1(cie
->code
));
407 ND_PRINT(", pl %d, mtu %d, htime %d, pref %d",
409 GET_BE_U_2(cie
->mtu
),
410 GET_BE_U_2(cie
->htime
),
413 cli_addr_tl
= GET_U_1(cie
->cli_addr_tl
);
414 cli_saddr_tl
= GET_U_1(cie
->cli_saddr_tl
);
415 cli_proto_tl
= GET_U_1(cie
->cli_proto_tl
);
417 /* check 2nd most significant bit */
418 if (cli_addr_tl
& 0x40)
419 ND_PRINT(", nbma E.154");
421 data
+= sizeof(*cie
);
422 cie_len
+= sizeof(*cie
);
423 mand_part_len
-= sizeof(*cie
);
426 ND_ICHECKMSG_U("remaining mandatory part length",
427 mand_part_len
, <, cli_addr_tl
);
430 ND_PRINT(", nbma %s", NHRP_IPv4_ADDR_STRING(data
, cli_addr_tl
));
433 ND_PRINT(", nbma %s", NHRP_IPv6_ADDR_STRING(data
, cli_addr_tl
));
436 ND_PRINT(", nbma %s", NHRP_MAC_ADDR_STRING(data
, cli_addr_tl
));
439 ND_PRINT(", unknown-nbma-addr-family-%04x (%s)",
440 afn
, GET_LINKADDR_STRING(data
, LINKADDR_OTHER
, cli_addr_tl
));
444 cie_len
+= cli_addr_tl
;
445 mand_part_len
-= cli_addr_tl
;
449 ND_ICHECKMSG_U("remaining mandatory part length",
450 mand_part_len
, <, cli_addr_tl
);
451 ND_PRINT(", unknown-nbma-saddr-family");
452 ND_TCHECK_LEN(data
, cli_saddr_tl
);
453 data
+= cli_saddr_tl
;
454 cie_len
+= cli_saddr_tl
;
455 mand_part_len
-= cli_saddr_tl
;
459 ND_ICHECKMSG_U("remaining mandatory part length",
460 mand_part_len
, <, cli_proto_tl
);
463 ND_PRINT(", proto %s", NHRP_IPv4_ADDR_STRING(data
, cli_proto_tl
));
466 ND_PRINT(", proto %s", NHRP_IPv6_ADDR_STRING(data
, cli_proto_tl
));
469 ND_PRINT(", unknown-proto-family-%04x (%s)",
470 pro_type
, GET_LINKADDR_STRING(data
, LINKADDR_OTHER
, cli_proto_tl
));
473 cie_len
+= cli_proto_tl
;
474 mand_part_len
-= cli_proto_tl
;
482 nd_print_invalid(ndo
);
485 * We get here because this CIE goes past the remaining length,
486 * of the mandatory part. We've reported that error; we now
487 * assign the insufficiently-large remaining piece of the
488 * mandatory part to this CIE, so that this CIE finishes up
489 * the mandatory part, and the loop processing the CIEs
490 * terminates. There cannot be any CIEs after this one.
492 cie_len
+= mand_part_len
;