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