Home | History | Annotate | Download | only in tcpdump
      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 (at) 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 /* \summary: Generic Routing Encapsulation (GRE) printer */
     35 
     36 /*
     37  * netdissect printer for GRE - Generic Routing Encapsulation
     38  * RFC1701 (GRE), RFC1702 (GRE IPv4), and RFC2637 (Enhanced GRE)
     39  */
     40 
     41 #ifdef HAVE_CONFIG_H
     42 #include "config.h"
     43 #endif
     44 
     45 #include <netdissect-stdinc.h>
     46 
     47 #include <string.h>
     48 
     49 #include "netdissect.h"
     50 #include "addrtostr.h"
     51 #include "extract.h"
     52 #include "ethertype.h"
     53 
     54 static const char tstr[] = "[|gre]";
     55 
     56 #define	GRE_CP		0x8000		/* checksum present */
     57 #define	GRE_RP		0x4000		/* routing present */
     58 #define	GRE_KP		0x2000		/* key present */
     59 #define	GRE_SP		0x1000		/* sequence# present */
     60 #define	GRE_sP		0x0800		/* source routing */
     61 #define	GRE_RECRS	0x0700		/* recursion count */
     62 #define	GRE_AP		0x0080		/* acknowledgment# present */
     63 
     64 static const struct tok gre_flag_values[] = {
     65     { GRE_CP, "checksum present"},
     66     { GRE_RP, "routing present"},
     67     { GRE_KP, "key present"},
     68     { GRE_SP, "sequence# present"},
     69     { GRE_sP, "source routing present"},
     70     { GRE_RECRS, "recursion count"},
     71     { GRE_AP, "ack present"},
     72     { 0, NULL }
     73 };
     74 
     75 #define	GRE_VERS_MASK	0x0007		/* protocol version */
     76 
     77 /* source route entry types */
     78 #define	GRESRE_IP	0x0800		/* IP */
     79 #define	GRESRE_ASN	0xfffe		/* ASN */
     80 
     81 static void gre_print_0(netdissect_options *, const u_char *, u_int);
     82 static void gre_print_1(netdissect_options *, const u_char *, u_int);
     83 static int gre_sre_print(netdissect_options *, uint16_t, uint8_t, uint8_t, const u_char *, u_int);
     84 static int gre_sre_ip_print(netdissect_options *, uint8_t, uint8_t, const u_char *, u_int);
     85 static int gre_sre_asn_print(netdissect_options *, uint8_t, uint8_t, const u_char *, u_int);
     86 
     87 void
     88 gre_print(netdissect_options *ndo, const u_char *bp, u_int length)
     89 {
     90 	u_int len = length, vers;
     91 
     92 	ND_TCHECK2(*bp, 2);
     93 	if (len < 2)
     94 		goto trunc;
     95 	vers = EXTRACT_16BITS(bp) & GRE_VERS_MASK;
     96         ND_PRINT((ndo, "GREv%u",vers));
     97 
     98         switch(vers) {
     99         case 0:
    100             gre_print_0(ndo, bp, len);
    101             break;
    102         case 1:
    103             gre_print_1(ndo, bp, len);
    104             break;
    105 	default:
    106             ND_PRINT((ndo, " ERROR: unknown-version"));
    107             break;
    108         }
    109         return;
    110 
    111 trunc:
    112 	ND_PRINT((ndo, "%s", tstr));
    113 	return;
    114 }
    115 
    116 static void
    117 gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length)
    118 {
    119 	u_int len = length;
    120 	uint16_t flags, prot;
    121 
    122 	flags = EXTRACT_16BITS(bp);
    123         if (ndo->ndo_vflag)
    124             ND_PRINT((ndo, ", Flags [%s]",
    125                    bittok2str(gre_flag_values,"none",flags)));
    126 
    127 	len -= 2;
    128 	bp += 2;
    129 
    130 	ND_TCHECK2(*bp, 2);
    131 	if (len < 2)
    132 		goto trunc;
    133 	prot = EXTRACT_16BITS(bp);
    134 	len -= 2;
    135 	bp += 2;
    136 
    137 	if ((flags & GRE_CP) | (flags & GRE_RP)) {
    138 		ND_TCHECK2(*bp, 2);
    139 		if (len < 2)
    140 			goto trunc;
    141 		if (ndo->ndo_vflag)
    142 			ND_PRINT((ndo, ", sum 0x%x", EXTRACT_16BITS(bp)));
    143 		bp += 2;
    144 		len -= 2;
    145 
    146 		ND_TCHECK2(*bp, 2);
    147 		if (len < 2)
    148 			goto trunc;
    149 		ND_PRINT((ndo, ", off 0x%x", EXTRACT_16BITS(bp)));
    150 		bp += 2;
    151 		len -= 2;
    152 	}
    153 
    154 	if (flags & GRE_KP) {
    155 		ND_TCHECK2(*bp, 4);
    156 		if (len < 4)
    157 			goto trunc;
    158 		ND_PRINT((ndo, ", key=0x%x", EXTRACT_32BITS(bp)));
    159 		bp += 4;
    160 		len -= 4;
    161 	}
    162 
    163 	if (flags & GRE_SP) {
    164 		ND_TCHECK2(*bp, 4);
    165 		if (len < 4)
    166 			goto trunc;
    167 		ND_PRINT((ndo, ", seq %u", EXTRACT_32BITS(bp)));
    168 		bp += 4;
    169 		len -= 4;
    170 	}
    171 
    172 	if (flags & GRE_RP) {
    173 		for (;;) {
    174 			uint16_t af;
    175 			uint8_t sreoff;
    176 			uint8_t srelen;
    177 
    178 			ND_TCHECK2(*bp, 4);
    179 			if (len < 4)
    180 				goto trunc;
    181 			af = EXTRACT_16BITS(bp);
    182 			sreoff = *(bp + 2);
    183 			srelen = *(bp + 3);
    184 			bp += 4;
    185 			len -= 4;
    186 
    187 			if (af == 0 && srelen == 0)
    188 				break;
    189 
    190 			if (!gre_sre_print(ndo, af, sreoff, srelen, bp, len))
    191 				goto trunc;
    192 
    193 			if (len < srelen)
    194 				goto trunc;
    195 			bp += srelen;
    196 			len -= srelen;
    197 		}
    198 	}
    199 
    200         if (ndo->ndo_eflag)
    201             ND_PRINT((ndo, ", proto %s (0x%04x)",
    202                    tok2str(ethertype_values,"unknown",prot),
    203                    prot));
    204 
    205         ND_PRINT((ndo, ", length %u",length));
    206 
    207         if (ndo->ndo_vflag < 1)
    208             ND_PRINT((ndo, ": ")); /* put in a colon as protocol demarc */
    209         else
    210             ND_PRINT((ndo, "\n\t")); /* if verbose go multiline */
    211 
    212 	switch (prot) {
    213 	case ETHERTYPE_IP:
    214 	        ip_print(ndo, bp, len);
    215 		break;
    216 	case ETHERTYPE_IPV6:
    217 		ip6_print(ndo, bp, len);
    218 		break;
    219 	case ETHERTYPE_MPLS:
    220 		mpls_print(ndo, bp, len);
    221 		break;
    222 	case ETHERTYPE_IPX:
    223 		ipx_print(ndo, bp, len);
    224 		break;
    225 	case ETHERTYPE_ATALK:
    226 		atalk_print(ndo, bp, len);
    227 		break;
    228 	case ETHERTYPE_GRE_ISO:
    229 		isoclns_print(ndo, bp, len);
    230 		break;
    231 	case ETHERTYPE_TEB:
    232 		ether_print(ndo, bp, len, ndo->ndo_snapend - bp, NULL, NULL);
    233 		break;
    234 	default:
    235 		ND_PRINT((ndo, "gre-proto-0x%x", prot));
    236 	}
    237 	return;
    238 
    239 trunc:
    240 	ND_PRINT((ndo, "%s", tstr));
    241 }
    242 
    243 static void
    244 gre_print_1(netdissect_options *ndo, const u_char *bp, u_int length)
    245 {
    246 	u_int len = length;
    247 	uint16_t flags, prot;
    248 
    249 	flags = EXTRACT_16BITS(bp);
    250 	len -= 2;
    251 	bp += 2;
    252 
    253 	if (ndo->ndo_vflag)
    254             ND_PRINT((ndo, ", Flags [%s]",
    255                    bittok2str(gre_flag_values,"none",flags)));
    256 
    257 	ND_TCHECK2(*bp, 2);
    258 	if (len < 2)
    259 		goto trunc;
    260 	prot = EXTRACT_16BITS(bp);
    261 	len -= 2;
    262 	bp += 2;
    263 
    264 
    265 	if (flags & GRE_KP) {
    266 		uint32_t k;
    267 
    268 		ND_TCHECK2(*bp, 4);
    269 		if (len < 4)
    270 			goto trunc;
    271 		k = EXTRACT_32BITS(bp);
    272 		ND_PRINT((ndo, ", call %d", k & 0xffff));
    273 		len -= 4;
    274 		bp += 4;
    275 	}
    276 
    277 	if (flags & GRE_SP) {
    278 		ND_TCHECK2(*bp, 4);
    279 		if (len < 4)
    280 			goto trunc;
    281 		ND_PRINT((ndo, ", seq %u", EXTRACT_32BITS(bp)));
    282 		bp += 4;
    283 		len -= 4;
    284 	}
    285 
    286 	if (flags & GRE_AP) {
    287 		ND_TCHECK2(*bp, 4);
    288 		if (len < 4)
    289 			goto trunc;
    290 		ND_PRINT((ndo, ", ack %u", EXTRACT_32BITS(bp)));
    291 		bp += 4;
    292 		len -= 4;
    293 	}
    294 
    295 	if ((flags & GRE_SP) == 0)
    296 		ND_PRINT((ndo, ", no-payload"));
    297 
    298         if (ndo->ndo_eflag)
    299             ND_PRINT((ndo, ", proto %s (0x%04x)",
    300                    tok2str(ethertype_values,"unknown",prot),
    301                    prot));
    302 
    303         ND_PRINT((ndo, ", length %u",length));
    304 
    305         if ((flags & GRE_SP) == 0)
    306             return;
    307 
    308         if (ndo->ndo_vflag < 1)
    309             ND_PRINT((ndo, ": ")); /* put in a colon as protocol demarc */
    310         else
    311             ND_PRINT((ndo, "\n\t")); /* if verbose go multiline */
    312 
    313 	switch (prot) {
    314 	case ETHERTYPE_PPP:
    315 		ppp_print(ndo, bp, len);
    316 		break;
    317 	default:
    318 		ND_PRINT((ndo, "gre-proto-0x%x", prot));
    319 		break;
    320 	}
    321 	return;
    322 
    323 trunc:
    324 	ND_PRINT((ndo, "%s", tstr));
    325 }
    326 
    327 static int
    328 gre_sre_print(netdissect_options *ndo, uint16_t af, uint8_t sreoff,
    329     uint8_t srelen, const u_char *bp, u_int len)
    330 {
    331 	int ret;
    332 
    333 	switch (af) {
    334 	case GRESRE_IP:
    335 		ND_PRINT((ndo, ", (rtaf=ip"));
    336 		ret = gre_sre_ip_print(ndo, sreoff, srelen, bp, len);
    337 		ND_PRINT((ndo, ")"));
    338 		break;
    339 	case GRESRE_ASN:
    340 		ND_PRINT((ndo, ", (rtaf=asn"));
    341 		ret = gre_sre_asn_print(ndo, sreoff, srelen, bp, len);
    342 		ND_PRINT((ndo, ")"));
    343 		break;
    344 	default:
    345 		ND_PRINT((ndo, ", (rtaf=0x%x)", af));
    346 		ret = 1;
    347 	}
    348 	return (ret);
    349 }
    350 
    351 static int
    352 gre_sre_ip_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
    353                  const u_char *bp, u_int len)
    354 {
    355 	const u_char *up = bp;
    356 	char buf[INET_ADDRSTRLEN];
    357 
    358 	if (sreoff & 3) {
    359 		ND_PRINT((ndo, ", badoffset=%u", sreoff));
    360 		return (1);
    361 	}
    362 	if (srelen & 3) {
    363 		ND_PRINT((ndo, ", badlength=%u", srelen));
    364 		return (1);
    365 	}
    366 	if (sreoff >= srelen) {
    367 		ND_PRINT((ndo, ", badoff/len=%u/%u", sreoff, srelen));
    368 		return (1);
    369 	}
    370 
    371 	while (srelen != 0) {
    372 		if (!ND_TTEST2(*bp, 4))
    373 			return (0);
    374 		if (len < 4)
    375 			return (0);
    376 
    377 		addrtostr(bp, buf, sizeof(buf));
    378 		ND_PRINT((ndo, " %s%s",
    379 		    ((bp - up) == sreoff) ? "*" : "", buf));
    380 
    381 		bp += 4;
    382 		len -= 4;
    383 		srelen -= 4;
    384 	}
    385 	return (1);
    386 }
    387 
    388 static int
    389 gre_sre_asn_print(netdissect_options *ndo, uint8_t sreoff, uint8_t srelen,
    390                   const u_char *bp, u_int len)
    391 {
    392 	const u_char *up = bp;
    393 
    394 	if (sreoff & 1) {
    395 		ND_PRINT((ndo, ", badoffset=%u", sreoff));
    396 		return (1);
    397 	}
    398 	if (srelen & 1) {
    399 		ND_PRINT((ndo, ", badlength=%u", srelen));
    400 		return (1);
    401 	}
    402 	if (sreoff >= srelen) {
    403 		ND_PRINT((ndo, ", badoff/len=%u/%u", sreoff, srelen));
    404 		return (1);
    405 	}
    406 
    407 	while (srelen != 0) {
    408 		if (!ND_TTEST2(*bp, 2))
    409 			return (0);
    410 		if (len < 2)
    411 			return (0);
    412 
    413 		ND_PRINT((ndo, " %s%x",
    414 		    ((bp - up) == sreoff) ? "*" : "",
    415 		    EXTRACT_16BITS(bp)));
    416 
    417 		bp += 2;
    418 		len -= 2;
    419 		srelen -= 2;
    420 	}
    421 	return (1);
    422 }
    423