On Mon, Dec 12, 2016 at 01:02:55PM +1000, David Gwynne wrote:
> gre can do more things than tcpdump currently thinks it can.
>
> specifically, gre can be carried by ipv6, and it can encapsulate
> more than just ip and ppp packets.
>
> as such, this tells tcpdump to look at gre inside ipv6 packets.
>
> gre uses ethertypes to represent what protocol it contains, so
> instead of rolling a gre specific version of ip and ppp protocol
> types, just reuse the ether ones.
>
> also tell tcpdump that gre can contains ipv6, ethernet, and mpls.
>
> NVGRE is basically a constrained gre header (ie, must be version
> 0, must only have the K bit set, must be transether), so this detects
> that and prints the NVGRE interpretation of the Key field. that
> makes the VSID in NVGRE packets easier to see.
>
> theres some tweaks to output so it looks ok with and without the
> -v optarg.
>
> ok?
ok stsp@
>
> Index: print-gre.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/tcpdump/print-gre.c,v
> retrieving revision 1.11
> diff -u -p -r1.11 print-gre.c
> --- print-gre.c 5 Nov 2015 11:55:21 -0000 1.11
> +++ print-gre.c 12 Dec 2016 02:48:21 -0000
> @@ -39,6 +39,8 @@
> #include <netinet/ip.h>
> #include <arpa/inet.h>
>
> +#include <net/ethertypes.h>
> +
> #include <stdio.h>
> #include <string.h>
>
> @@ -55,13 +57,15 @@
> #define GRE_AP 0x0080 /* acknowledgment# present */
> #define GRE_VERS 0x0007 /* protocol version */
>
> -#define GREPROTO_IP 0x0800 /* IP */
> -#define GREPROTO_PPP 0x880b /* PPTP */
> -
> /* source route entry types */
> #define GRESRE_IP 0x0800 /* IP */
> #define GRESRE_ASN 0xfffe /* ASN */
>
> +#define NVGRE_VSID_MASK 0xffffff00U
> +#define NVGRE_VSID_SHIFT 8
> +#define NVGRE_FLOWID_MASK 0x000000ffU
> +#define NVGRE_FLOWID_SHIFT 0
> +
> 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);
> @@ -82,14 +86,17 @@ gre_print(const u_char *bp, u_int length
> }
> vers = EXTRACT_16BITS(bp) & GRE_VERS;
>
> - if (vers == 0)
> + switch (vers) {
> + case 0:
> gre_print_0(bp, len);
> - else if (vers == 1)
> + break;
> + case 1:
> gre_print_1(bp, len);
> - else
> + break;
> + default:
> printf("gre-unknown-version=%u", vers);
> - return;
> -
> + break;
> + }
> }
>
> void
> @@ -114,6 +121,8 @@ gre_print_0(const u_char *bp, u_int leng
> if (len < 2)
> goto trunc;
> prot = EXTRACT_16BITS(bp);
> + printf("%s", etherproto_string(prot));
> +
> len -= 2;
> bp += 2;
>
> @@ -121,21 +130,32 @@ gre_print_0(const u_char *bp, u_int leng
> if (len < 2)
> goto trunc;
> if (vflag)
> - printf("sum 0x%x ", EXTRACT_16BITS(bp));
> + printf(" sum 0x%x", EXTRACT_16BITS(bp));
> bp += 2;
> len -= 2;
>
> if (len < 2)
> goto trunc;
> - printf("off 0x%x ", EXTRACT_16BITS(bp));
> + printf(" off 0x%x", EXTRACT_16BITS(bp));
> bp += 2;
> len -= 2;
> }
>
> if (flags & GRE_KP) {
> + uint32_t key, vsid;
> +
> if (len < 4)
> goto trunc;
> - printf("key=0x%x ", EXTRACT_32BITS(bp));
> + key = EXTRACT_32BITS(bp);
> +
> + /* maybe NVGRE? */
> + if (flags == (GRE_KP | 0) && prot == ETHERTYPE_TRANSETHER) {
> + vsid = (key & NVGRE_VSID_MASK) >> NVGRE_VSID_SHIFT;
> + printf(" NVGRE vsid=%u (0x%x)+flowid=0x%02x /",
> + vsid, vsid,
> + (key & NVGRE_FLOWID_MASK) >> NVGRE_FLOWID_SHIFT);
> + }
> + printf(" key=%u (0x%x)", key, key);
> bp += 4;
> len -= 4;
> }
> @@ -143,7 +163,7 @@ gre_print_0(const u_char *bp, u_int leng
> if (flags & GRE_SP) {
> if (len < 4)
> goto trunc;
> - printf("seq %u ", EXTRACT_32BITS(bp));
> + printf(" seq %u", EXTRACT_32BITS(bp));
> bp += 4;
> len -= 4;
> }
> @@ -174,10 +194,21 @@ gre_print_0(const u_char *bp, u_int leng
> }
> }
>
> + printf(": ");
> +
> switch (prot) {
> - case GREPROTO_IP:
> + case ETHERTYPE_IP:
> ip_print(bp, len);
> break;
> + case ETHERTYPE_IPV6:
> + ip6_print(bp, len);
> + break;
> + case ETHERTYPE_MPLS:
> + mpls_print(bp, len);
> + break;
> + case ETHERTYPE_TRANSETHER:
> + ether_print(bp, len);
> + break;
> default:
> printf("gre-proto-0x%x", prot);
> }
> @@ -198,7 +229,7 @@ gre_print_1(const u_char *bp, u_int leng
> bp += 2;
>
> if (vflag) {
> - printf("[%s%s%s%s%s%s] ",
> + printf("[%s%s%s%s%s%s]",
> (flags & GRE_CP) ? "C" : "",
> (flags & GRE_RP) ? "R" : "",
> (flags & GRE_KP) ? "K" : "",
> @@ -214,19 +245,19 @@ gre_print_1(const u_char *bp, u_int leng
> bp += 2;
>
> if (flags & GRE_CP) {
> - printf("cpset!");
> + printf(" cpset!");
> return;
> }
> if (flags & GRE_RP) {
> - printf("rpset!");
> + printf(" rpset!");
> return;
> }
> if ((flags & GRE_KP) == 0) {
> - printf("kpunset!");
> + printf(" kpunset!");
> return;
> }
> if (flags & GRE_sP) {
> - printf("spset!");
> + printf(" spset!");
> return;
> }
>
> @@ -236,7 +267,7 @@ gre_print_1(const u_char *bp, u_int leng
> if (len < 4)
> goto trunc;
> k = EXTRACT_32BITS(bp);
> - printf("call %d ", k & 0xffff);
> + printf(" call %d", k & 0xffff);
> len -= 4;
> bp += 4;
> }
> @@ -244,7 +275,7 @@ gre_print_1(const u_char *bp, u_int leng
> if (flags & GRE_SP) {
> if (len < 4)
> goto trunc;
> - printf("seq %u ", EXTRACT_32BITS(bp));
> + printf(" seq %u", EXTRACT_32BITS(bp));
> bp += 4;
> len -= 4;
> }
> @@ -252,18 +283,20 @@ gre_print_1(const u_char *bp, u_int leng
> if (flags & GRE_AP) {
> if (len < 4)
> goto trunc;
> - printf("ack %u ", EXTRACT_32BITS(bp));
> + printf(" ack %u", EXTRACT_32BITS(bp));
> bp += 4;
> len -= 4;
> }
>
> if ((flags & GRE_SP) == 0) {
> - printf("no-payload");
> + printf(" no-payload");
> return;
> }
>
> + printf(": ");
> +
> switch (prot) {
> - case GREPROTO_PPP:
> + case ETHERTYPE_PPP:
> printf("gre-ppp-payload");
> break;
> default:
> @@ -282,17 +315,17 @@ gre_sre_print(u_int16_t af, u_int8_t sre
> {
> switch (af) {
> case GRESRE_IP:
> - printf("(rtaf=ip");
> + printf(" (rtaf=ip");
> gre_sre_ip_print(sreoff, srelen, bp, len);
> - printf(") ");
> + printf(")");
> break;
> case GRESRE_ASN:
> - printf("(rtaf=asn");
> + printf(" (rtaf=asn");
> gre_sre_asn_print(sreoff, srelen, bp, len);
> - printf(") ");
> + printf(")");
> break;
> default:
> - printf("(rtaf=0x%x) ", af);
> + printf(" (rtaf=0x%x)", af);
> }
> }
> void
> Index: print-ip6.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/tcpdump/print-ip6.c,v
> retrieving revision 1.23
> diff -u -p -r1.23 print-ip6.c
> --- print-ip6.c 16 Nov 2015 00:16:39 -0000 1.23
> +++ print-ip6.c 12 Dec 2016 02:48:21 -0000
> @@ -184,6 +184,18 @@ ip6_print(const u_char *bp, u_int length
> if (! vflag)
> printf(" (encap)");
> goto end;
> +
> +#ifndef IPPROTO_GRE
> +#define IPPROTO_GRE 47
> +#endif
> + case IPPROTO_GRE:
> + gre_print(cp, len);
> + if (! vflag) {
> + printf(" (gre encap)");
> + goto out;
> + }
> + goto end;
> +
> case IPPROTO_NONE:
> (void)printf("no next header");
> goto end;
>