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