1/*	$OpenBSD: print-gre.c,v 1.6 2002/10/30 03:04:04 fgsch Exp $	*/
2
3/*
4 * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by Jason L. Wright
18 * 4. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/*
35 * tcpdump filter for GRE - Generic Routing Encapsulation
36 * RFC1701 (GRE), RFC1702 (GRE IPv4), and RFC2637 (Enhanced GRE)
37 */
38
39#ifndef lint
40static const char rcsid[] _U_ =
41    "@(#) $Header: /tcpdump/master/tcpdump/print-gre.c,v 1.28 2005/04/06 21:32:39 mcr Exp $ (LBL)";
42#endif
43
44#ifdef HAVE_CONFIG_H
45#include "config.h"
46#endif
47
48#include <tcpdump-stdinc.h>
49
50#include <stdio.h>
51#include <string.h>
52
53#include "interface.h"
54#include "addrtoname.h"
55#include "extract.h"
56
57#include "ip.h"
58#include "ethertype.h"
59
60#define	GRE_CP		0x8000		/* checksum present */
61#define	GRE_RP		0x4000		/* routing present */
62#define	GRE_KP		0x2000		/* key present */
63#define	GRE_SP		0x1000		/* sequence# present */
64#define	GRE_sP		0x0800		/* source routing */
65#define	GRE_RECRS	0x0700		/* recursion count */
66#define	GRE_AP		0x0080		/* acknowledgment# present */
67
68struct tok gre_flag_values[] = {
69    { GRE_CP, "checksum present"},
70    { GRE_RP, "routing present"},
71    { GRE_KP, "key present"},
72    { GRE_SP, "sequence# present"},
73    { GRE_sP, "source routing present"},
74    { GRE_RECRS, "recursion count"},
75    { GRE_AP, "ack present"},
76    { 0, NULL }
77};
78
79#define	GRE_VERS_MASK	0x0007		/* protocol version */
80
81/* source route entry types */
82#define	GRESRE_IP	0x0800		/* IP */
83#define	GRESRE_ASN	0xfffe		/* ASN */
84
85void gre_print_0(const u_char *, u_int);
86void gre_print_1(const u_char *, u_int);
87void gre_sre_print(u_int16_t, u_int8_t, u_int8_t, const u_char *, u_int);
88void gre_sre_ip_print(u_int8_t, u_int8_t, const u_char *, u_int);
89void gre_sre_asn_print(u_int8_t, u_int8_t, const u_char *, u_int);
90
91void
92gre_print(const u_char *bp, u_int length)
93{
94	u_int len = length, vers;
95
96	if (len < 2) {
97		printf("[|gre]");
98		return;
99	}
100	vers = EXTRACT_16BITS(bp) & GRE_VERS_MASK;
101        printf("GREv%u",vers);
102
103        switch(vers) {
104        case 0:
105            gre_print_0(bp, len);
106            break;
107        case 1:
108            gre_print_1(bp, len);
109            break;
110	default:
111            printf(" ERROR: unknown-version");
112            break;
113        }
114	return;
115
116}
117
118void
119gre_print_0(const u_char *bp, u_int length)
120{
121	u_int len = length;
122	u_int16_t flags, prot;
123
124	flags = EXTRACT_16BITS(bp);
125        if (vflag)
126            printf(", Flags [%s]",
127                   bittok2str(gre_flag_values,"none",flags));
128
129	len -= 2;
130	bp += 2;
131
132	if (len < 2)
133		goto trunc;
134	prot = EXTRACT_16BITS(bp);
135	len -= 2;
136	bp += 2;
137
138	if ((flags & GRE_CP) | (flags & GRE_RP)) {
139		if (len < 2)
140			goto trunc;
141		if (vflag)
142			printf(", sum 0x%x", EXTRACT_16BITS(bp));
143		bp += 2;
144		len -= 2;
145
146		if (len < 2)
147			goto trunc;
148		printf(", off 0x%x", EXTRACT_16BITS(bp));
149		bp += 2;
150		len -= 2;
151	}
152
153	if (flags & GRE_KP) {
154		if (len < 4)
155			goto trunc;
156		printf(", key=0x%x", EXTRACT_32BITS(bp));
157		bp += 4;
158		len -= 4;
159	}
160
161	if (flags & GRE_SP) {
162		if (len < 4)
163			goto trunc;
164		printf(", seq %u", EXTRACT_32BITS(bp));
165		bp += 4;
166		len -= 4;
167	}
168
169	if (flags & GRE_RP) {
170		for (;;) {
171			u_int16_t af;
172			u_int8_t sreoff;
173			u_int8_t srelen;
174
175			if (len < 4)
176				goto trunc;
177			af = EXTRACT_16BITS(bp);
178			sreoff = *(bp + 2);
179			srelen = *(bp + 3);
180			bp += 4;
181			len -= 4;
182
183			if (af == 0 && srelen == 0)
184				break;
185
186			gre_sre_print(af, sreoff, srelen, bp, len);
187
188			if (len < srelen)
189				goto trunc;
190			bp += srelen;
191			len -= srelen;
192		}
193	}
194
195        if (eflag)
196            printf(", proto %s (0x%04x)",
197                   tok2str(ethertype_values,"unknown",prot),
198                   prot);
199
200        printf(", length %u",length);
201
202        if (vflag < 1)
203            printf(": "); /* put in a colon as protocol demarc */
204        else
205            printf("\n\t"); /* if verbose go multiline */
206
207	switch (prot) {
208	case ETHERTYPE_IP:
209	        ip_print(gndo, bp, len);
210		break;
211#ifdef INET6
212	case ETHERTYPE_IPV6:
213		ip6_print(bp, len);
214		break;
215#endif
216	case ETHERTYPE_MPLS:
217		mpls_print(bp, len);
218		break;
219	case ETHERTYPE_IPX:
220		ipx_print(bp, len);
221		break;
222	case ETHERTYPE_ATALK:
223		atalk_print(bp, len);
224		break;
225	case ETHERTYPE_GRE_ISO:
226		isoclns_print(bp, len, len);
227		break;
228	default:
229		printf("gre-proto-0x%x", prot);
230	}
231	return;
232
233trunc:
234	printf("[|gre]");
235}
236
237void
238gre_print_1(const u_char *bp, u_int length)
239{
240	u_int len = length;
241	u_int16_t flags, prot;
242
243	flags = EXTRACT_16BITS(bp);
244	len -= 2;
245	bp += 2;
246
247	if (vflag)
248            printf(", Flags [%s]",
249                   bittok2str(gre_flag_values,"none",flags));
250
251	if (len < 2)
252		goto trunc;
253	prot = EXTRACT_16BITS(bp);
254	len -= 2;
255	bp += 2;
256
257
258	if (flags & GRE_KP) {
259		u_int32_t k;
260
261		if (len < 4)
262			goto trunc;
263		k = EXTRACT_32BITS(bp);
264		printf(", call %d", k & 0xffff);
265		len -= 4;
266		bp += 4;
267	}
268
269	if (flags & GRE_SP) {
270		if (len < 4)
271			goto trunc;
272		printf(", seq %u", EXTRACT_32BITS(bp));
273		bp += 4;
274		len -= 4;
275	}
276
277	if (flags & GRE_AP) {
278		if (len < 4)
279			goto trunc;
280		printf(", ack %u", EXTRACT_32BITS(bp));
281		bp += 4;
282		len -= 4;
283	}
284
285	if ((flags & GRE_SP) == 0)
286		printf(", no-payload");
287
288        if (eflag)
289            printf(", proto %s (0x%04x)",
290                   tok2str(ethertype_values,"unknown",prot),
291                   prot);
292
293        printf(", length %u",length);
294
295        if ((flags & GRE_SP) == 0)
296            return;
297
298        if (vflag < 1)
299            printf(": "); /* put in a colon as protocol demarc */
300        else
301            printf("\n\t"); /* if verbose go multiline */
302
303	switch (prot) {
304	case ETHERTYPE_PPP:
305                ppp_print(bp, len);
306		break;
307	default:
308		printf("gre-proto-0x%x", prot);
309		break;
310	}
311	return;
312
313trunc:
314	printf("[|gre]");
315}
316
317void
318gre_sre_print(u_int16_t af, u_int8_t sreoff, u_int8_t srelen,
319    const u_char *bp, u_int len)
320{
321	switch (af) {
322	case GRESRE_IP:
323		printf(", (rtaf=ip");
324		gre_sre_ip_print(sreoff, srelen, bp, len);
325		printf(") ");
326		break;
327	case GRESRE_ASN:
328		printf(", (rtaf=asn");
329		gre_sre_asn_print(sreoff, srelen, bp, len);
330		printf(") ");
331		break;
332	default:
333		printf(", (rtaf=0x%x) ", af);
334	}
335}
336void
337gre_sre_ip_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
338{
339	struct in_addr a;
340	const u_char *up = bp;
341
342	if (sreoff & 3) {
343		printf(", badoffset=%u", sreoff);
344		return;
345	}
346	if (srelen & 3) {
347		printf(", badlength=%u", srelen);
348		return;
349	}
350	if (sreoff >= srelen) {
351		printf(", badoff/len=%u/%u", sreoff, srelen);
352		return;
353	}
354
355	for (;;) {
356		if (len < 4 || srelen == 0)
357			return;
358
359		memcpy(&a, bp, sizeof(a));
360		printf(" %s%s",
361		    ((bp - up) == sreoff) ? "*" : "",
362		    inet_ntoa(a));
363
364		bp += 4;
365		len -= 4;
366		srelen -= 4;
367	}
368}
369
370void
371gre_sre_asn_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
372{
373	const u_char *up = bp;
374
375	if (sreoff & 1) {
376		printf(", badoffset=%u", sreoff);
377		return;
378	}
379	if (srelen & 1) {
380		printf(", badlength=%u", srelen);
381		return;
382	}
383	if (sreoff >= srelen) {
384		printf(", badoff/len=%u/%u", sreoff, srelen);
385		return;
386	}
387
388	for (;;) {
389		if (len < 2 || srelen == 0)
390			return;
391
392		printf(" %s%x",
393		    ((bp - up) == sreoff) ? "*" : "",
394		    EXTRACT_16BITS(bp));
395
396		bp += 2;
397		len -= 2;
398		srelen -= 2;
399	}
400}
401