1127668Sbms/*	$OpenBSD: print-gre.c,v 1.6 2002/10/30 03:04:04 fgsch Exp $	*/
2127668Sbms
326180Sfenner/*
4127668Sbms * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
5127668Sbms * All rights reserved.
626180Sfenner *
7127668Sbms * Redistribution and use in source and binary forms, with or without
8127668Sbms * modification, are permitted provided that the following conditions
9127668Sbms * are met:
10127668Sbms * 1. Redistributions of source code must retain the above copyright
11127668Sbms *    notice, this list of conditions and the following disclaimer.
12127668Sbms * 2. Redistributions in binary form must reproduce the above copyright
13127668Sbms *    notice, this list of conditions and the following disclaimer in the
14127668Sbms *    documentation and/or other materials provided with the distribution.
15127668Sbms * 3. All advertising materials mentioning features or use of this software
16127668Sbms *    must display the following acknowledgement:
17127668Sbms *	This product includes software developed by Jason L. Wright
18127668Sbms * 4. The name of the author may not be used to endorse or promote products
19127668Sbms *    derived from this software without specific prior written permission.
2026180Sfenner *
21127668Sbms * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22127668Sbms * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23127668Sbms * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24127668Sbms * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25127668Sbms * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26127668Sbms * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27127668Sbms * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28127668Sbms * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29127668Sbms * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30127668Sbms * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31127668Sbms * POSSIBILITY OF SUCH DAMAGE.
3226180Sfenner */
3326180Sfenner
34127668Sbms/*
35127668Sbms * tcpdump filter for GRE - Generic Routing Encapsulation
36127668Sbms * RFC1701 (GRE), RFC1702 (GRE IPv4), and RFC2637 (Enhanced GRE)
37127668Sbms */
38127668Sbms
3926180Sfenner#ifndef lint
40127668Sbmsstatic const char rcsid[] _U_ =
41190207Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-gre.c,v 1.28 2005-04-06 21:32:39 mcr Exp $ (LBL)";
4226180Sfenner#endif
4326180Sfenner
4456893Sfenner#ifdef HAVE_CONFIG_H
4556893Sfenner#include "config.h"
4656893Sfenner#endif
4756893Sfenner
48127668Sbms#include <tcpdump-stdinc.h>
4926180Sfenner
5026180Sfenner#include <stdio.h>
51127668Sbms#include <string.h>
5226180Sfenner
5326180Sfenner#include "interface.h"
5426180Sfenner#include "addrtoname.h"
55127668Sbms#include "extract.h"
5626180Sfenner
57127668Sbms#include "ip.h"
58146773Ssam#include "ethertype.h"
5926180Sfenner
60127668Sbms#define	GRE_CP		0x8000		/* checksum present */
61127668Sbms#define	GRE_RP		0x4000		/* routing present */
62127668Sbms#define	GRE_KP		0x2000		/* key present */
63127668Sbms#define	GRE_SP		0x1000		/* sequence# present */
64127668Sbms#define	GRE_sP		0x0800		/* source routing */
65127668Sbms#define	GRE_RECRS	0x0700		/* recursion count */
66127668Sbms#define	GRE_AP		0x0080		/* acknowledgment# present */
6798524Sfenner
68146773Ssamstruct tok gre_flag_values[] = {
69146773Ssam    { GRE_CP, "checksum present"},
70146773Ssam    { GRE_RP, "routing present"},
71146773Ssam    { GRE_KP, "key present"},
72146773Ssam    { GRE_SP, "sequence# present"},
73146773Ssam    { GRE_sP, "source routing present"},
74146773Ssam    { GRE_RECRS, "recursion count"},
75146773Ssam    { GRE_AP, "ack present"},
76146773Ssam    { 0, NULL }
77146773Ssam};
7826180Sfenner
79146773Ssam#define	GRE_VERS_MASK	0x0007		/* protocol version */
80146773Ssam
81127668Sbms/* source route entry types */
82127668Sbms#define	GRESRE_IP	0x0800		/* IP */
83127668Sbms#define	GRESRE_ASN	0xfffe		/* ASN */
8426180Sfenner
85127668Sbmsvoid gre_print_0(const u_char *, u_int);
86127668Sbmsvoid gre_print_1(const u_char *, u_int);
87127668Sbmsvoid gre_sre_print(u_int16_t, u_int8_t, u_int8_t, const u_char *, u_int);
88127668Sbmsvoid gre_sre_ip_print(u_int8_t, u_int8_t, const u_char *, u_int);
89127668Sbmsvoid gre_sre_asn_print(u_int8_t, u_int8_t, const u_char *, u_int);
9098524Sfenner
91127668Sbmsvoid
92127668Sbmsgre_print(const u_char *bp, u_int length)
93127668Sbms{
94127668Sbms	u_int len = length, vers;
9598524Sfenner
96127668Sbms	if (len < 2) {
97127668Sbms		printf("[|gre]");
98127668Sbms		return;
99127668Sbms	}
100146773Ssam	vers = EXTRACT_16BITS(bp) & GRE_VERS_MASK;
101146773Ssam        printf("GREv%u",vers);
10298524Sfenner
103146773Ssam        switch(vers) {
104146773Ssam        case 0:
105146773Ssam            gre_print_0(bp, len);
106146773Ssam            break;
107146773Ssam        case 1:
108146773Ssam            gre_print_1(bp, len);
109146773Ssam            break;
110146773Ssam	default:
111146773Ssam            printf(" ERROR: unknown-version");
112146773Ssam            break;
113146773Ssam        }
114127668Sbms	return;
115127668Sbms
116127668Sbms}
117127668Sbms
11826180Sfennervoid
119127668Sbmsgre_print_0(const u_char *bp, u_int length)
12026180Sfenner{
121127668Sbms	u_int len = length;
122127668Sbms	u_int16_t flags, prot;
12326180Sfenner
124127668Sbms	flags = EXTRACT_16BITS(bp);
125146773Ssam        if (vflag)
126146773Ssam            printf(", Flags [%s]",
127146773Ssam                   bittok2str(gre_flag_values,"none",flags));
12826180Sfenner
129127668Sbms	len -= 2;
130127668Sbms	bp += 2;
13126180Sfenner
132127668Sbms	if (len < 2)
133127668Sbms		goto trunc;
134127668Sbms	prot = EXTRACT_16BITS(bp);
135127668Sbms	len -= 2;
136127668Sbms	bp += 2;
137127668Sbms
138127668Sbms	if ((flags & GRE_CP) | (flags & GRE_RP)) {
139127668Sbms		if (len < 2)
140127668Sbms			goto trunc;
141127668Sbms		if (vflag)
142146773Ssam			printf(", sum 0x%x", EXTRACT_16BITS(bp));
143127668Sbms		bp += 2;
144127668Sbms		len -= 2;
145127668Sbms
146127668Sbms		if (len < 2)
147127668Sbms			goto trunc;
148146773Ssam		printf(", off 0x%x", EXTRACT_16BITS(bp));
149127668Sbms		bp += 2;
150127668Sbms		len -= 2;
15126180Sfenner	}
15226180Sfenner
153127668Sbms	if (flags & GRE_KP) {
154127668Sbms		if (len < 4)
155127668Sbms			goto trunc;
156146773Ssam		printf(", key=0x%x", EXTRACT_32BITS(bp));
157127668Sbms		bp += 4;
158127668Sbms		len -= 4;
159127668Sbms	}
16098524Sfenner
161127668Sbms	if (flags & GRE_SP) {
162127668Sbms		if (len < 4)
163127668Sbms			goto trunc;
164146773Ssam		printf(", seq %u", EXTRACT_32BITS(bp));
165127668Sbms		bp += 4;
166127668Sbms		len -= 4;
167127668Sbms	}
16898524Sfenner
169127668Sbms	if (flags & GRE_RP) {
170127668Sbms		for (;;) {
171127668Sbms			u_int16_t af;
172127668Sbms			u_int8_t sreoff;
173127668Sbms			u_int8_t srelen;
17498524Sfenner
175127668Sbms			if (len < 4)
176127668Sbms				goto trunc;
177127668Sbms			af = EXTRACT_16BITS(bp);
178127668Sbms			sreoff = *(bp + 2);
179127668Sbms			srelen = *(bp + 3);
180127668Sbms			bp += 4;
181127668Sbms			len -= 4;
18298524Sfenner
183127668Sbms			if (af == 0 && srelen == 0)
184127668Sbms				break;
185127668Sbms
186127668Sbms			gre_sre_print(af, sreoff, srelen, bp, len);
187127668Sbms
188127668Sbms			if (len < srelen)
189127668Sbms				goto trunc;
190127668Sbms			bp += srelen;
191127668Sbms			len -= srelen;
19298524Sfenner		}
19398524Sfenner	}
194127668Sbms
195146773Ssam        if (eflag)
196146773Ssam            printf(", proto %s (0x%04x)",
197146773Ssam                   tok2str(ethertype_values,"unknown",prot),
198146773Ssam                   prot);
199146773Ssam
200146773Ssam        printf(", length %u",length);
201146773Ssam
202146773Ssam        if (vflag < 1)
203146773Ssam            printf(": "); /* put in a colon as protocol demarc */
204146773Ssam        else
205146773Ssam            printf("\n\t"); /* if verbose go multiline */
206146773Ssam
207127668Sbms	switch (prot) {
208146773Ssam	case ETHERTYPE_IP:
209146773Ssam	        ip_print(gndo, bp, len);
210127668Sbms		break;
211146773Ssam#ifdef INET6
212146773Ssam	case ETHERTYPE_IPV6:
213235530Sdelphij		ip6_print(gndo, bp, len);
214146773Ssam		break;
215146773Ssam#endif
216146773Ssam	case ETHERTYPE_MPLS:
217146773Ssam		mpls_print(bp, len);
218146773Ssam		break;
219146773Ssam	case ETHERTYPE_IPX:
220146773Ssam		ipx_print(bp, len);
221146773Ssam		break;
222146773Ssam	case ETHERTYPE_ATALK:
223146773Ssam		atalk_print(bp, len);
224146773Ssam		break;
225146773Ssam	case ETHERTYPE_GRE_ISO:
226127668Sbms		isoclns_print(bp, len, len);
227127668Sbms		break;
228214478Srpaulo	case ETHERTYPE_TEB:
229235530Sdelphij		ether_print(gndo, bp, len, len, NULL, NULL);
230214478Srpaulo		break;
231127668Sbms	default:
232127668Sbms		printf("gre-proto-0x%x", prot);
233127668Sbms	}
234127668Sbms	return;
235127668Sbms
236127668Sbmstrunc:
237127668Sbms	printf("[|gre]");
238127668Sbms}
239127668Sbms
240127668Sbmsvoid
241127668Sbmsgre_print_1(const u_char *bp, u_int length)
242127668Sbms{
243127668Sbms	u_int len = length;
244127668Sbms	u_int16_t flags, prot;
245127668Sbms
246127668Sbms	flags = EXTRACT_16BITS(bp);
247127668Sbms	len -= 2;
248127668Sbms	bp += 2;
249127668Sbms
250146773Ssam	if (vflag)
251146773Ssam            printf(", Flags [%s]",
252146773Ssam                   bittok2str(gre_flag_values,"none",flags));
253127668Sbms
254127668Sbms	if (len < 2)
255127668Sbms		goto trunc;
256127668Sbms	prot = EXTRACT_16BITS(bp);
257127668Sbms	len -= 2;
258127668Sbms	bp += 2;
259127668Sbms
260127668Sbms
26198524Sfenner	if (flags & GRE_KP) {
262127668Sbms		u_int32_t k;
263127668Sbms
264127668Sbms		if (len < 4)
265127668Sbms			goto trunc;
266127668Sbms		k = EXTRACT_32BITS(bp);
267146773Ssam		printf(", call %d", k & 0xffff);
268127668Sbms		len -= 4;
269127668Sbms		bp += 4;
27098524Sfenner	}
271127668Sbms
27298524Sfenner	if (flags & GRE_SP) {
273127668Sbms		if (len < 4)
274127668Sbms			goto trunc;
275146773Ssam		printf(", seq %u", EXTRACT_32BITS(bp));
276127668Sbms		bp += 4;
277127668Sbms		len -= 4;
27898524Sfenner	}
279127668Sbms
280127668Sbms	if (flags & GRE_AP) {
281127668Sbms		if (len < 4)
282127668Sbms			goto trunc;
283146773Ssam		printf(", ack %u", EXTRACT_32BITS(bp));
284127668Sbms		bp += 4;
285127668Sbms		len -= 4;
28698524Sfenner	}
287127668Sbms
288146773Ssam	if ((flags & GRE_SP) == 0)
289146773Ssam		printf(", no-payload");
29026180Sfenner
291146773Ssam        if (eflag)
292146773Ssam            printf(", proto %s (0x%04x)",
293146773Ssam                   tok2str(ethertype_values,"unknown",prot),
294146773Ssam                   prot);
295146773Ssam
296146773Ssam        printf(", length %u",length);
297146773Ssam
298146773Ssam        if ((flags & GRE_SP) == 0)
299146773Ssam            return;
300146773Ssam
301146773Ssam        if (vflag < 1)
302146773Ssam            printf(": "); /* put in a colon as protocol demarc */
303146773Ssam        else
304146773Ssam            printf("\n\t"); /* if verbose go multiline */
305146773Ssam
306127668Sbms	switch (prot) {
307146773Ssam	case ETHERTYPE_PPP:
308146773Ssam                ppp_print(bp, len);
309127668Sbms		break;
310127668Sbms	default:
311127668Sbms		printf("gre-proto-0x%x", prot);
312127668Sbms		break;
313127668Sbms	}
31426180Sfenner	return;
31526180Sfenner
31626180Sfennertrunc:
317127668Sbms	printf("[|gre]");
318127668Sbms}
31926180Sfenner
320127668Sbmsvoid
321127668Sbmsgre_sre_print(u_int16_t af, u_int8_t sreoff, u_int8_t srelen,
322127668Sbms    const u_char *bp, u_int len)
323127668Sbms{
324127668Sbms	switch (af) {
325127668Sbms	case GRESRE_IP:
326146773Ssam		printf(", (rtaf=ip");
327127668Sbms		gre_sre_ip_print(sreoff, srelen, bp, len);
328127668Sbms		printf(") ");
329127668Sbms		break;
330127668Sbms	case GRESRE_ASN:
331146773Ssam		printf(", (rtaf=asn");
332127668Sbms		gre_sre_asn_print(sreoff, srelen, bp, len);
333127668Sbms		printf(") ");
334127668Sbms		break;
335127668Sbms	default:
336146773Ssam		printf(", (rtaf=0x%x) ", af);
337127668Sbms	}
33826180Sfenner}
339127668Sbmsvoid
340127668Sbmsgre_sre_ip_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
341127668Sbms{
342127668Sbms	struct in_addr a;
343127668Sbms	const u_char *up = bp;
344127668Sbms
345127668Sbms	if (sreoff & 3) {
346146773Ssam		printf(", badoffset=%u", sreoff);
347127668Sbms		return;
348127668Sbms	}
349127668Sbms	if (srelen & 3) {
350146773Ssam		printf(", badlength=%u", srelen);
351127668Sbms		return;
352127668Sbms	}
353127668Sbms	if (sreoff >= srelen) {
354146773Ssam		printf(", badoff/len=%u/%u", sreoff, srelen);
355127668Sbms		return;
356127668Sbms	}
357127668Sbms
358127668Sbms	for (;;) {
359127668Sbms		if (len < 4 || srelen == 0)
360127668Sbms			return;
361127668Sbms
362127668Sbms		memcpy(&a, bp, sizeof(a));
363127668Sbms		printf(" %s%s",
364127668Sbms		    ((bp - up) == sreoff) ? "*" : "",
365127668Sbms		    inet_ntoa(a));
366127668Sbms
367127668Sbms		bp += 4;
368127668Sbms		len -= 4;
369127668Sbms		srelen -= 4;
370127668Sbms	}
371127668Sbms}
372127668Sbms
373127668Sbmsvoid
374127668Sbmsgre_sre_asn_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
375127668Sbms{
376127668Sbms	const u_char *up = bp;
377127668Sbms
378127668Sbms	if (sreoff & 1) {
379146773Ssam		printf(", badoffset=%u", sreoff);
380127668Sbms		return;
381127668Sbms	}
382127668Sbms	if (srelen & 1) {
383146773Ssam		printf(", badlength=%u", srelen);
384127668Sbms		return;
385127668Sbms	}
386127668Sbms	if (sreoff >= srelen) {
387146773Ssam		printf(", badoff/len=%u/%u", sreoff, srelen);
388127668Sbms		return;
389127668Sbms	}
390127668Sbms
391127668Sbms	for (;;) {
392127668Sbms		if (len < 2 || srelen == 0)
393127668Sbms			return;
394127668Sbms
395127668Sbms		printf(" %s%x",
396127668Sbms		    ((bp - up) == sreoff) ? "*" : "",
397127668Sbms		    EXTRACT_16BITS(bp));
398127668Sbms
399127668Sbms		bp += 2;
400127668Sbms		len -= 2;
401127668Sbms		srelen -= 2;
402127668Sbms	}
403127668Sbms}
404