]> The Tcpdump Group git mirrors - tcpdump/commitdiff
Add support for MACsec (IEEE 802.1AE-2006)
authorSabrina Dubroca <[email protected]>
Thu, 18 May 2017 13:47:57 +0000 (15:47 +0200)
committerSabrina Dubroca <[email protected]>
Thu, 18 May 2017 13:47:57 +0000 (15:47 +0200)
20 files changed:
Makefile.in
ethertype.h
netdissect.h
print-ether.c
print-macsec.c [new file with mode: 0644]
tests/TESTLIST
tests/macsec-changed.out [new file with mode: 0644]
tests/macsec-changed.pcap [new file with mode: 0644]
tests/macsec-encrypted.out [new file with mode: 0644]
tests/macsec-encrypted.pcap [new file with mode: 0644]
tests/macsec-integonly.out [new file with mode: 0644]
tests/macsec-integonly.pcap [new file with mode: 0644]
tests/macsec-short-longer.out [new file with mode: 0644]
tests/macsec-short-longer.pcap [new file with mode: 0644]
tests/macsec-short-shorter.out [new file with mode: 0644]
tests/macsec-short-shorter.pcap [new file with mode: 0644]
tests/macsec-short-valid.out [new file with mode: 0644]
tests/macsec-short-valid.pcap [new file with mode: 0644]
tests/macsec-snap.out [new file with mode: 0644]
tests/macsec-snap.pcap [new file with mode: 0644]

index c18d5ed91656ae5c29ee32b1b19e875f89ce1289..4bec2139c27268beaca463da25af6862a612deb2 100644 (file)
@@ -164,6 +164,7 @@ LIBNETDISSECT_SRC=\
        print-lwapp.c \
        print-lwres.c \
        print-m3ua.c \
+       print-macsec.c \
        print-medsa.c \
        print-mobile.c \
        print-mobility.c \
index f38ec8e4f7881f377353fb7740bf1fb69a7a0b42..8694ffdd66c80ad1bf09d13b0b415a7ed8e375e0 100644 (file)
 #ifndef        ETHERTYPE_8021QinQ
 #define        ETHERTYPE_8021QinQ      0x88a8
 #endif
+#ifndef ETHERTYPE_MACSEC
+#define ETHERTYPE_MACSEC       0x88e5
+#endif
 #ifndef ETHERTYPE_IPX
 #define ETHERTYPE_IPX          0x8137
 #endif
