X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/ef5323efe6c03aaa50eac0949bf95999b91fe05b..HEAD:/print-gre.c diff --git a/print-gre.c b/print-gre.c index 136fb69d..1d545b3f 100644 --- a/print-gre.c +++ b/print-gre.c @@ -30,12 +30,21 @@ /* * netdissect printer for GRE - Generic Routing Encapsulation - * RFC1701 (GRE), RFC1702 (GRE IPv4), and RFC2637 (Enhanced GRE) + * RFC 1701 (GRE), RFC 1702 (GRE IPv4), RFC 2637 (PPTP, which + * has an extended form of GRE), RFC 2784 (revised GRE, with + * R, K, S, and s bits and Recur and Offset fields now reserved + * in the header, and no optional Key or Sequence number in the + * header), and RFC 2890 (proposal to add back the K and S bits + * and the optional Key and Sequence number). + * + * The RFC 2637 PPTP GRE repurposes the Key field to hold a + * 16-bit Payload Length and a 16-bit Call ID. + * + * RFC 7637 (NVGRE) repurposes the Key field to hold a 24-bit + * Virtual Subnet ID (VSID) and an 8-bit FlowID. */ -#ifdef HAVE_CONFIG_H #include -#endif #include "netdissect-stdinc.h" @@ -44,14 +53,7 @@ #include "addrtostr.h" #include "extract.h" #include "ethertype.h" - - -#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_AP 0x0080 /* acknowledgment# present */ +#include "gre.h" static const struct tok gre_flag_values[] = { { GRE_CP, "checksum present"}, @@ -70,6 +72,26 @@ static const struct tok gre_flag_values[] = { #define GRESRE_IP 0x0800 /* IP */ #define GRESRE_ASN 0xfffe /* ASN */ +/* + * Ethertype values used for GRE (but not elsewhere?). + */ +#define GRE_CDP 0x2000 /* Cisco Discovery Protocol */ +#define GRE_NHRP 0x2001 /* Next Hop Resolution Protocol */ +#define GRE_MIKROTIK_EOIP 0x6400 /* MikroTik RouterBoard Ethernet over IP (EoIP) */ +#define GRE_ERSPAN_III 0x22eb +#define GRE_WCCP 0x883e /* Web Cache C* Protocol */ +#define GRE_ERSPAN_I_II 0x88be + +struct wccp_redirect { + nd_uint8_t flags; +#define WCCP_T (1 << 7) +#define WCCP_A (1 << 6) +#define WCCP_U (1 << 5) + nd_uint8_t ServiceId; + nd_uint8_t AltBucket; + nd_uint8_t PriBucket; +}; + static void gre_print_0(netdissect_options *, const u_char *, u_int); static void gre_print_1(netdissect_options *, const u_char *, u_int); static int gre_sre_print(netdissect_options *, uint16_t, uint8_t, uint8_t, const u_char *, u_int); @@ -141,10 +163,21 @@ gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length) } if (flags & GRE_KP) { + uint32_t key; + ND_ICHECK_U(len, <, 4); - ND_PRINT(", key=0x%x", GET_BE_U_4(bp)); + key = GET_BE_U_4(bp); bp += 4; len -= 4; + + /* + * OpenBSD shows this as both a 32-bit + * (decimal) key value and a VSID+FlowID + * pair, with the VSID in decimal and + * the FlowID in hex, as key=|+, + * in case this is NVGRE. + */ + ND_PRINT(", key=0x%x", key); } if (flags & GRE_SP) { @@ -191,6 +224,59 @@ gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length) ND_PRINT("\n\t"); /* if verbose go multiline */ switch (prot) { + case 0x0000: + /* + * 0x0000 is reserved, but Cisco, at least, appears to + * use it for keep-alives; see, for example, + * https://www.cisco.com/c/en/us/support/docs/ip/generic-routing-encapsulation-gre/118370-technote-gre-00.html#anc1 + */ + ND_PRINT("keep-alive"); + break; + case GRE_WCCP: + /* + * This is a bit weird. + * + * This may either just mean "IPv4" or it may mean + * "IPv4 preceded by a WCCP redirect header". We + * check to see if the first octet looks like the + * beginning of an IPv4 header and, if not, dissect + * it "IPv4 preceded by a WCCP redirect header", + * otherwise we dissect it as just IPv4. + * + * See "Packet redirection" in draft-forster-wrec-wccp-v1-00, + * section 4.12 "Traffic Forwarding" in + * draft-wilson-wrec-wccp-v2-01, and section 3.12.1 + * "Forwarding using GRE Encapsulation" in + * draft-param-wccp-v2rev1-01. + */ + ND_PRINT("wccp "); + + ND_ICHECK_U(len, <, 1); + if (GET_U_1(bp) >> 4 != 4) { + /* + * First octet isn't 0x4*, so it's not IPv4. + */ + const struct wccp_redirect *wccp; + uint8_t wccp_flags; + + ND_ICHECK_ZU(len, <, sizeof(*wccp)); + wccp = (const struct wccp_redirect *)bp; + wccp_flags = GET_U_1(wccp->flags); + + ND_PRINT("T:%c A:%c U:%c SId:%u Alt:%u Pri:%u", + (wccp_flags & WCCP_T) ? '1' : '0', + (wccp_flags & WCCP_A) ? '1' : '0', + (wccp_flags & WCCP_U) ? '1' : '0', + GET_U_1(wccp->ServiceId), + GET_U_1(wccp->AltBucket), + GET_U_1(wccp->PriBucket)); + + bp += sizeof(*wccp); + len -= sizeof(*wccp); + + ND_PRINT(": "); + } + /* FALLTHROUGH */ case ETHERTYPE_IP: ip_print(ndo, bp, len); break; @@ -198,6 +284,7 @@ gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length) ip6_print(ndo, bp, len); break; case ETHERTYPE_MPLS: + case ETHERTYPE_MPLS_MULTI: mpls_print(ndo, bp, len); break; case ETHERTYPE_IPX: @@ -212,6 +299,21 @@ gre_print_0(netdissect_options *ndo, const u_char *bp, u_int length) case ETHERTYPE_TEB: ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL); break; + case ETHERTYPE_NSH: + nsh_print(ndo, bp, len); + break; + case GRE_ERSPAN_I_II: + erspan_i_ii_print(ndo, flags, bp, len); + break; + case GRE_ERSPAN_III: + erspan_iii_print(ndo, bp, len); + break; + case GRE_CDP: + cdp_print(ndo, bp, len); + break; + case GRE_NHRP: + nhrp_print(ndo, bp, len); + break; default: ND_PRINT("gre-proto-0x%x", prot); } @@ -241,16 +343,48 @@ gre_print_1(netdissect_options *ndo, const u_char *bp, u_int length) len -= 2; bp += 2; + /* + * This version is used for two purposes: + * + * RFC 2637 PPTP; + * Some Mikrotik Ethernet-over-IP hack. + */ + switch (prot) { + case GRE_MIKROTIK_EOIP: + /* + * The MikroTik hack uses only the key field, and uses it + * for its own purposes. If anything other than the version + * and K bit are set, report an error and give up. + */ + if ((flags & ~GRE_VERS_MASK) != GRE_KP) { + ND_PRINT(" unknown-eoip-flags-%04x!", flags); + return; + } + break; + default: + /* + * XXX - what should we do if it's not ETHERTYPE_PPP? + */ + break; + } if (flags & GRE_KP) { - uint32_t k; + /* Skip payload length? */ + ND_ICHECK_U(len, <, 2); + ND_TCHECK_2(bp); + len -= 2; + bp += 2; - ND_ICHECK_U(len, <, 4); - k = GET_BE_U_4(bp); - ND_PRINT(", call %u", k & 0xffff); - len -= 4; - bp += 4; - } + ND_ICHECK_U(len, <, 2); + if (prot == GRE_MIKROTIK_EOIP) { + /* Non-standard */ + ND_PRINT(", tunnel-id %u", GET_BE_U_2(bp)); + } else + ND_PRINT(", call %u", GET_BE_U_2(bp)); + len -= 2; + bp += 2; + } else + ND_PRINT(", (ERROR: K flag not set)"); if (flags & GRE_SP) { ND_ICHECK_U(len, <, 4); @@ -266,7 +400,10 @@ gre_print_1(netdissect_options *ndo, const u_char *bp, u_int length) len -= 4; } - if ((flags & GRE_SP) == 0) + /* + * More non-standard EoIP behavior. + */ + if (prot != GRE_MIKROTIK_EOIP && (flags & GRE_SP) == 0) ND_PRINT(", no-payload"); if (ndo->ndo_eflag) @@ -275,7 +412,10 @@ gre_print_1(netdissect_options *ndo, const u_char *bp, u_int length) ND_PRINT(", length %u",length); - if ((flags & GRE_SP) == 0) + /* + * More non-standard EoIP behavior. + */ + if (prot != GRE_MIKROTIK_EOIP && (flags & GRE_SP) == 0) return; if (ndo->ndo_vflag < 1) @@ -287,6 +427,13 @@ gre_print_1(netdissect_options *ndo, const u_char *bp, u_int length) case ETHERTYPE_PPP: ppp_print(ndo, bp, len); break; + case GRE_MIKROTIK_EOIP: + /* MikroTik RouterBoard Ethernet over IP (EoIP) */ + if (len == 0) + ND_PRINT("keepalive"); + else + ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL); + break; default: ND_PRINT("gre-proto-0x%x", prot); break;