i was trying to understand some packets that tcpdump didnt know about, and discovered they were EAPOL. turns out EAPOL is a little container around a bunch of different types of messages including EAP, the MACsec Key Agreement protocol, and it's own type of capabilities advertisements.
this implements basic parsing of the EAPOL container so it can print the type. any further parsing will need code for each type of message to be added. i didnt think it was worth adding a new file just for eapol, so i put it in print-ether.c. we do have something in src/sys/net/ethertypes.h for 0x888e, but i want to rename it to ETHERTYPE_EAPOL anyway. ok? Index: print-ether.c =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/print-ether.c,v retrieving revision 1.39 diff -u -p -r1.39 print-ether.c --- print-ether.c 1 Dec 2021 18:28:46 -0000 1.39 +++ print-ether.c 4 Jan 2022 02:56:21 -0000 @@ -36,6 +36,7 @@ #include <netinet/tcp.h> #include <stdio.h> +#include <stddef.h> #include <pcap.h> @@ -49,6 +50,7 @@ const u_char *snapend; void ether_macctl(const u_char *, u_int); void ether_pbb_print(const u_char *, u_int, u_int); +void ether_eapol_print(const u_char *, u_int, u_int); void ether_print(const u_char *bp, u_int length) @@ -294,6 +296,13 @@ recurse: nsh_print(p, length); return (1); +#ifndef ETHERTYPE_EAPOL +#define ETHERTYPE_EAPOL 0x888e +#endif + case ETHERTYPE_EAPOL: + ether_eapol_print(p, length, caplen); + return (1); + #ifndef ETHERTYPE_PBB #define ETHERTYPE_PBB 0x88e7 #endif @@ -367,4 +376,87 @@ ether_macctl(const u_char *p, u_int leng trunc: printf("[|MACCTL]"); +} + +/* + * 802.1X EAPOL PDU + */ + +struct eapol_header { + uint8_t version; + uint8_t type; +#define EAPOL_T_EAP 0x00 +#define EAPOL_T_START 0x01 +#define EAPOL_T_LOGOFF 0x02 +#define EAPOL_T_KEY 0x03 +#define EAPOL_T_ENCAP_ASF_ALERT 0x04 +#define EAPOL_T_MKA 0x05 +#define EAPOL_T_ANNOUNCEMENT_GENERIC 0x06 +#define EAPOL_T_ANNOUNCEMENT_SPECIFIC 0x07 +#define EAPOL_T_ANNOUNCEMENT_REQ 0x08 + uint16_t length; +}; + +void +ether_eapol_print(const u_char *bp, u_int length, u_int caplen) +{ + struct eapol_header h; + + printf("EAPOL"); + + if (caplen < sizeof(h)) + goto trunc; + + h.version = *(bp + offsetof(struct eapol_header, version)); + h.type = *(bp + offsetof(struct eapol_header, type)); + h.length = EXTRACT_16BITS(bp + offsetof(struct eapol_header, length)); + + bp += sizeof(h); + length -= sizeof(h); + caplen -= sizeof(h); + + if (vflag) + printf(" (v%u, len %u)", h.version, h.length); + + if (length > h.length) + length = h.length; + else if (length < h.length) { + printf(" truncated-eapol - %u bytes missing!", + h.length - length); + } + + switch (h.type) { + case EAPOL_T_EAP: + printf(" EAP"); + break; + case EAPOL_T_START: + printf(" Start"); + break; + case EAPOL_T_LOGOFF: + printf(" Logoff"); + break; + case EAPOL_T_KEY: + printf(" Key"); + break; + case EAPOL_T_MKA: + printf(" MKA"); + break; + case EAPOL_T_ANNOUNCEMENT_GENERIC: + printf(" Announcement (Generic)"); + break; + case EAPOL_T_ANNOUNCEMENT_SPECIFIC: + printf(" Announcement (Specific)"); + break; + case EAPOL_T_ANNOUNCEMENT_REQ: + printf(" Announcement Req"); + break; + default: + printf(" unknown (%u)", h.type); + break; + } + + return; + +trunc: + printf(" [|eapol] "); }