index ac916c2a2e117160bb01fd5c23578dcdca075b72..ad4182a3823ca9b98d68fe39d187503e0f4618c3 100644 (file)
@@ -547,6 +547,9 @@ extern void lwapp_control_print(netdissect_options *, const u_char *, u_int, int
 extern void lwapp_data_print(netdissect_options *, const u_char *, u_int);
 extern void lwres_print(netdissect_options *, const u_char *, u_int);
 extern void m3ua_print(netdissect_options *, const u_char *, const u_int);
+extern int macsec_print(netdissect_options *, const u_char **,
+                        u_int *, u_int *, u_int *,
+                        u_short *);
 extern void medsa_print(netdissect_options *, const u_char *, u_int, u_int, const struct lladdr_info *, const struct lladdr_info *);
 extern u_int mfr_print(netdissect_options *, register const u_char *, u_int);
 extern void mobile_print(netdissect_options *, const u_char *, u_int);
index 57c07ce935182931692fc98f62a40386159c0b37..3b1ef34e36f2b29c6b3284ba7d10b9bb9b5afa1f 100644 (file)
@@ -42,6 +42,7 @@ const struct tok ethertype_values[] = {
     { ETHERTYPE_8021Q9100,     "802.1Q-9100" },
     { ETHERTYPE_8021QinQ,      "802.1Q-QinQ" },
     { ETHERTYPE_8021Q9200,     "802.1Q-9200" },
+    { ETHERTYPE_MACSEC,                "802.1AE MACsec" },
     { ETHERTYPE_VMAN,          "VMAN" },
     { ETHERTYPE_PUP,            "PUP" },
     { ETHERTYPE_ARP,            "ARP"},
@@ -214,6 +215,18 @@ recurse:
                caplen -= 4;
                hdrlen += 4;
                goto recurse;
+       } else if (length_type == ETHERTYPE_MACSEC) {
+               /*
+                * MACsec, aka IEEE 802.1AE-2006
+                * Print the header, and try to print the payload if it's not encrypted
+                */
+               int ret = macsec_print(ndo, &p, &length, &caplen, &hdrlen, &length_type);
+               if (ret < 0)
+                       goto recurse;
+               else if (ret == 0)
+                       goto raw;
+               else
+                       return ret;
        } else if (length_type == ETHERTYPE_JUMBO) {
                /*
                 * Alteon jumbo frames.
@@ -235,6 +248,7 @@ recurse:
                hdrlen += llc_hdrlen;
        } else {
                if (ethertype_print(ndo, length_type, p, length, caplen, &src, &dst) == 0) {
+raw:
                        /* type not known, print raw packet */
                        if (!ndo->ndo_eflag) {
                                if (print_encap_header != NULL)
diff --git a/print-macsec.c b/print-macsec.c
new file mode 100644 (file)
index 0000000..3df80fe
--- /dev/null
@@ -0,0 +1,208 @@
+/* Copyright (c) 2017, Sabrina Dubroca <[email protected]>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in
+ *      the documentation and/or other materials provided with the
+ *      distribution.
+ *   3. The names of the authors may not be used to endorse or promote
+ *      products derived from this software without specific prior
+ *      written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* \summary: MACsec printer */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <netdissect-stdinc.h>
+
+#include <string.h>
+
+#include "netdissect.h"
+#include "addrtoname.h"
+#include "ether.h"
+#include "ethertype.h"
+#include "extract.h"
+
+static const char tstr[] = "[|MACsec]";
+
+#define MACSEC_DEFAULT_ICV_LEN 16
+
+/* Header format (SecTAG), following an Ethernet header
+ * IEEE 802.1AE-2006 9.3
+ *
+ * +---------------------------------+----------------+----------------+
+ * |        (MACsec ethertype)       |     TCI_AN     |       SL       |
+ * +---------------------------------+----------------+----------------+
+ * |                           Packet Number                           |
+ * +-------------------------------------------------------------------+
+ * |                     Secure Channel Identifier                     |
+ * |                            (optional)                             |
+ * +-------------------------------------------------------------------+
+ *
+ * MACsec ethertype = 0x88e5
+ * TCI: Tag Control Information, set of flags
+ * AN: association number, 2 bits
+ * SL (short length): 6-bit length of the protected payload, if < 48
+ * Packet Number: 32-bits packet identifier
+ * Secure Channel Identifier: 64-bit unique identifier, usually
+ *     composed of a MAC address + 16-bit port number
+ */
+struct macsec_sectag {
+       u_char  tci_an;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+       u_char short_length:6,
+                    unused:2;
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+       u_char        unused:2,
+               short_length:6;
+#endif
+       uint32_t packet_number;
+       u_char secure_channel_id[8]; /* optional */
+} __attribute__((packed));
+
+/* IEEE 802.1AE-2006 9.5 */
+#define MACSEC_TCI_VERSION 0x80
+#define MACSEC_TCI_ES      0x40 /* end station */
+#define MACSEC_TCI_SC      0x20 /* SCI present */
+#define MACSEC_TCI_SCB     0x10 /* epon */
+#define MACSEC_TCI_E       0x08 /* encryption */
+#define MACSEC_TCI_C       0x04 /* changed text */
+#define MACSEC_AN_MASK     0x03 /* association number */
+#define MACSEC_TCI_FLAGS   (MACSEC_TCI_ES | MACSEC_TCI_SC | MACSEC_TCI_SCB | MACSEC_TCI_E | MACSEC_TCI_C)
+#define MACSEC_TCI_CONFID  (MACSEC_TCI_E | MACSEC_TCI_C)
+
+#define MACSEC_SECTAG_LEN_NOSCI 6
+#define MACSEC_SECTAG_LEN_SCI 14
+static int
+ieee8021ae_sectag_len(const struct macsec_sectag *sectag)
+{
+       return (sectag->tci_an & MACSEC_TCI_SC) ?
+              MACSEC_SECTAG_LEN_SCI :
+              MACSEC_SECTAG_LEN_NOSCI;
+}
+
+static int macsec_check_length(const struct macsec_sectag *sectag, u_int length, u_int caplen)
+{
+       u_int len;
+
+       /* we need the full MACsec header in the capture */
+       if (caplen < (MACSEC_SECTAG_LEN_NOSCI + 2))
+               return 0;
+
+       len = ieee8021ae_sectag_len(sectag);
+       if (caplen < (len + 2))
+               return 0;
+
+       if (sectag->short_length != 0) {
+               /* original packet must have exact length */
+               u_int exact = ETHER_HDRLEN + len + 2 + sectag->short_length;
+               return exact == length;
+       } else {
+               /* original packet must not be short */
+               u_int minlen = ETHER_HDRLEN + len + 2 + 48;
+               return length >= minlen;
+       }
+
+       return 1;
+}
+
+#define SCI_FMT "%016" PRIx64
+
+static const struct tok macsec_flag_values[] = {
+       { MACSEC_TCI_E,   "E" },
+       { MACSEC_TCI_C,   "C" },
+       { MACSEC_TCI_ES,  "S" },
+       { MACSEC_TCI_SCB, "B" },
+       { MACSEC_TCI_SC,  "I" },
+       { 0, NULL }
+};
+
+/* returns < 0 iff the packet can be decoded completely */
+int macsec_print(netdissect_options *ndo, const u_char **bp,
+                u_int *lengthp, u_int *caplenp, u_int *hdrlenp,
+                u_short *length_type)
+{
+       const u_char *p = *bp;
+       u_int length = *lengthp;
+       u_int caplen = *caplenp;
+       u_int hdrlen = *hdrlenp;
+       const struct macsec_sectag *sectag = (const struct macsec_sectag *)p;
+       u_int len;
+
+       if (!macsec_check_length(sectag, length, caplen)) {
+               ND_PRINT((ndo, tstr));
+               return hdrlen + caplen;
+       }
+
+       if (sectag->unused || sectag->tci_an & MACSEC_TCI_VERSION) {
+               ND_PRINT((ndo, "%s", istr));
+               return hdrlen + caplen;
+       }
+
+       if (ndo->ndo_eflag) {
+               char buf[128];
+               int n = snprintf(buf, sizeof(buf), "an %d, pn %d, flags %s",
+                                sectag->tci_an & MACSEC_AN_MASK,
+                                EXTRACT_32BITS(&sectag->packet_number),
+                                bittok2str_nosep(macsec_flag_values, "none",
+                                                 sectag->tci_an & MACSEC_TCI_FLAGS));
+               if (n < 0)
+                       return hdrlen + caplen;
+
+
+               if (sectag->short_length) {
+                       int r = snprintf(buf + n, sizeof(buf) - n, ", sl %d",
+                                        sectag->short_length);
+                       if (r < 0)
+                               return hdrlen + caplen;
+                       n += r;
+               }
+
+               if (sectag->tci_an & MACSEC_TCI_SC) {
+                       uint64_t sci;
+                       int r;
+                       sci = EXTRACT_64BITS(sectag->secure_channel_id);
+                       r = snprintf(buf + n, sizeof(buf) - n, ", sci " SCI_FMT, sci);
+                       if (r < 0)
+                               return hdrlen + caplen;
+                       n += r;
+               }
+
+               ND_PRINT((ndo, "%s, ", buf));
+       }
+
+       len = ieee8021ae_sectag_len(sectag);
+       *length_type = EXTRACT_16BITS(*bp + len);
+       if (ndo->ndo_eflag && *length_type > ETHERMTU && !(sectag->tci_an & MACSEC_TCI_E))
+               ND_PRINT((ndo, "ethertype %s, ", tok2str(ethertype_values,"0x%04x", *length_type)));
+
+       if ((sectag->tci_an & MACSEC_TCI_CONFID)) {
+               *bp += len;
+               *hdrlenp += len;
+
+               *lengthp -= len;
+               *caplenp -= len;
+               return 0;
+       } else {
+               len += 2;
+               *bp += len;
+               *hdrlenp += len;
+
+               len += MACSEC_DEFAULT_ICV_LEN;
+               *lengthp -= len;
+               *caplenp -= len;
+               return -1;
+       }
+}
index 7ab888c1eebe0f10087a56043f50d6446cc5d0e8..66dbb6e590982e1053744c92fe64dea8cdda5837 100644 (file)
@@ -446,3 +446,12 @@ rtp-seg-fault-2  rtp-seg-fault-2.pcap  rtp-seg-fault-2.out  -t -v -T rtp
 # NFS tests
 # fuzzed pcap
 nfs-seg-fault-1  nfs-seg-fault-1.pcap  nfs-seg-fault-1.out  -t
+
+# MACsec
+macsec-encrypted       macsec-encrypted.pcap          macsec-encrypted.out        -t -e
+macsec-changed         macsec-changed.pcap            macsec-changed.out          -t -e
+macsec-integonly       macsec-integonly.pcap          macsec-integonly.out        -t -e
+macsec-snap            macsec-snap.pcap               macsec-snap.out             -t -e
+macsec-short-shorter   macsec-short-shorter.pcap      macsec-short-shorter.out    -t -e
+macsec-short-longer    macsec-short-longer.pcap       macsec-short-longer.out     -t -e
+macsec-short-valid     macsec-short-valid.pcap        macsec-short-valid.out      -t -e
diff --git a/tests/macsec-changed.out b/tests/macsec-changed.out
new file mode 100644 (file)
index 0000000..3321e30
--- /dev/null
@@ -0,0 +1,7 @@
+2e:b7:3f:39:95:c3 > 3e:6f:f3:74:23:7c, ethertype 802.1AE MACsec (0x88e5), length 122: an 0, pn 6, flags CI, sci 2eb73f3995c3006f, ethertype IPv4, 
+       0x0000:  0800 4500 0054 ab6b 4000 4001 27e9 c0a8  ..E..T.k@.@.'...
+       0x0010:  7301 c0a8 7302 0800 c5fd 0784 0001 a636  s...s..........6
+       0x0020:  1a57 0000 0000 a51c 0600 0000 0000 1011  .W..............
+       0x0030:  1213 1415 1617 1819 1a1b 1c1d 1e1f 2021  ...............!
+       0x0040:  2223 2425 2627 2829 2a2b 2c2d 2e2f 3031  "#$%&'()*+,-./01
+       0x0050:  3233 3435 3637 72f1 e918 85fa ca0b       234567r.......
diff --git a/tests/macsec-changed.pcap b/tests/macsec-changed.pcap
new file mode 100644 (file)
index 0000000..7d05dca
Binary files /dev/null and b/tests/macsec-changed.pcap differ
diff --git a/tests/macsec-encrypted.out b/tests/macsec-encrypted.out
new file mode 100644 (file)
index 0000000..68866d0
--- /dev/null
@@ -0,0 +1,8 @@
+2e:b7:3f:39:95:c3 > 3e:6f:f3:74:23:7c, ethertype 802.1AE MACsec (0x88e5), length 130: an 0, pn 72, flags ECI, sci 2eb73f3995c30001, 
+       0x0000:  50c6 8aab f682 2b69 adc7 f4bc a4d8 af67  P.....+i.......g
+       0x0010:  5437 64c9 b927 4dcb 49f5 7641 d6ee 5aaa  T7d..'M.I.vA..Z.
+       0x0020:  34b1 1748 4565 fb62 d328 810d b6ce 99b3  4..HEe.b.(......
+       0x0030:  719f 7333 1dbe cdfe d3dc 75a4 fe35 dd96  q.s3......u..5..
+       0x0040:  79c2 e460 9e0d 52eb e804 83a3 17ee f359  y..`..R........Y
+       0x0050:  a692 37ec d92d 194d bb66 fdf6 7812 2496  ..7..-.M.f..x.$.
+       0x0060:  2d32 9492 13fd                           -2....
diff --git a/tests/macsec-encrypted.pcap b/tests/macsec-encrypted.pcap
new file mode 100644 (file)
index 0000000..1fefda9
Binary files /dev/null and b/tests/macsec-encrypted.pcap differ
diff --git a/tests/macsec-integonly.out b/tests/macsec-integonly.out
new file mode 100644 (file)
index 0000000..fcc2d1a
--- /dev/null
@@ -0,0 +1 @@
+2e:b7:3f:39:95:c3 > 3e:6f:f3:74:23:7c, ethertype 802.1AE MACsec (0x88e5), length 130: an 0, pn 68, flags I, sci 2eb73f3995c30001, ethertype IPv4, 192.168.113.1 > 192.168.113.2: ICMP echo request, id 948, seq 1, length 64
diff --git a/tests/macsec-integonly.pcap b/tests/macsec-integonly.pcap
new file mode 100644 (file)
index 0000000..5a9f8af
Binary files /dev/null and b/tests/macsec-integonly.pcap differ
diff --git a/tests/macsec-short-longer.out b/tests/macsec-short-longer.out
new file mode 100644 (file)
index 0000000..67228f1
--- /dev/null
@@ -0,0 +1 @@
+ca:f9:df:4f:50:9a > b6:b9:5d:80:8d:79, ethertype 802.1AE MACsec (0x88e5), length 84: [|MACsec]
diff --git a/tests/macsec-short-longer.pcap b/tests/macsec-short-longer.pcap
new file mode 100644 (file)
index 0000000..1130428
Binary files /dev/null and b/tests/macsec-short-longer.pcap differ
diff --git a/tests/macsec-short-shorter.out b/tests/macsec-short-shorter.out
new file mode 100644 (file)
index 0000000..e16b04c
--- /dev/null
@@ -0,0 +1 @@
+ca:f9:df:4f:50:9a > b6:b9:5d:80:8d:79, ethertype 802.1AE MACsec (0x88e5), length 74: [|MACsec]
diff --git a/tests/macsec-short-shorter.pcap b/tests/macsec-short-shorter.pcap
new file mode 100644 (file)
index 0000000..41de359
Binary files /dev/null and b/tests/macsec-short-shorter.pcap differ
diff --git a/tests/macsec-short-valid.out b/tests/macsec-short-valid.out
new file mode 100644 (file)
index 0000000..b4d8d2e
--- /dev/null
@@ -0,0 +1 @@
+ca:f9:df:4f:50:9a > b6:b9:5d:80:8d:79, ethertype 802.1AE MACsec (0x88e5), length 78: an 0, pn 66, flags I, sl 34, sci caf9df4f509a0064, ethertype IPv4, 192.168.114.1.37459 > 192.168.114.2.6666: UDP, length 4
diff --git a/tests/macsec-short-valid.pcap b/tests/macsec-short-valid.pcap
new file mode 100644 (file)
index 0000000..e295056
Binary files /dev/null and b/tests/macsec-short-valid.pcap differ
diff --git a/tests/macsec-snap.out b/tests/macsec-snap.out
new file mode 100644 (file)
index 0000000..0ceb5fd
--- /dev/null
@@ -0,0 +1 @@
+ca:f9:df:4f:50:9a > b6:b9:5d:80:8d:79, ethertype 802.1AE MACsec (0x88e5), length 130: [|MACsec]
diff --git a/tests/macsec-snap.pcap b/tests/macsec-snap.pcap
new file mode 100644 (file)
index 0000000..a0c0a3e
Binary files /dev/null and b/tests/macsec-snap.pcap differ