1*3a50f0a9Sjmc /* $OpenBSD: print-nhrp.c,v 1.2 2022/12/28 21:30:19 jmc Exp $ */
2a66f6432Sremi
3a66f6432Sremi /*
4a66f6432Sremi * Copyright (c) 2020 Remi Locherer <remi@openbsd.org>
5a66f6432Sremi *
6a66f6432Sremi * Permission to use, copy, modify, and distribute this software for any
7a66f6432Sremi * purpose with or without fee is hereby granted, provided that the above
8a66f6432Sremi * copyright notice and this permission notice appear in all copies.
9a66f6432Sremi *
10a66f6432Sremi * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11a66f6432Sremi * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12a66f6432Sremi * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13a66f6432Sremi * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14a66f6432Sremi * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15a66f6432Sremi * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16a66f6432Sremi * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a66f6432Sremi */
18a66f6432Sremi
19a66f6432Sremi /*
20a66f6432Sremi * RFC 2332 NBMA Next Hop Resolution Protocol (NHRP)
21a66f6432Sremi */
22a66f6432Sremi
23a66f6432Sremi #include <sys/time.h>
24a66f6432Sremi #include <sys/uio.h>
25a66f6432Sremi #include <sys/socket.h>
26a66f6432Sremi
27a66f6432Sremi #include <netinet/in.h>
28a66f6432Sremi #include <netinet/ip.h>
29a66f6432Sremi #include <arpa/inet.h>
30a66f6432Sremi
31a66f6432Sremi #include <net/ethertypes.h>
32a66f6432Sremi
33a66f6432Sremi #include <stdio.h>
34a66f6432Sremi #include <string.h>
35a66f6432Sremi #include <ctype.h>
36a66f6432Sremi
37a66f6432Sremi #include "addrtoname.h"
38a66f6432Sremi #include "afnum.h"
39a66f6432Sremi #include "interface.h"
40a66f6432Sremi #include "extract.h"
41a66f6432Sremi
42a66f6432Sremi #define NHRP_VER_RFC2332 1
43a66f6432Sremi
44a66f6432Sremi #define NHRP_PKG_RESOLUTION_REQUEST 1
45a66f6432Sremi #define NHRP_PKG_RESOLUTION_REPLY 2
46a66f6432Sremi #define NHRP_PKG_REGISTRATION_REQUEST 3
47a66f6432Sremi #define NHRP_PKG_REGISTRATION_REPLY 4
48a66f6432Sremi #define NHRP_PKG_PURGE_REQUEST 5
49a66f6432Sremi #define NHRP_PKG_PURGE_REPLY 6
50a66f6432Sremi #define NHRP_PKG_ERROR_INDICATION 7
51a66f6432Sremi
52a66f6432Sremi
53a66f6432Sremi struct nhrp_header {
54a66f6432Sremi /* fixed header part */
55a66f6432Sremi u_int16_t afn; /* link layer address */
56a66f6432Sremi u_int16_t pro_type; /* protocol type (short form) */
57a66f6432Sremi u_int8_t pro_snap[5]; /* protocol type (long form) */
58a66f6432Sremi u_int8_t hopcnt; /* hop count */
59a66f6432Sremi u_int16_t pktsz; /* length of the NHRP packet (octets) */
60a66f6432Sremi u_int16_t chksum; /* IP checksum over the entier packet */
61a66f6432Sremi u_int16_t extoff; /* extension offset */
62a66f6432Sremi u_int8_t op_version; /* version of address mapping and
63a66f6432Sremi management protocol */
64a66f6432Sremi u_int8_t op_type; /* NHRP packet type */
65a66f6432Sremi u_int8_t shtl; /* type and length of src NBMA addr */
66a66f6432Sremi u_int8_t sstl; /* type and length of src NBMA
67a66f6432Sremi subaddress */
68a66f6432Sremi /* mandatory header part */
69a66f6432Sremi u_int8_t spl; /* src proto len */
70a66f6432Sremi u_int8_t dpl; /* dst proto len */
71a66f6432Sremi u_int16_t flags; /* flags */
72a66f6432Sremi union {
73a66f6432Sremi u_int32_t id; /* request id */
74a66f6432Sremi struct { /* error code */
75a66f6432Sremi u_int16_t code;
76a66f6432Sremi u_int16_t offset;
77a66f6432Sremi } err;
78a66f6432Sremi } u;
79a66f6432Sremi };
80a66f6432Sremi
81a66f6432Sremi struct nhrp_cie {
82a66f6432Sremi /* client information entrie */
83a66f6432Sremi u_int8_t code;
84a66f6432Sremi u_int8_t plen;
85a66f6432Sremi u_int16_t unused;
86a66f6432Sremi u_int16_t mtu;
87a66f6432Sremi u_int16_t htime;
88a66f6432Sremi u_int8_t cli_addr_tl;
89a66f6432Sremi u_int8_t cli_saddr_tl;
90a66f6432Sremi u_int8_t cli_proto_tl;
91a66f6432Sremi u_int8_t pref;
92a66f6432Sremi };
93a66f6432Sremi
94a66f6432Sremi static const u_char * nhrp_print_cie(const u_char *, u_int16_t, u_int16_t);
95a66f6432Sremi
96a66f6432Sremi
97a66f6432Sremi void
nhrp_print(const u_char * p,u_int length)98a66f6432Sremi nhrp_print(const u_char *p, u_int length)
99a66f6432Sremi {
100a66f6432Sremi struct nhrp_header *hdr;
101a66f6432Sremi const u_char *nhrpext, *nhrpend;
102a66f6432Sremi
103a66f6432Sremi printf("NHRP: ");
104a66f6432Sremi
105a66f6432Sremi if ((snapend - p) < sizeof(*hdr))
106a66f6432Sremi goto trunc;
107a66f6432Sremi
108a66f6432Sremi hdr = (struct nhrp_header *)p;
109a66f6432Sremi
110a66f6432Sremi if (hdr->op_version != NHRP_VER_RFC2332) {
111a66f6432Sremi printf("unknown-version-%02x", hdr->op_version);
112a66f6432Sremi return;
113a66f6432Sremi
114a66f6432Sremi }
115a66f6432Sremi
116a66f6432Sremi nhrpext = p + EXTRACT_16BITS(&hdr->extoff);
117a66f6432Sremi nhrpend = p + EXTRACT_16BITS(&hdr->pktsz);
118a66f6432Sremi
119a66f6432Sremi switch (hdr->op_type) {
120a66f6432Sremi case NHRP_PKG_RESOLUTION_REQUEST:
121a66f6432Sremi printf("res request, ");
122a66f6432Sremi break;
123a66f6432Sremi case NHRP_PKG_RESOLUTION_REPLY:
124a66f6432Sremi printf("res reply, ");
125a66f6432Sremi break;
126a66f6432Sremi case NHRP_PKG_REGISTRATION_REQUEST:
127a66f6432Sremi printf("reg request, ");
128a66f6432Sremi break;
129a66f6432Sremi case NHRP_PKG_REGISTRATION_REPLY:
130a66f6432Sremi printf("reg reply, ");
131a66f6432Sremi break;
132a66f6432Sremi case NHRP_PKG_PURGE_REQUEST:
133a66f6432Sremi printf("purge request, ");
134a66f6432Sremi break;
135a66f6432Sremi case NHRP_PKG_PURGE_REPLY:
136a66f6432Sremi printf("purge reply, ");
137a66f6432Sremi break;
138a66f6432Sremi case NHRP_PKG_ERROR_INDICATION:
139a66f6432Sremi printf("error %u", hdr->u.err.code);
140a66f6432Sremi return;
141a66f6432Sremi default:
142a66f6432Sremi printf("unknown-op-type-%04x, ", hdr->op_type);
143a66f6432Sremi break;
144a66f6432Sremi }
145a66f6432Sremi
146a66f6432Sremi printf("id %u", EXTRACT_32BITS(&hdr->u.id));
147a66f6432Sremi
148a66f6432Sremi if (vflag) {
149a66f6432Sremi printf(", hopcnt %u", hdr->hopcnt);
150a66f6432Sremi
151*3a50f0a9Sjmc /* most significant bit must be 0 */
152a66f6432Sremi if (hdr->shtl & 0x80)
153a66f6432Sremi printf(" (shtl bit 7 set)");
154a66f6432Sremi
155a66f6432Sremi /* check 2nd most significant bit */
156a66f6432Sremi if (hdr->shtl & 0x40)
157a66f6432Sremi printf(" (nbma E.154)");
158a66f6432Sremi }
159a66f6432Sremi
160a66f6432Sremi p += sizeof(*hdr);
161a66f6432Sremi if ((snapend - p) < hdr->shtl)
162a66f6432Sremi goto trunc;
163a66f6432Sremi
164a66f6432Sremi if (hdr->shtl) {
165a66f6432Sremi switch (EXTRACT_16BITS(&hdr->afn)) {
166a66f6432Sremi case AFNUM_INET:
167a66f6432Sremi printf(", src nbma %s", ipaddr_string(p));
168a66f6432Sremi break;
169a66f6432Sremi case AFNUM_INET6:
170a66f6432Sremi printf(", src nbma %s", ip6addr_string(p));
171a66f6432Sremi break;
172a66f6432Sremi case AFNUM_802:
173a66f6432Sremi printf(", src nbma %s", etheraddr_string(p));
174a66f6432Sremi break;
175a66f6432Sremi default:
176a66f6432Sremi printf(", unknown-nbma-addr-family-%04x",
177a66f6432Sremi EXTRACT_16BITS(&hdr->afn));
178a66f6432Sremi break;
179a66f6432Sremi }
180a66f6432Sremi }
181a66f6432Sremi
182a66f6432Sremi p += hdr->shtl;
183a66f6432Sremi if ((snapend - p) < (hdr->spl + hdr->dpl))
184a66f6432Sremi goto trunc;
185a66f6432Sremi
186a66f6432Sremi switch (EXTRACT_16BITS(&hdr->pro_type)) {
187a66f6432Sremi case ETHERTYPE_IP:
188a66f6432Sremi printf(", %s -> %s",
189a66f6432Sremi ipaddr_string(p),
190a66f6432Sremi ipaddr_string(p + hdr->spl));
191a66f6432Sremi break;
192a66f6432Sremi case ETHERTYPE_IPV6:
193a66f6432Sremi printf(", %s -> %s",
194a66f6432Sremi ip6addr_string(p),
195a66f6432Sremi ip6addr_string(p + hdr->spl));
196a66f6432Sremi break;
197a66f6432Sremi default:
198a66f6432Sremi printf(", proto type %04x",
199a66f6432Sremi EXTRACT_16BITS(&hdr->pro_type));
200a66f6432Sremi break;
201a66f6432Sremi }
202a66f6432Sremi
203a66f6432Sremi p += hdr->spl + hdr->dpl;
204a66f6432Sremi
205a66f6432Sremi do {
206a66f6432Sremi p = nhrp_print_cie(p, hdr->afn, hdr->pro_type);
207a66f6432Sremi if (p == 0)
208a66f6432Sremi goto trunc;
209a66f6432Sremi } while ((hdr->extoff && (p < nhrpext)) ||
210a66f6432Sremi ((!hdr->extoff && (p < nhrpend))));
211a66f6432Sremi
212a66f6432Sremi return;
213a66f6432Sremi
214a66f6432Sremi trunc:
215a66f6432Sremi printf(" [|nhrp]");
216a66f6432Sremi
217a66f6432Sremi }
218a66f6432Sremi
219a66f6432Sremi static const u_char *
nhrp_print_cie(const u_char * data,u_int16_t afn,u_int16_t pro_type)220a66f6432Sremi nhrp_print_cie(const u_char *data, u_int16_t afn, u_int16_t pro_type)
221a66f6432Sremi {
222a66f6432Sremi struct nhrp_cie *cie;
223a66f6432Sremi int family, type;
224a66f6432Sremi
225a66f6432Sremi if ((snapend - data) < sizeof(*cie))
226a66f6432Sremi return (0);
227a66f6432Sremi
228a66f6432Sremi cie = (struct nhrp_cie *)data;
229a66f6432Sremi
230a66f6432Sremi family = EXTRACT_16BITS(&afn);
231a66f6432Sremi type = EXTRACT_16BITS(&pro_type);
232a66f6432Sremi
233a66f6432Sremi printf(" (code %d", cie->code);
234a66f6432Sremi if (vflag)
235a66f6432Sremi printf(", pl %d, mtu %d, htime %d, pref %d", cie->plen,
236a66f6432Sremi EXTRACT_16BITS(&cie->mtu), EXTRACT_16BITS(&cie->htime),
237a66f6432Sremi cie->pref);
238a66f6432Sremi
239a66f6432Sremi /* check 2nd most significant bit */
240a66f6432Sremi if (cie->cli_addr_tl & 0x40)
241a66f6432Sremi printf(", nbma E.154");
242a66f6432Sremi
243a66f6432Sremi data += sizeof(*cie);
244a66f6432Sremi if ((snapend - data) < cie->cli_addr_tl)
245a66f6432Sremi return (0);
246a66f6432Sremi
247a66f6432Sremi if (cie->cli_addr_tl) {
248a66f6432Sremi switch (family) {
249a66f6432Sremi case AFNUM_INET:
250a66f6432Sremi printf(", nbma %s", ipaddr_string(data));
251a66f6432Sremi break;
252a66f6432Sremi case AFNUM_INET6:
253a66f6432Sremi printf(", nbma %s", ip6addr_string(data));
254a66f6432Sremi break;
255a66f6432Sremi case AFNUM_802:
256a66f6432Sremi printf(", nbma %s", etheraddr_string(data));
257a66f6432Sremi break;
258a66f6432Sremi default:
259a66f6432Sremi printf(", unknown-nbma-addr-family-%04x", family);
260a66f6432Sremi break;
261a66f6432Sremi }
262a66f6432Sremi }
263a66f6432Sremi if (cie->cli_saddr_tl)
264a66f6432Sremi printf(", unknown-nbma-saddr-family");
265a66f6432Sremi
266a66f6432Sremi data += cie->cli_addr_tl + cie->cli_saddr_tl;
267a66f6432Sremi if ((snapend - data) < cie->cli_proto_tl)
268a66f6432Sremi return (0);
269a66f6432Sremi
270a66f6432Sremi if (cie->cli_proto_tl) {
271a66f6432Sremi switch (type) {
272a66f6432Sremi case ETHERTYPE_IP:
273a66f6432Sremi printf(", proto %s", ipaddr_string(data));
274a66f6432Sremi break;
275a66f6432Sremi case ETHERTYPE_IPV6:
276a66f6432Sremi printf(", proto %s", ip6addr_string(data));
277a66f6432Sremi break;
278a66f6432Sremi default:
279a66f6432Sremi printf(", unknown-proto-family-%04x", type);
280a66f6432Sremi break;
281a66f6432Sremi }
282a66f6432Sremi }
283a66f6432Sremi
284a66f6432Sremi printf(")");
285a66f6432Sremi
286a66f6432Sremi return (data + cie->cli_proto_tl);
287a66f6432Sremi }
288