summaryrefslogtreecommitdiff
path: root/print-gre.c
diff options
context:
space:
mode:
authoritojun <itojun>2002-09-20 22:42:21 +0000
committeritojun <itojun>2002-09-20 22:42:21 +0000
commit2c98bd5d6f08377f666629a784d3be018419edf2 (patch)
tree86a57c010db3d76aa5c0ff3a875da89164708137 /print-gre.c
parentc7a6e750ac1c57519b3f0975b7bf907534df67a0 (diff)
downloadtcpdump-2c98bd5d6f08377f666629a784d3be018419edf2.tar.gz
rewrite with better license (explicit "with or without modification").
from openbsd
Diffstat (limited to 'print-gre.c')
-rw-r--r--print-gre.c451
1 files changed, 325 insertions, 126 deletions
diff --git a/print-gre.c b/print-gre.c
index 3afa0eba..fc090a4a 100644
--- a/print-gre.c
+++ b/print-gre.c
@@ -1,30 +1,44 @@
+/* $OpenBSD: print-gre.c,v 1.5 2002/09/18 20:40:06 jason Exp $ */
+
/*
- * Copyright (c) 1996
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Lawrence Berkeley Laboratory,
- * Berkeley, CA. The name of the University may not be used to
- * endorse or promote products derived from this software without
- * specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
+ * All rights reserved.
*
- * Initial contribution from John Hawkinson <jhawk@bbnplanet.com>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Jason L. Wright
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
*
- * This module implements support for decoding GRE (Generic Routing
- * Encapsulation) tunnels; they're documented in RFC1701 and RFC1702.
- * This code only supports the IP encapsulation thereof.
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * tcpdump filter for GRE - Generic Routing Encapsulation
+ * RFC1701 (GRE), RFC1702 (GRE IPv4), and RFC2637 (Enhanced GRE)
*/
#ifndef lint
static const char rcsid[] =
- "@(#) $Header: /tcpdump/master/tcpdump/print-gre.c,v 1.16 2002-08-01 08:53:08 risso Exp $";
+ "@(#) $Header: /tcpdump/master/tcpdump/print-gre.c,v 1.17 2002-09-20 22:42:21 itojun Exp $ (LBL)";
#endif
#ifdef HAVE_CONFIG_H
@@ -34,137 +48,322 @@ static const char rcsid[] =
#include <tcpdump-stdinc.h>
#include <stdio.h>
+#include <string.h>
#include "interface.h"
#include "addrtoname.h"
-#include "extract.h" /* must come after interface.h */
+#include "extract.h"
-struct gre {
- u_int16_t flags;
- u_int16_t proto;
-};
+#include "ip.h"
-/* RFC 2784 - GRE */
-#define GRE_CP 0x8000 /* Checksum Present */
-#define GRE_VER_MASK 0x0007 /* Version */
+#define GRE_CP 0x8000 /* checksum present */
+#define GRE_RP 0x4000 /* routing present */
+#define GRE_KP 0x2000 /* key present */
+#define GRE_SP 0x1000 /* sequence# present */
+#define GRE_sP 0x0800 /* source routing */
+#define GRE_RECRS 0x0700 /* recursion count */
+#define GRE_AP 0x0080 /* acknowledgment# present */
+#define GRE_VERS 0x0007 /* protocol version */
-/* RFC 2890 - Key and Sequence extensions to GRE */
-#define GRE_KP 0x2000 /* Key Present */
-#define GRE_SP 0x1000 /* Sequence Present */
+#define GREPROTO_IP 0x0800 /* IP */
+#define GREPROTO_PPP 0x880b /* PPTP */
-/* Legacy from RFC 1700 */
-#define GRE_RP 0x4000 /* Routing Present */
-#define GRE_sP 0x0800 /* strict source route present */
-#define GRE_RECUR_MASK 0x0700 /* Recursion Control */
-#define GRE_RECUR_SHIFT 8
+/* source route entry types */
+#define GRESRE_IP 0x0800 /* IP */
+#define GRESRE_ASN 0xfffe /* ASN */
-#define GRE_COP (GRE_RP|GRE_CP) /* Checksum & Offset Present */
+void gre_print_0(const u_char *, u_int);
+void gre_print_1(const u_char *, u_int);
+void gre_sre_print(u_int16_t, u_int8_t, u_int8_t, const u_char *, u_int);
+void gre_sre_ip_print(u_int8_t, u_int8_t, const u_char *, u_int);
+void gre_sre_asn_print(u_int8_t, u_int8_t, const u_char *, u_int);
-/* "Enhanced GRE" from RFC2637 - PPTP */
-#define GRE_AP 0x0080 /* Ack present */
+void
+gre_print(const u_char *bp, u_int length)
+{
+ u_int len = length, vers;
-#define GRE_MBZ_MASK 0x0078 /* not defined */
+ if (len < 2) {
+ printf("[|gre]");
+ return;
+ }
+ vers = EXTRACT_16BITS(bp) & 7;
+
+ if (vers == 0)
+ gre_print_0(bp, len);
+ else if (vers == 1)
+ gre_print_1(bp, len);
+ else
+ printf("gre-unknown-version=%u", vers);
+ return;
+
+}
-/*
- * Deencapsulate and print a GRE-tunneled IP datagram
- */
void
-gre_print(const u_char *bp, u_int length)
+gre_print_0(const u_char *bp, u_int length)
{
- const u_char *cp = bp + 4;
- const struct gre *gre;
- u_int16_t flags, proto;
- u_short ver=0;
- u_short extracted_ethertype;
-
- gre = (const struct gre *)bp;
-
- TCHECK(gre->proto);
- flags = EXTRACT_16BITS(&gre->flags);
- proto = EXTRACT_16BITS(&gre->proto);
- (void)printf("gre ");
-
- if (flags) {
- /* Decode the flags */
- putchar('[');
- if (flags & GRE_CP)
- putchar('C');
- if (flags & GRE_RP)
- putchar('R');
- if (flags & GRE_KP)
- putchar('K');
- if (flags & GRE_SP)
- putchar('S');
- if (flags & GRE_sP)
- putchar('s');
- if (flags & GRE_AP)
- putchar('A');
- if (flags & GRE_RECUR_MASK)
- printf("R%x", (flags & GRE_RECUR_MASK) >> GRE_RECUR_SHIFT);
- ver = flags & GRE_VER_MASK;
- printf("v%u", ver);
-
- if (flags & GRE_MBZ_MASK)
- printf("!%x", flags & GRE_MBZ_MASK);
- fputs("] ", stdout);
- }
-
- if (flags & GRE_COP) {
- int checksum, offset;
-
- TCHECK2(*cp, 4);
- checksum = EXTRACT_16BITS(cp);
- offset = EXTRACT_16BITS(cp + 2);
-
- if (flags & GRE_CP) {
- /* Checksum present */
-
- /* todo: check checksum */
- if (vflag > 1)
- printf("C:%04x ", checksum);
- }
- if (flags & GRE_RP) {
- /* Offset present */
+ u_int len = length;
+ u_int16_t flags, prot;
- if (vflag > 1)
- printf("O:%04x ", offset);
- }
- cp += 4; /* skip checksum and offset */
+ flags = EXTRACT_16BITS(bp);
+ if (vflag) {
+ printf("[%s%s%s%s%s] ",
+ (flags & GRE_CP) ? "C" : "",
+ (flags & GRE_RP) ? "R" : "",
+ (flags & GRE_KP) ? "K" : "",
+ (flags & GRE_SP) ? "S" : "",
+ (flags & GRE_sP) ? "s" : "");
}
+
+ len -= 2;
+ bp += 2;
+
+ if (len < 2)
+ goto trunc;
+ prot = EXTRACT_16BITS(bp);
+ len -= 2;
+ bp += 2;
+
+ if ((flags & GRE_CP) | (flags & GRE_RP)) {
+ if (len < 2)
+ goto trunc;
+ if (vflag)
+ printf("sum 0x%x ", EXTRACT_16BITS(bp));
+ bp += 2;
+ len -= 2;
+
+ if (len < 2)
+ goto trunc;
+ printf("off 0x%x ", EXTRACT_16BITS(bp));
+ bp += 2;
+ len -= 2;
+ }
+
if (flags & GRE_KP) {
- TCHECK2(*cp, 4);
- if (ver == 1) { /* PPTP */
- if (vflag > 1)
- printf("PL:%u ", EXTRACT_16BITS(cp));
- printf("ID:%04x ", EXTRACT_16BITS(cp+2));
- }
- else
- printf("K:%08x ", EXTRACT_32BITS(cp));
- cp += 4; /* skip key */
+ if (len < 4)
+ goto trunc;
+ printf("key=0x%x ", EXTRACT_32BITS(bp));
+ bp += 4;
+ len -= 4;
}
+
if (flags & GRE_SP) {
- TCHECK2(*cp, 4);
- printf("S:%u ", EXTRACT_32BITS(cp));
- cp += 4; /* skip seq */
+ if (len < 4)
+ goto trunc;
+ printf("seq=0x%x ", EXTRACT_32BITS(bp));
+ bp += 4;
+ len -= 4;
}
- if (flags & GRE_AP && ver >= 1) {
- TCHECK2(*cp, 4);
- printf("A:%u ", EXTRACT_32BITS(cp));
- cp += 4; /* skip ack */
+
+ if (flags & GRE_RP) {
+ for (;;) {
+ u_int16_t af;
+ u_int8_t sreoff;
+ u_int8_t srelen;
+
+ if (len < 4)
+ goto trunc;
+ af = EXTRACT_16BITS(bp);
+ sreoff = *(bp + 2);
+ srelen = *(bp + 3);
+ bp += 4;
+ len -= 4;
+
+ if (af == 0 && srelen == 0)
+ break;
+
+ gre_sre_print(af, sreoff, srelen, bp, len);
+
+ if (len < srelen)
+ goto trunc;
+ bp += srelen;
+ len -= srelen;
+ }
+ }
+
+ switch (prot) {
+ case GREPROTO_IP:
+ ip_print(bp, len);
+ break;
+ default:
+ printf("gre-proto-0x%x", prot);
}
- /* We don't support routing fields (variable length) now. Punt. */
- if (flags & GRE_RP)
+ return;
+
+trunc:
+ printf("[|gre]");
+}
+
+void
+gre_print_1(const u_char *bp, u_int length)
+{
+ u_int len = length;
+ u_int16_t flags, prot;
+
+ flags = EXTRACT_16BITS(bp);
+ len -= 2;
+ bp += 2;
+
+ if (vflag) {
+ printf("[%s%s%s%s%s%s] ",
+ (flags & GRE_CP) ? "C" : "",
+ (flags & GRE_RP) ? "R" : "",
+ (flags & GRE_KP) ? "K" : "",
+ (flags & GRE_SP) ? "S" : "",
+ (flags & GRE_sP) ? "s" : "",
+ (flags & GRE_AP) ? "A" : "");
+ }
+
+ if (len < 2)
+ goto trunc;
+ prot = EXTRACT_16BITS(bp);
+ len -= 2;
+ bp += 2;
+
+ if (flags & GRE_CP) {
+ printf("cpset! ");
return;
+ }
+ if (flags & GRE_RP) {
+ printf("rpset! ");
+ return;
+ }
+ if ((flags & GRE_KP) != 0) {
+ printf("kpunset! ");
+ return;
+ }
+ if (flags & GRE_sP) {
+ printf("spset! ");
+ return;
+ }
- TCHECK(cp[0]);
+ if (flags & GRE_KP) {
+ u_int32_t k;
+
+ if (len < 4)
+ goto trunc;
+ k = EXTRACT_32BITS(bp);
+ printf("key=0x%x call=0x%x ", (k >> 16) & 0xffff, k & 0xffff);
+ len -= 4;
+ bp += 4;
+ }
- length -= cp - bp;
- if (ether_encap_print(proto, cp, length, length,
- &extracted_ethertype) == 0)
- printf("gre-proto-0x%04X", proto);
+ if (flags & GRE_SP) {
+ if (len < 4)
+ goto trunc;
+ printf("seq=0x%x ", EXTRACT_32BITS(bp));
+ bp += 4;
+ len -= 4;
+ }
+
+ if (flags & GRE_AP) {
+ if (len < 4)
+ goto trunc;
+ printf("ack=0x%x ", EXTRACT_32BITS(bp));
+ bp += 4;
+ len -= 4;
+ }
+
+ if ((flags & GRE_SP) == 0) {
+ printf("no-payload ");
+ return;
+ }
+
+ switch (prot) {
+ case GREPROTO_PPP:
+ printf("gre-ppp-payload ");
+ break;
+ default:
+ printf("gre-proto-0x%x ", prot);
+ break;
+ }
return;
trunc:
- fputs("[|gre]", stdout);
+ printf("[|gre]");
+}
+
+void
+gre_sre_print(u_int16_t af, u_int8_t sreoff, u_int8_t srelen,
+ const u_char *bp, u_int len)
+{
+ switch (af) {
+ case GRESRE_IP:
+ printf("(rtaf=ip");
+ gre_sre_ip_print(sreoff, srelen, bp, len);
+ printf(") ");
+ break;
+ case GRESRE_ASN:
+ printf("(rtaf=asn");
+ gre_sre_asn_print(sreoff, srelen, bp, len);
+ printf(") ");
+ break;
+ default:
+ printf("(rtaf=0x%x) ", af);
+ }
+}
+void
+gre_sre_ip_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
+{
+ struct in_addr a;
+ const u_char *up = bp;
+ if (sreoff & 3) {
+ printf(" badoffset=%u", sreoff);
+ return;
+ }
+ if (srelen & 3) {
+ printf(" badlength=%u", srelen);
+ return;
+ }
+ if (sreoff >= srelen) {
+ printf(" badoff/len=%u/%u", sreoff, srelen);
+ return;
+ }
+
+ for (;;) {
+ if (len < 4 || srelen == 0)
+ return;
+
+ memcpy(&a, bp, sizeof(a));
+ printf(" %s%s",
+ ((bp - up) == sreoff) ? "*" : "",
+ inet_ntoa(a));
+
+ bp += 4;
+ len -= 4;
+ srelen -= 4;
+ }
+}
+
+void
+gre_sre_asn_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len)
+{
+ const u_char *up = bp;
+
+ if (sreoff & 1) {
+ printf(" badoffset=%u", sreoff);
+ return;
+ }
+ if (srelen & 1) {
+ printf(" badlength=%u", srelen);
+ return;
+ }
+ if (sreoff >= srelen) {
+ printf(" badoff/len=%u/%u", sreoff, srelen);
+ return;
+ }
+
+ for (;;) {
+ if (len < 2 || srelen == 0)
+ return;
+
+ printf(" %s%x",
+ ((bp - up) == sreoff) ? "*" : "",
+ EXTRACT_16BITS(bp));
+
+ bp += 2;
+ len -= 2;
+ srelen -= 2;
+ }
}