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)
29 #include "netdissect-stdinc.h"
31 #define ND_LONGJMP_FROM_TCHECK
32 #include "netdissect.h"
33 #include "addrtoname.h"
35 #include "ethertype.h"
36 #include "interface.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
49 static const struct tok pkt_types
[] = {
50 { NHRP_PKT_RESOLUTION_REQUEST
, "res request" },
51 { NHRP_PKT_RESOLUTION_REPLY
, "res reply" },
52 { NHRP_PKT_REGISTRATION_REQUEST
, "reg request" },
53 { NHRP_PKT_REGISTRATION_REPLY
, "reg reply" },
54 { NHRP_PKT_PURGE_REQUEST
, "purge request" },
55 { NHRP_PKT_PURGE_REPLY
, "purge reply" },
56 { NHRP_PKT_ERROR_INDICATION
, "error 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 rather
86 * than a 32-bit request ID.
88 struct nhrp_mand_header
{
89 nd_uint8_t spl
; /* src proto len */
90 nd_uint8_t dpl
; /* dst proto len */
91 nd_uint16_t flags
; /* flags */
93 nd_uint32_t id
; /* request id */
94 struct { /* error code */
101 #define NHRP_FIXED_HEADER_LEN 20
104 /* client information entry */
110 nd_uint8_t cli_addr_tl
;
111 nd_uint8_t cli_saddr_tl
;
112 nd_uint8_t cli_proto_tl
;
116 static u_int
nhrp_print_cie(netdissect_options
*ndo
, const u_char
*, uint16_t, uint16_t, uint16_t);
119 * Get string for IPv4 address pointed to by addr if addrlen is 4;
120 * otherwise, get it as a string for the sequence of hex bytes.
123 nhrp_ipv4_addr_string(netdissect_options
*ndo
, const u_char
*addr
, u_int addrlen
)
126 return (GET_IPADDR_STRING(addr
));
128 return (GET_LINKADDR_STRING(addr
, LINKADDR_OTHER
, addrlen
));
130 #define NHRP_IPv4_ADDR_STRING(addr, addrlen) \
131 nhrp_ipv4_addr_string(ndo, (addr), (addrlen))
134 * Get string for IPv6 address pointed to by addr if addrlen is 16;
135 * otherwise, get it as a string for the sequence of hex bytes.
138 nhrp_ipv6_addr_string(netdissect_options
*ndo
, const u_char
*addr
, u_int addrlen
)
141 return (GET_IP6ADDR_STRING(addr
));
143 return (GET_LINKADDR_STRING(addr
, LINKADDR_OTHER
, addrlen
));
145 #define NHRP_IPv6_ADDR_STRING(addr, addrlen) \
146 nhrp_ipv6_addr_string(ndo, (addr), (addrlen))
149 * Get string for MAC address pointed to by addr if addrlen is 6;
150 * otherwise, get it as a string for the sequence of hex bytes.
153 nhrp_mac_addr_string(netdissect_options
*ndo
, const u_char
*addr
, u_int addrlen
)
156 return (GET_ETHERADDR_STRING(addr
));
158 return (GET_LINKADDR_STRING(addr
, LINKADDR_OTHER
, addrlen
));
160 #define NHRP_MAC_ADDR_STRING(addr, addrlen) \
161 nhrp_mac_addr_string(ndo, (addr), (addrlen))
164 nhrp_print(netdissect_options
*ndo
, const u_char
*bp
, u_int length
)
166 const struct nhrp_fixed_header
*fixed_hdr
;
174 const struct nhrp_mand_header
*mand_hdr
;
175 uint16_t mand_part_len
;
178 ndo
->ndo_protocol
= "nhrp";
179 nd_print_protocol_caps(ndo
);
182 fixed_hdr
= (const struct nhrp_fixed_header
*)bp
;
184 ND_ICHECK_ZU(length
, <, sizeof(*fixed_hdr
));
185 op_version
= GET_U_1(fixed_hdr
->op_version
);
186 if (op_version
!= NHRP_VER_RFC2332
) {
187 ND_PRINT("unknown-version-%02x", op_version
);
191 afn
= GET_BE_U_2(fixed_hdr
->afn
);
192 pro_type
= GET_BE_U_2(fixed_hdr
->pro_type
);
194 pktsz
= GET_BE_U_2(fixed_hdr
->pktsz
);
195 ND_ICHECKMSG_ZU("pktsz", pktsz
, <, sizeof(*fixed_hdr
));
196 extoff
= GET_BE_U_2(fixed_hdr
->extoff
);
198 op_type
= GET_U_1(fixed_hdr
->op_type
);
199 ND_PRINT("%s", tok2str(pkt_types
, "unknown-op-type-%04x", op_type
));
202 * Mandatory part length.
203 * We already know that pktsz is large enough for the fixed
204 * header and the fixed part of the mandatory heaer.
207 mand_part_len
= pktsz
- sizeof(*fixed_hdr
);
209 ND_ICHECKMSG_U("extoff", extoff
, >, pktsz
);
210 ND_ICHECKMSG_ZU("extoff", extoff
, <, sizeof(*fixed_hdr
));
211 mand_part_len
= extoff
- sizeof(*fixed_hdr
);
213 length
-= sizeof(*fixed_hdr
);
214 if (mand_part_len
> length
)
215 mand_part_len
= length
;
217 /* We start looking at the mandatory header here. */
218 ND_TCHECK_LEN(bp
, sizeof(*fixed_hdr
));
219 bp
+= sizeof(*fixed_hdr
);
220 length
-= sizeof(*fixed_hdr
);
221 ND_ICHECK_ZU(mand_part_len
, <, sizeof(*mand_hdr
));
222 ND_TCHECK_LEN(bp
, sizeof(*mand_hdr
));
223 mand_hdr
= (const struct nhrp_mand_header
*)bp
;
225 // nhrpext = p + extoff;
226 // nhrpend = p + pktsz;
229 case NHRP_PKT_RESOLUTION_REQUEST
:
230 case NHRP_PKT_RESOLUTION_REPLY
:
231 case NHRP_PKT_REGISTRATION_REQUEST
:
232 case NHRP_PKT_REGISTRATION_REPLY
:
233 case NHRP_PKT_PURGE_REQUEST
:
234 case NHRP_PKT_PURGE_REPLY
:
235 ND_PRINT(", id %u", GET_BE_U_4(mand_hdr
->u
.id
));
237 case NHRP_PKT_ERROR_INDICATION
:
238 ND_PRINT(", error %u", GET_BE_U_2(mand_hdr
->u
.err
.code
));
242 shtl
= GET_U_1(fixed_hdr
->shtl
);
243 sstl
= GET_U_1(fixed_hdr
->sstl
);
245 if (ndo
->ndo_vflag
) {
246 ND_PRINT(", hopcnt %u", GET_U_1(fixed_hdr
->hopcnt
));
248 /* most significant bit must be 0 */
250 ND_PRINT(" (shtl bit 7 set)");
252 /* check 2nd most significant bit */
254 ND_PRINT(" (nbma E.154)");
257 /* Mandatory header part */
258 spl
= GET_U_1(mand_hdr
->spl
);
259 dpl
= GET_U_1(mand_hdr
->dpl
);
260 bp
+= sizeof(*mand_hdr
); /* Skip to the addresses */
261 mand_part_len
-= sizeof(*mand_hdr
);
263 /* Source NBMA Address, if any. */
265 ND_ICHECK_U(mand_part_len
, <, shtl
);
268 ND_PRINT(", src nbma %s", NHRP_IPv4_ADDR_STRING(bp
, shtl
));
271 ND_PRINT(", src nbma %s", NHRP_IPv6_ADDR_STRING(bp
, shtl
));
274 ND_PRINT(", src nbma %s", NHRP_MAC_ADDR_STRING(bp
, shtl
));
277 ND_PRINT(", unknown-nbma-addr-family-%04x (%s)",
278 afn
, GET_LINKADDR_STRING(bp
, LINKADDR_OTHER
, shtl
));
282 mand_part_len
-= shtl
;
285 /* Skip the Source NBMA SubAddress, if any */
287 ND_ICHECK_U(mand_part_len
, <, sstl
);
288 ND_TCHECK_LEN(bp
, sstl
);
290 mand_part_len
-= sstl
;
294 /* Source Protocol Address */
296 ND_ICHECK_U(mand_part_len
, <, spl
);
299 ND_PRINT("%s ", NHRP_IPv4_ADDR_STRING(bp
, spl
));
302 ND_PRINT("%s ", NHRP_IPv6_ADDR_STRING(bp
, spl
));
305 ND_PRINT("proto type %04x ", pro_type
);
306 ND_PRINT("%s ", GET_LINKADDR_STRING(bp
, LINKADDR_OTHER
, spl
));
310 mand_part_len
-= spl
;
313 /* Destination Protocol Address */
315 ND_ICHECK_U(mand_part_len
, <, dpl
);
318 ND_PRINT(" %s", NHRP_IPv4_ADDR_STRING(bp
, dpl
));
321 ND_PRINT(" %s", NHRP_IPv6_ADDR_STRING(bp
, dpl
));
324 ND_PRINT(" %s", GET_LINKADDR_STRING(bp
, LINKADDR_OTHER
, dpl
));
328 mand_part_len
-= dpl
;
332 case NHRP_PKT_RESOLUTION_REQUEST
:
333 case NHRP_PKT_RESOLUTION_REPLY
:
334 case NHRP_PKT_REGISTRATION_REQUEST
:
335 case NHRP_PKT_REGISTRATION_REPLY
:
336 case NHRP_PKT_PURGE_REQUEST
:
337 case NHRP_PKT_PURGE_REPLY
:
338 /* Client Information Entries */
339 while (mand_part_len
!= 0) {
342 cie_len
= nhrp_print_cie(ndo
, bp
, mand_part_len
,
345 mand_part_len
-= cie_len
;
348 case NHRP_PKT_ERROR_INDICATION
:
349 /* Contents of NHRP Packet in error */
357 nd_print_invalid(ndo
);
361 nhrp_print_cie(netdissect_options
*ndo
, const u_char
*data
, uint16_t mand_part_len
,
362 uint16_t afn
, uint16_t pro_type
)
364 const struct nhrp_cie
*cie
;
367 uint8_t cli_saddr_tl
;
368 uint8_t cli_proto_tl
;
370 cie
= (const struct nhrp_cie
*)data
;
372 ND_ICHECKMSG_ZU("remaining mandatory part length",
373 mand_part_len
, <, sizeof(*cie
));
375 ND_PRINT(" (code %d", GET_U_1(cie
->code
));
377 ND_PRINT(", pl %d, mtu %d, htime %d, pref %d",
379 GET_BE_U_2(cie
->mtu
),
380 GET_BE_U_2(cie
->htime
),
383 cli_addr_tl
= GET_U_1(cie
->cli_addr_tl
);
384 cli_saddr_tl
= GET_U_1(cie
->cli_saddr_tl
);
385 cli_proto_tl
= GET_U_1(cie
->cli_proto_tl
);
387 /* check 2nd most significant bit */
388 if (cli_addr_tl
& 0x40)
389 ND_PRINT(", nbma E.154");
391 data
+= sizeof(*cie
);
392 cie_len
+= sizeof(*cie
);
393 mand_part_len
-= sizeof(*cie
);
396 ND_ICHECKMSG_U("remaining mandatory part length",
397 mand_part_len
, <, cli_addr_tl
);
400 ND_PRINT(", nbma %s", NHRP_IPv4_ADDR_STRING(data
, cli_addr_tl
));
403 ND_PRINT(", nbma %s", NHRP_IPv6_ADDR_STRING(data
, cli_addr_tl
));
406 ND_PRINT(", nbma %s", NHRP_MAC_ADDR_STRING(data
, cli_addr_tl
));
409 ND_PRINT(", unknown-nbma-addr-family-%04x (%s)",
410 afn
, GET_LINKADDR_STRING(data
, LINKADDR_OTHER
, cli_addr_tl
));
414 cie_len
+= cli_addr_tl
;
415 mand_part_len
-= cli_addr_tl
;
419 ND_ICHECKMSG_U("remaining mandatory part length",
420 mand_part_len
, <, cli_addr_tl
);
421 ND_PRINT(", unknown-nbma-saddr-family");
422 ND_TCHECK_LEN(data
, cli_saddr_tl
);
423 data
+= cli_saddr_tl
;
424 cie_len
+= cli_saddr_tl
;
425 mand_part_len
-= cli_saddr_tl
;
429 ND_ICHECKMSG_U("remaining mandatory part length",
430 mand_part_len
, <, cli_proto_tl
);
433 ND_PRINT(", proto %s", NHRP_IPv4_ADDR_STRING(data
, cli_proto_tl
));
436 ND_PRINT(", proto %s", NHRP_IPv6_ADDR_STRING(data
, cli_proto_tl
));
439 ND_PRINT(", unknown-proto-family-%04x (%s)",
440 pro_type
, GET_LINKADDR_STRING(data
, LINKADDR_OTHER
, cli_proto_tl
));
443 cie_len
+= cli_proto_tl
;
444 mand_part_len
-= cli_proto_tl
;
452 nd_print_invalid(ndo
);