1190815Srmacklem/*	$OpenBSD: print-gre.c,v 1.6 2002/10/30 03:04:04 fgsch Exp $	*/
2190815Srmacklem
3190815Srmacklem/*
4190815Srmacklem * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
5190815Srmacklem * All rights reserved.
6190815Srmacklem *
7190815Srmacklem * Redistribution and use in source and binary forms, with or without
8190815Srmacklem * modification, are permitted provided that the following conditions
9190815Srmacklem * are met:
10190815Srmacklem * 1. Redistributions of source code must retain the above copyright
11190815Srmacklem *    notice, this list of conditions and the following disclaimer.
12190815Srmacklem * 2. Redistributions in binary form must reproduce the above copyright
13190815Srmacklem *    notice, this list of conditions and the following disclaimer in the
14190815Srmacklem *    documentation and/or other materials provided with the distribution.
15190815Srmacklem *
16190815Srmacklem * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17190815Srmacklem * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18190815Srmacklem * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19190815Srmacklem * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20190815Srmacklem * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21190815Srmacklem * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22190815Srmacklem * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23190815Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24190815Srmacklem * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25190815Srmacklem * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26190815Srmacklem * POSSIBILITY OF SUCH DAMAGE.
27190815Srmacklem */
28190815Srmacklem
29190815Srmacklem/* \summary: Generic Routing Encapsulation (GRE) printer */
30190815Srmacklem
31190815Srmacklem/*
32190815Srmacklem * netdissect printer for GRE - Generic Routing Encapsulation
33190815Srmacklem * RFC1701 (GRE), RFC1702 (GRE IPv4), and RFC2637 (Enhanced GRE)
34190815Srmacklem */
35190815Srmacklem
36190815Srmacklem#include <sys/cdefs.h>
37190815Srmacklem#ifndef lint
38190815Srmacklem__RCSID("$NetBSD: print-gre.c,v 1.10 2023/08/17 20:19:40 christos Exp $");
39190815Srmacklem#endif
40190815Srmacklem
41190815Srmacklem#ifdef HAVE_CONFIG_H
42190815Srmacklem#include <config.h>
43190815Srmacklem#endif
44190815Srmacklem
45190815Srmacklem#include "netdissect-stdinc.h"
46190815Srmacklem
47190815Srmacklem#include "netdissect.h"
48190815Srmacklem#include "addrtostr.h"
49190815Srmacklem#include "extract.h"
50190815Srmacklem#include "ethertype.h"
51190815Srmacklem
52190815Srmacklem
53190815Srmacklem#define	GRE_CP		0x8000		/* checksum present */
54190815Srmacklem#define	GRE_RP		0x4000		/* routing present */
55190815Srmacklem#define	GRE_KP		0x2000		/* key present */
56190815Srmacklem#define	GRE_SP		0x1000		/* sequence# present */
57190815Srmacklem#define	GRE_sP		0x0800		/* source routing */
58190815Srmacklem#define	GRE_AP		0x0080		/* acknowledgment# present */
59190815Srmacklem
60190815Srmacklemstatic const struct tok gre_flag_values[] = {
61190815Srmacklem    { GRE_CP, "checksum present"},
62190815Srmacklem    { GRE_RP, "routing present"},
63190815Srmacklem    { GRE_KP, "key present"},
64190815Srmacklem    { GRE_SP, "sequence# present"},
65190815Srmacklem    { GRE_sP, "source routing present"},
66217432Srmacklem    { GRE_AP, "ack present"},
67221439Srmacklem    { 0, NULL }
68221439Srmacklem};
69241561Srmacklem
70241561Srmacklem#define	GRE_RECRS_MASK	0x0700		/* recursion count */
71243782Srmacklem#define	GRE_VERS_MASK	0x0007		/* protocol version */
72291527Srmacklem
73190815Srmacklem/* source route entry types */
74243782Srmacklem#define	GRESRE_IP	0x0800		/* IP */
75243782Srmacklem#define	GRESRE_ASN	0xfffe		/* ASN */
76243782Srmacklem
77243782Srmacklemstatic void gre_print_0(netdissect_options *, const u_char *, u_int);
78243782Srmacklemstatic void gre_print_1(netdissect_options *, const u_char *, u_int);
79243782Srmacklemstatic int gre_sre_print(netdissect_options *, uint16_t, uint8_t, uint8_t, const u_char *, u_int);
80243782Srmacklemstatic int gre_sre_ip_print(netdissect_options *, uint8_t, uint8_t, const u_char *, u_int);
81190815Srmacklemstatic int gre_sre_asn_print(netdissect_options *, uint8_t, uint8_t, const u_char *, u_int);
82
83void
84gre_print(netdissect_options *ndo, const u_char *bp, u_int length)
85{
86	u_int len = length, vers;
87
88	ndo->ndo_protocol = "gre";
89	ND_TCHECK_2(bp);
90	if (len < 2)
91		goto trunc;
92	vers = GET_BE_U_2(bp) & GRE_VERS_MASK;
93	ND_PRINT("GREv%u",vers);
94
95	switch(vers) {
96	case 0:
97		gre_print_0(ndo, bp, len);
98		break;
99	case 1:
100		gre_print_1(ndo, bp, len);
101		break;
102	default:
103		ND_PRINT(" ERROR: unknown-version");
104		break;
105	}
106	return;
107
108trunc:
109	nd_print_trunc(ndo);
110}
111
112static void
113gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length)
114{
115	u_int len = length;
116	uint16_t flags, prot;
117
118	/* 16 bits ND_TCHECKed in gre_print() */
119	flags = GET_BE_U_2(bp);
120	if (ndo->ndo_vflag)
121		ND_PRINT(", Flags [%s]",
122			 bittok2str(gre_flag_values,"none",flags));
123
124	len -= 2;
125	bp += 2;
126
127	ND_TCHECK_2(bp);
128	if (len < 2)
129		goto trunc;
130	prot = GET_BE_U_2(bp);
131	len -= 2;
132	bp += 2;
133
134	if ((flags & GRE_CP) | (flags & GRE_RP)) {
135		ND_TCHECK_2(bp);
136		if (len < 2)
137			goto trunc;
138		if (ndo->ndo_vflag)
139			ND_PRINT(", sum 0x%x", GET_BE_U_2(bp));
140		bp += 2;
141		len -= 2;
142
143		ND_TCHECK_2(bp);
144		if (len < 2)
145			goto trunc;
146		ND_PRINT(", off 0x%x", GET_BE_U_2(bp));
147		bp += 2;
148		len -= 2;
149	}
150
151	if (flags & GRE_KP) {
152		ND_TCHECK_4(bp);
153		if (len < 4)
154			goto trunc;
155		ND_PRINT(", key=0x%x", GET_BE_U_4(bp));
156		bp += 4;
157		len -= 4;
158	}
159
160	if (flags & GRE_SP) {
161		ND_TCHECK_4(bp);
162		if (len < 4)
163			goto trunc;
164		ND_PRINT(", seq %u", GET_BE_U_4(bp));
165		bp += 4;
166		len -= 4;
167	}
168
169	if (flags & GRE_RP) {
170		for (;;) {
171			uint16_t af;
172			uint8_t sreoff;
173			uint8_t srelen;
174
175			ND_TCHECK_4(bp);
176			if (len < 4)
177				goto trunc;
178			af = GET_BE_U_2(bp);
179			sreoff = GET_U_1(bp + 2);
180			srelen = GET_U_1(bp + 3);
181			bp += 4;
182			len -= 4;
183
184			if (af == 0 && srelen == 0)
185				break;
186
187			if (!gre_sre_print(ndo, af, sreoff, srelen, bp, len))
188				goto trunc;
189
190			if (len < srelen)
191				goto trunc;
192			bp += srelen;
193			len -= srelen;
194		}
195	}
196
197	if (ndo->ndo_eflag)
198		ND_PRINT(", proto %s (0x%04x)",
199			 tok2str(ethertype_values,"unknown",prot), prot);
200
201	ND_PRINT(", length %u",length);
202
203	if (ndo->ndo_vflag < 1)
204		ND_PRINT(": "); /* put in a colon as protocol demarc */
205	else
206		ND_PRINT("\n\t"); /* if verbose go multiline */
207
208	switch (prot) {
209	case ETHERTYPE_IP:
210		ip_print(ndo, bp, len);
211		break;
212	case ETHERTYPE_IPV6:
213		ip6_print(ndo, bp, len);
214		break;
215	case ETHERTYPE_MPLS:
216		mpls_print(ndo, bp, len);
217		break;
218	case ETHERTYPE_IPX:
219		ipx_print(ndo, bp, len);
220		break;
221	case ETHERTYPE_ATALK:
222		atalk_print(ndo, bp, len);
223		break;
224	case ETHERTYPE_GRE_ISO:
225		isoclns_print(ndo, bp, len);
226		break;
227	case ETHERTYPE_TEB:
228		ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
229		break;
230	default:
231		ND_PRINT("gre-proto-0x%x", prot);
232	}
233	return;
234
235trunc:
236	nd_print_trunc(ndo);
237}
238
239static void
240gre_print_1(netdissect_options *ndo, const u_char *bp, u_int length)
241{
242	u_int len = length;
243	uint16_t flags, prot;
244
245	/* 16 bits ND_TCHECKed in gre_print() */
246	flags = GET_BE_U_2(bp);
247	len -= 2;
248	bp += 2;
249
250	if (ndo->ndo_vflag)
251		ND_PRINT(", Flags [%s]",
252			 bittok2str(gre_flag_values,"none",flags));
253
254	ND_TCHECK_2(bp);
255	if (len < 2)
256		goto trunc;
257	prot = GET_BE_U_2(bp);
258	len -= 2;
259	bp += 2;
260
261
262	if (flags & GRE_KP) {
263		uint32_t k;
264
265		ND_TCHECK_4(bp);
266		if (len < 4)
267			goto trunc;
268		k = GET_BE_U_4(bp);
269		ND_PRINT(", call %u", k & 0xffff);
270		len -= 4;
271		bp += 4;
272	}
273
274	if (flags & GRE_SP) {
275		ND_TCHECK_4(bp);
276		if (len < 4)
277			goto trunc;
278		ND_PRINT(", seq %u", GET_BE_U_4(bp));
279		bp += 4;
280		len -= 4;
281	}
282
283	if (flags & GRE_AP) {
284		ND_TCHECK_4(bp);
285		if (len < 4)
286			goto trunc;
287		ND_PRINT(", ack %u", GET_BE_U_4(bp));
288		bp += 4;
289		len -= 4;
290	}
291
292	if ((flags & GRE_SP) == 0)
293		ND_PRINT(", no-payload");
294
295	if (ndo->ndo_eflag)
296		ND_PRINT(", proto %s (0x%04x)",
297			 tok2str(ethertype_values,"unknown",prot), prot);
298
299	ND_PRINT(", length %u",length);
300
301	if ((flags & GRE_SP) == 0)
302		return;
303
304	if (ndo->ndo_vflag < 1)
305		ND_PRINT(": "); /* put in a colon as protocol demarc */
306	else
307		ND_PRINT("\n\t"); /* if verbose go multiline */
308
309	switch (prot) {
310	case ETHERTYPE_PPP:
311		ppp_print(ndo, bp, len);
312		break;
313	default:
314		ND_PRINT("gre-proto-0x%x", prot);
315		break;
316	}
317	return;
318
319trunc:
320	nd_print_trunc(ndo);
321}
322
323static int
324gre_sre_print(netdissect_options *ndo, uint16_t af, uint8_t sreoff,
325	      uint8_t srelen, const u_char *bp, u_int len)
326{
327	int ret;
328
329	switch (af) {
330	case GRESRE_IP:
331		ND_PRINT(", (rtaf=ip");
332		ret = gre_sre_ip_print(ndo, sreoff, srelen, bp, len);
333		ND_PRINT(")");
334		break;
335	case GRESRE_ASN:
336		ND_PRINT(", (rtaf=asn");
337		ret = gre_sre_asn_print(ndo, sreoff, srelen, bp, len);
338		ND_PRINT(")");
339		break;
340	default:
341		ND_PRINT(", (rtaf=0x%x)", af);
342		ret = 1;
343	}
344	return (ret);
345}
346
347static int
348gre_sre_ip_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
349		 const u_char *bp, u_int len)
350{
351	const u_char *up = bp;
352	char buf[INET_ADDRSTRLEN];
353
354	if (sreoff & 3) {
355		ND_PRINT(", badoffset=%u", sreoff);
356		return (1);
357	}
358	if (srelen & 3) {
359		ND_PRINT(", badlength=%u", srelen);
360		return (1);
361	}
362	if (sreoff >= srelen) {
363		ND_PRINT(", badoff/len=%u/%u", sreoff, srelen);
364		return (1);
365	}
366
367	while (srelen != 0) {
368		ND_TCHECK_4(bp);
369		if (len < 4)
370			return (0);
371
372		addrtostr(bp, buf, sizeof(buf));
373		ND_PRINT(" %s%s",
374			 ((bp - up) == sreoff) ? "*" : "", buf);
375
376		bp += 4;
377		len -= 4;
378		srelen -= 4;
379	}
380	return (1);
381trunc:
382	return 0;
383}
384
385static int
386gre_sre_asn_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
387		  const u_char *bp, u_int len)
388{
389	const u_char *up = bp;
390
391	if (sreoff & 1) {
392		ND_PRINT(", badoffset=%u", sreoff);
393		return (1);
394	}
395	if (srelen & 1) {
396		ND_PRINT(", badlength=%u", srelen);
397		return (1);
398	}
399	if (sreoff >= srelen) {
400		ND_PRINT(", badoff/len=%u/%u", sreoff, srelen);
401		return (1);
402	}
403
404	while (srelen != 0) {
405		ND_TCHECK_2(bp);
406		if (len < 2)
407			return (0);
408
409		ND_PRINT(" %s%x",
410			 ((bp - up) == sreoff) ? "*" : "", GET_BE_U_2(bp));
411
412		bp += 2;
413		len -= 2;
414		srelen -= 2;
415	}
416	return (1);
417trunc:
418	return 0;
419}
420