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)
28 #include "netdissect-stdinc.h"
30 #define ND_LONGJMP_FROM_TCHECK
31 #include "netdissect.h"
32 #include "addrtoname.h"
34 #include "ethertype.h"
37 #define NHRP_VER_RFC2332 1
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 */
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" },
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
80 * Mandatory header part. This is the beginning of the mandatory
81 * header; it's followed by addresses and client information entries.
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.
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 */
94 nd_uint32_t id
; /* request id */
95 struct { /* error code */
99 struct { /* error code */
100 nd_uint16_t traffic_code
;
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" },
119 static const struct tok traffic_code_types
[] = {
120 { 0, "NHRP traffic redirect/indirection" },
124 #define NHRP_FIXED_HEADER_LEN 20
127 /* client information entry */
133 nd_uint8_t cli_addr_tl
;
134 nd_uint8_t cli_saddr_tl
;
135 nd_uint8_t cli_proto_tl
;
139 static u_int
nhrp_print_cie(netdissect_options
*ndo
, const u_char
*, uint16_t, uint16_t, uint16_t);
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.
146 nhrp_ipv4_addr_string(netdissect_options
*ndo
, const u_char
*addr
, u_int addrlen
)
149 return (GET_IPADDR_STRING(addr
));
151 return (GET_LINKADDR_STRING(addr
, LINKADDR_OTHER
, addrlen
));
153 #define NHRP_IPv4_ADDR_STRING(addr, addrlen) \
154 nhrp_ipv4_addr_string(ndo, (addr), (addrlen))
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.
161 nhrp_ipv6_addr_string(netdissect_options
*ndo
, const u_char
*addr
, u_int addrlen
)
164 return (GET_IP6ADDR_STRING(addr
));
166 return (GET_LINKADDR_STRING(addr
, LINKADDR_OTHER
, addrlen
));
168 #define NHRP_IPv6_ADDR_STRING(addr, addrlen) \
169 nhrp_ipv6_addr_string(ndo, (addr), (addrlen))
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.
176 nhrp_mac_addr_string(netdissect_options
*ndo
, const u_char
*addr
, u_int addrlen
)
179 return (GET_MAC48_STRING(addr
));
181 return (GET_LINKADDR_STRING(addr
, LINKADDR_OTHER
, addrlen
));
183 #define NHRP_MAC_ADDR_STRING(addr, addrlen) \
184 nhrp_mac_addr_string(ndo, (addr), (addrlen))
187 nhrp_print(netdissect_options
*ndo
, const u_char
*bp
, u_int length
)
189 const struct nhrp_fixed_header
*fixed_hdr
;
197 const struct nhrp_mand_header
*mand_hdr
;
198 uint16_t mand_part_len
;
201 ndo
->ndo_protocol
= "nhrp";
202 nd_print_protocol_caps(ndo
);
205 fixed_hdr
= (const struct nhrp_fixed_header
*)bp
;
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
);
214 afn
= GET_BE_U_2(fixed_hdr
->afn
);
215 pro_type
= GET_BE_U_2(fixed_hdr
->pro_type
);
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
);
221 op_type
= GET_U_1(fixed_hdr
->op_type
);
222 ND_PRINT("%s", tok2str(pkt_types
, "unknown-op-type-%04x", op_type
));
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.
230 mand_part_len
= pktsz
- sizeof(*fixed_hdr
);
232 ND_ICHECKMSG_U("extoff", extoff
, >, pktsz
);
233 ND_ICHECKMSG_ZU("extoff", extoff
, <, sizeof(*fixed_hdr
));
234 mand_part_len
= extoff
- sizeof(*fixed_hdr
);
236 length
-= sizeof(*fixed_hdr
);
237 if (mand_part_len
> length
)
238 mand_part_len
= (uint16_t)length
;
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
;
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
));
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
)));
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
)));
265 shtl
= GET_U_1(fixed_hdr
->shtl
);
266 sstl
= GET_U_1(fixed_hdr
->sstl
);
268 if (ndo
->ndo_vflag
) {
269 ND_PRINT(", hopcnt %u", GET_U_1(fixed_hdr
->hopcnt
));
271 /* most significant bit must be 0 */
273 ND_PRINT(" (shtl bit 7 set)");
275 /* check 2nd most significant bit */
277 ND_PRINT(" (nbma E.154)");
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
);
286 /* Source NBMA Address, if any. */
288 ND_ICHECK_U(mand_part_len
, <, shtl
);
291 ND_PRINT(", src nbma %s", NHRP_IPv4_ADDR_STRING(bp
, shtl
));
294 ND_PRINT(", src nbma %s", NHRP_IPv6_ADDR_STRING(bp
, shtl
));
297 ND_PRINT(", src nbma %s", NHRP_MAC_ADDR_STRING(bp
, shtl
));
300 ND_PRINT(", unknown-nbma-addr-family-%04x (%s)",
301 afn
, GET_LINKADDR_STRING(bp
, LINKADDR_OTHER
, shtl
));
305 mand_part_len
-= shtl
;
308 /* Skip the Source NBMA SubAddress, if any */
310 ND_ICHECK_U(mand_part_len
, <, sstl
);
311 ND_TCHECK_LEN(bp
, sstl
);
313 mand_part_len
-= sstl
;
317 /* Source Protocol Address */
319 ND_ICHECK_U(mand_part_len
, <, spl
);
322 ND_PRINT("%s ", NHRP_IPv4_ADDR_STRING(bp
, spl
));
325 ND_PRINT("%s ", NHRP_IPv6_ADDR_STRING(bp
, spl
));
328 ND_PRINT("proto type %04x ", pro_type
);
329 ND_PRINT("%s ", GET_LINKADDR_STRING(bp
, LINKADDR_OTHER
, spl
));
333 mand_part_len
-= spl
;
336 /* Destination Protocol Address */
338 ND_ICHECK_U(mand_part_len
, <, dpl
);
341 ND_PRINT(" %s", NHRP_IPv4_ADDR_STRING(bp
, dpl
));
344 ND_PRINT(" %s", NHRP_IPv6_ADDR_STRING(bp
, dpl
));
347 ND_PRINT(" %s", GET_LINKADDR_STRING(bp
, LINKADDR_OTHER
, dpl
));
351 mand_part_len
-= dpl
;
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) {
366 * cie_len is guaranteed by nhrp_print_cie()
367 * to be <= mand_part_len.
369 cie_len
= nhrp_print_cie(ndo
, bp
, mand_part_len
,
372 mand_part_len
-= (uint16_t)cie_len
;
375 case NHRP_PKT_ERROR_INDICATION
:
376 /* Contents of NHRP Packet in error */
384 nd_print_invalid(ndo
);
388 nhrp_print_cie(netdissect_options
*ndo
, const u_char
*data
, uint16_t mand_part_len
,
389 uint16_t afn
, uint16_t pro_type
)
391 const struct nhrp_cie
*cie
;
394 uint8_t cli_saddr_tl
;
395 uint8_t cli_proto_tl
;
397 cie
= (const struct nhrp_cie
*)data
;
399 ND_ICHECKMSG_ZU("remaining mandatory part length",
400 mand_part_len
, <, sizeof(*cie
));
402 ND_PRINT(" (code %d", GET_U_1(cie
->code
));
404 ND_PRINT(", pl %d, mtu %d, htime %d, pref %d",
406 GET_BE_U_2(cie
->mtu
),
407 GET_BE_U_2(cie
->htime
),
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
);
414 /* check 2nd most significant bit */
415 if (cli_addr_tl
& 0x40)
416 ND_PRINT(", nbma E.154");
418 data
+= sizeof(*cie
);
419 cie_len
+= sizeof(*cie
);
420 mand_part_len
-= sizeof(*cie
);
423 ND_ICHECKMSG_U("remaining mandatory part length",
424 mand_part_len
, <, cli_addr_tl
);
427 ND_PRINT(", nbma %s", NHRP_IPv4_ADDR_STRING(data
, cli_addr_tl
));
430 ND_PRINT(", nbma %s", NHRP_IPv6_ADDR_STRING(data
, cli_addr_tl
));
433 ND_PRINT(", nbma %s", NHRP_MAC_ADDR_STRING(data
, cli_addr_tl
));
436 ND_PRINT(", unknown-nbma-addr-family-%04x (%s)",
437 afn
, GET_LINKADDR_STRING(data
, LINKADDR_OTHER
, cli_addr_tl
));
441 cie_len
+= cli_addr_tl
;
442 mand_part_len
-= cli_addr_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
;
456 ND_ICHECKMSG_U("remaining mandatory part length",
457 mand_part_len
, <, cli_proto_tl
);
460 ND_PRINT(", proto %s", NHRP_IPv4_ADDR_STRING(data
, cli_proto_tl
));
463 ND_PRINT(", proto %s", NHRP_IPv6_ADDR_STRING(data
, cli_proto_tl
));
466 ND_PRINT(", unknown-proto-family-%04x (%s)",
467 pro_type
, GET_LINKADDR_STRING(data
, LINKADDR_OTHER
, cli_proto_tl
));
470 cie_len
+= cli_proto_tl
;
471 mand_part_len
-= cli_proto_tl
;
479 nd_print_invalid(ndo
);
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.
489 cie_len
+= mand_part_len
;