1 /* $OpenBSD: print-gre.c,v 1.19 2018/02/24 08:53:36 dlg 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 * 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 /* 30 * tcpdump filter for GRE - Generic Routing Encapsulation 31 * RFC1701 (GRE), RFC1702 (GRE IPv4), and RFC2637 (Enhanced GRE) 32 */ 33 34 #include <sys/time.h> 35 #include <sys/uio.h> 36 #include <sys/socket.h> 37 38 #include <netinet/in.h> 39 #include <netinet/ip.h> 40 #include <arpa/inet.h> 41 42 #include <net/ethertypes.h> 43 44 #include <stdio.h> 45 #include <string.h> 46 47 #include "interface.h" 48 #include "addrtoname.h" 49 #include "extract.h" 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_RECRS 0x0700 /* recursion count */ 57 #define GRE_AP 0x0080 /* acknowledgment# present */ 58 #define GRE_VERS 0x0007 /* protocol version */ 59 60 /* source route entry types */ 61 #define GRESRE_IP 0x0800 /* IP */ 62 #define GRESRE_ASN 0xfffe /* ASN */ 63 64 #define NVGRE_VSID_MASK 0xffffff00U 65 #define NVGRE_VSID_SHIFT 8 66 #define NVGRE_FLOWID_MASK 0x000000ffU 67 #define NVGRE_FLOWID_SHIFT 0 68 69 #define GRE_WCCP 0x883e 70 71 struct wccp_redirect { 72 uint8_t flags; 73 #define WCCP_D (1 << 7) 74 #define WCCP_A (1 << 6) 75 uint8_t ServiceId; 76 uint8_t AltBucket; 77 uint8_t PriBucket; 78 }; 79 80 void gre_print_0(const u_char *, u_int); 81 void gre_print_1(const u_char *, u_int); 82 void gre_sre_print(u_int16_t, u_int8_t, u_int8_t, const u_char *, u_int); 83 void gre_sre_ip_print(u_int8_t, u_int8_t, const u_char *, u_int); 84 void gre_sre_asn_print(u_int8_t, u_int8_t, const u_char *, u_int); 85 86 void 87 gre_print(const u_char *p, u_int length) 88 { 89 uint16_t vers; 90 int l; 91 92 l = snapend - p; 93 94 if (l < sizeof(vers)) { 95 printf("[|gre]"); 96 return; 97 } 98 vers = EXTRACT_16BITS(p) & GRE_VERS; 99 100 switch (vers) { 101 case 0: 102 gre_print_0(p, length); 103 break; 104 case 1: 105 gre_print_1(p, length); 106 break; 107 default: 108 printf("gre-unknown-version=%u", vers); 109 break; 110 } 111 } 112 113 void 114 gre_print_0(const u_char *p, u_int length) 115 { 116 uint16_t flags, proto; 117 u_int l; 118 119 l = snapend - p; 120 121 flags = EXTRACT_16BITS(p); 122 p += sizeof(flags); 123 l -= sizeof(flags); 124 length -= sizeof(flags); 125 126 printf("gre"); 127 128 if (vflag) { 129 printf(" [%s%s%s%s%s]", 130 (flags & GRE_CP) ? "C" : "", 131 (flags & GRE_RP) ? "R" : "", 132 (flags & GRE_KP) ? "K" : "", 133 (flags & GRE_SP) ? "S" : "", 134 (flags & GRE_sP) ? "s" : ""); 135 } 136 137 if (l < sizeof(proto)) 138 goto trunc; 139 proto = EXTRACT_16BITS(p); 140 p += sizeof(proto); 141 l -= sizeof(proto); 142 length -= sizeof(proto); 143 144 if ((flags & GRE_CP) | (flags & GRE_RP)) { 145 if (l < 2) 146 goto trunc; 147 if ((flags & GRE_CP) && vflag) 148 printf(" sum 0x%x", EXTRACT_16BITS(p)); 149 p += 2; 150 l -= 2; 151 length -= 2; 152 153 if (l < 2) 154 goto trunc; 155 if (flags & GRE_RP) 156 printf(" off 0x%x", EXTRACT_16BITS(p)); 157 p += 2; 158 l -= 2; 159 length -= 2; 160 } 161 162 if (flags & GRE_KP) { 163 uint32_t key, vsid; 164 165 if (l < sizeof(key)) 166 goto trunc; 167 key = EXTRACT_32BITS(p); 168 p += sizeof(key); 169 l -= sizeof(key); 170 length -= sizeof(key); 171 172 /* maybe NVGRE, or key entropy? */ 173 vsid = (key & NVGRE_VSID_MASK) >> NVGRE_VSID_SHIFT; 174 printf(" key=%u|%u+%02x", key, vsid, 175 (key & NVGRE_FLOWID_MASK) >> NVGRE_FLOWID_SHIFT); 176 } 177 178 if (flags & GRE_SP) { 179 if (l < 4) 180 goto trunc; 181 printf(" seq %u", EXTRACT_32BITS(p)); 182 p += 4; 183 l -= 4; 184 length -= 4; 185 } 186 187 if (flags & GRE_RP) { 188 for (;;) { 189 u_int16_t af; 190 u_int8_t sreoff; 191 u_int8_t srelen; 192 193 if (l < 4) 194 goto trunc; 195 af = EXTRACT_16BITS(p); 196 sreoff = *(p + 2); 197 srelen = *(p + 3); 198 p += 4; 199 l -= 4; 200 length -= 4; 201 202 if (af == 0 && srelen == 0) 203 break; 204 205 gre_sre_print(af, sreoff, srelen, p, l); 206 207 if (l < srelen) 208 goto trunc; 209 p += srelen; 210 l -= srelen; 211 length -= srelen; 212 } 213 } 214 215 printf(" "); 216 217 switch (proto) { 218 case 0: 219 printf("keep-alive"); 220 break; 221 case GRE_WCCP: { 222 printf("wccp "); 223 224 if (l == 0) 225 return; 226 227 if (*p >> 4 != 4) { 228 struct wccp_redirect *wccp; 229 230 if (l < sizeof(*wccp)) { 231 printf("[|wccp]"); 232 return; 233 } 234 235 wccp = (struct wccp_redirect *)p; 236 237 printf("D:%c A:%c SId:%u Alt:%u Pri:%u", 238 (wccp->flags & WCCP_D) ? '1' : '0', 239 (wccp->flags & WCCP_A) ? '1' : '0', 240 wccp->ServiceId, wccp->AltBucket, wccp->PriBucket); 241 242 p += sizeof(*wccp); 243 l -= sizeof(*wccp); 244 245 printf(": "); 246 } 247 248 /* FALLTHROUGH */ 249 } 250 case ETHERTYPE_IP: 251 ip_print(p, length); 252 break; 253 case ETHERTYPE_IPV6: 254 ip6_print(p, length); 255 break; 256 case ETHERTYPE_MPLS: 257 mpls_print(p, length); 258 break; 259 case ETHERTYPE_TRANSETHER: 260 ether_tryprint(p, length, 0); 261 break; 262 default: 263 printf("unknown-proto-%04x", proto); 264 } 265 return; 266 267 trunc: 268 printf("[|gre]"); 269 } 270 271 void 272 gre_print_1(const u_char *p, u_int length) 273 { 274 uint16_t flags, proto, len; 275 int l; 276 277 l = snapend - p; 278 279 flags = EXTRACT_16BITS(p); 280 p += sizeof(flags); 281 l -= sizeof(flags); 282 length -= sizeof(flags); 283 284 printf("pptp"); 285 286 if (vflag) { 287 printf(" [%s%s%s%s%s%s] ", 288 (flags & GRE_CP) ? "C" : "", 289 (flags & GRE_RP) ? "R" : "", 290 (flags & GRE_KP) ? "K" : "", 291 (flags & GRE_SP) ? "S" : "", 292 (flags & GRE_sP) ? "s" : "", 293 (flags & GRE_AP) ? "A" : ""); 294 } 295 296 if (l < sizeof(proto)) 297 goto trunc; 298 299 proto = EXTRACT_16BITS(p); 300 p += sizeof(proto); 301 l -= sizeof(proto); 302 length -= sizeof(proto); 303 304 if (flags & GRE_CP) { 305 printf(" cpset!"); 306 return; 307 } 308 if (flags & GRE_RP) { 309 printf(" rpset!"); 310 return; 311 } 312 if ((flags & GRE_KP) == 0) { 313 printf(" kpunset!"); 314 return; 315 } 316 if (flags & GRE_sP) { 317 printf(" spset!"); 318 return; 319 } 320 321 /* GRE_KP */ 322 if (l < sizeof(len)) 323 goto trunc; 324 len = EXTRACT_16BITS(p); 325 p += sizeof(len); 326 l -= sizeof(len); 327 length -= sizeof(len); 328 329 if (vflag) 330 printf(" len %u", EXTRACT_16BITS(p)); 331 332 if (l < 2) 333 goto trunc; 334 printf(" callid %u", EXTRACT_16BITS(p)); 335 p += 2; 336 l -= 2; 337 length -= 2; 338 339 if (flags & GRE_SP) { 340 if (l < 4) 341 goto trunc; 342 printf(" seq %u", EXTRACT_32BITS(p)); 343 p += 4; 344 l -= 4; 345 length -= 4; 346 } 347 348 if (flags & GRE_AP) { 349 if (l < 4) 350 goto trunc; 351 printf(" ack %u", EXTRACT_32BITS(p)); 352 p += 4; 353 l -= 4; 354 length -= 4; 355 } 356 357 if ((flags & GRE_SP) == 0) 358 return; 359 360 if (length < len) { 361 (void)printf(" truncated-pptp - %d bytes missing!", 362 len - length); 363 len = length; 364 } 365 366 printf(": "); 367 368 switch (proto) { 369 case ETHERTYPE_PPP: 370 ppp_hdlc_print(p, len); 371 break; 372 default: 373 printf("unknown-proto-%04x", proto); 374 break; 375 } 376 return; 377 378 trunc: 379 printf("[|pptp]"); 380 } 381 382 void 383 gre_sre_print(u_int16_t af, u_int8_t sreoff, u_int8_t srelen, 384 const u_char *bp, u_int len) 385 { 386 switch (af) { 387 case GRESRE_IP: 388 printf(" (rtaf=ip"); 389 gre_sre_ip_print(sreoff, srelen, bp, len); 390 printf(")"); 391 break; 392 case GRESRE_ASN: 393 printf(" (rtaf=asn"); 394 gre_sre_asn_print(sreoff, srelen, bp, len); 395 printf(")"); 396 break; 397 default: 398 printf(" (rtaf=0x%x)", af); 399 } 400 } 401 void 402 gre_sre_ip_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len) 403 { 404 struct in_addr a; 405 const u_char *up = bp; 406 407 if (sreoff & 3) { 408 printf(" badoffset=%u", sreoff); 409 return; 410 } 411 if (srelen & 3) { 412 printf(" badlength=%u", srelen); 413 return; 414 } 415 if (sreoff >= srelen) { 416 printf(" badoff/len=%u/%u", sreoff, srelen); 417 return; 418 } 419 420 for (;;) { 421 if (len < 4 || srelen == 0) 422 return; 423 424 memcpy(&a, bp, sizeof(a)); 425 printf(" %s%s", 426 ((bp - up) == sreoff) ? "*" : "", 427 inet_ntoa(a)); 428 429 bp += 4; 430 len -= 4; 431 srelen -= 4; 432 } 433 } 434 435 void 436 gre_sre_asn_print(u_int8_t sreoff, u_int8_t srelen, const u_char *bp, u_int len) 437 { 438 const u_char *up = bp; 439 440 if (sreoff & 1) { 441 printf(" badoffset=%u", sreoff); 442 return; 443 } 444 if (srelen & 1) { 445 printf(" badlength=%u", srelen); 446 return; 447 } 448 if (sreoff >= srelen) { 449 printf(" badoff/len=%u/%u", sreoff, srelen); 450 return; 451 } 452 453 for (;;) { 454 if (len < 2 || srelen == 0) 455 return; 456 457 printf(" %s%x", 458 ((bp - up) == sreoff) ? "*" : "", 459 EXTRACT_16BITS(bp)); 460 461 bp += 2; 462 len -= 2; 463 srelen -= 2; 464 } 465 } 466