Download raw body.
pcap: add missing 802.11 subtype keywords
"Theo de Raadt" <deraadt@openbsd.org> writes:
> This diff is killing me.
>
> Can someone put these into a sorted table and use bsearch?
>
This replaces all of the long if-else blocks (802.11 keywords and pf
actions) with table lookups, following the ipsecctl grammar and upstream
libpcap grammar. Also adds the missing 802.11 keywords.
Lightly tested with wifi traffic and a pflog file.
diff /usr/src
commit - 6c24eb55e021991196003dc7f0a643e806b14295
path + /usr/src
blob - 0c7db1641efc8c73baae467b25ca33c0b1bccbed
file + lib/libpcap/grammar.y
--- lib/libpcap/grammar.y
+++ lib/libpcap/grammar.y
@@ -37,6 +37,7 @@
#include <net80211/ieee80211.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include "pcap-int.h"
@@ -54,6 +55,99 @@
int n_errors = 0;
+struct keywords {
+ const char *k_name;
+ int k_val;
+};
+
+/* these must be kept sorted, as they are searched with bsearch() */
+const struct keywords pf_actions[] = {
+ { "accept", PF_PASS },
+ { "binat", PF_BINAT },
+ { "block", PF_DROP },
+ { "drop", PF_DROP },
+ { "match", PF_MATCH },
+ { "nat", PF_NAT },
+ { "pass", PF_PASS },
+ { "rdr", PF_RDR },
+ { "scrub", PF_SCRUB }
+};
+const struct keywords ieee80211_dirs[] = {
+ { "dstods", IEEE80211_FC1_DIR_DSTODS },
+ { "fromds", IEEE80211_FC1_DIR_FROMDS },
+ { "nods", IEEE80211_FC1_DIR_TODS },
+ { "tods", IEEE80211_FC1_DIR_TODS }
+};
+const struct keywords ieee80211_types[] = {
+ { "control", IEEE80211_FC0_TYPE_CTL },
+ { "ctl", IEEE80211_FC0_TYPE_CTL },
+ { "data", IEEE80211_FC0_TYPE_DATA },
+ { "management", IEEE80211_FC0_TYPE_MGT },
+ { "mgt", IEEE80211_FC0_TYPE_MGT }
+};
+const struct keywords ieee80211_subtypes[] = {
+ { "ack", IEEE80211_FC0_SUBTYPE_ACK },
+ { "assoc-req", IEEE80211_FC0_SUBTYPE_ASSOC_REQ },
+ { "assoc-resp", IEEE80211_FC0_SUBTYPE_ASSOC_RESP },
+ { "assocreq", IEEE80211_FC0_SUBTYPE_ASSOC_REQ },
+ { "assocresp", IEEE80211_FC0_SUBTYPE_ASSOC_RESP },
+ { "atim", IEEE80211_FC0_SUBTYPE_ATIM },
+ { "auth", IEEE80211_FC0_SUBTYPE_AUTH },
+ { "authentication", IEEE80211_FC0_SUBTYPE_AUTH },
+ { "beacon", IEEE80211_FC0_SUBTYPE_BEACON },
+ { "cf-ack", IEEE80211_FC0_SUBTYPE_NODATA_CF_ACK },
+ { "cf-ack-poll", IEEE80211_FC0_SUBTYPE_NODATA_CF_ACKPOLL },
+ { "cf-end", IEEE80211_FC0_SUBTYPE_CF_END },
+ { "cf-end-ack", IEEE80211_FC0_SUBTYPE_CF_END_ACK },
+ { "cf-poll", IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL },
+ { "cts", IEEE80211_FC0_SUBTYPE_CTS },
+ { "data", IEEE80211_FC0_SUBTYPE_DATA },
+ { "data-cf-ack", IEEE80211_FC0_SUBTYPE_DATA_CF_ACK },
+ { "data-cf-ack-poll", IEEE80211_FC0_SUBTYPE_DATA_CF_ACKPOLL },
+ { "data-cf-poll", IEEE80211_FC0_SUBTYPE_DATA_CF_POLL },
+ { "deauth", IEEE80211_FC0_SUBTYPE_DEAUTH },
+ { "deauthentication", IEEE80211_FC0_SUBTYPE_DEAUTH },
+ { "disassoc", IEEE80211_FC0_SUBTYPE_DISASSOC },
+ { "disassociation", IEEE80211_FC0_SUBTYPE_DISASSOC },
+ { "null", IEEE80211_FC0_SUBTYPE_NODATA },
+ { "probe-req", IEEE80211_FC0_SUBTYPE_PROBE_REQ },
+ { "probe-resp", IEEE80211_FC0_SUBTYPE_PROBE_RESP },
+ { "probereq", IEEE80211_FC0_SUBTYPE_PROBE_REQ },
+ { "proberesp", IEEE80211_FC0_SUBTYPE_PROBE_RESP },
+ { "ps-poll", IEEE80211_FC0_SUBTYPE_PS_POLL },
+ { "qos", IEEE80211_FC0_SUBTYPE_QOS |
+ IEEE80211_FC0_SUBTYPE_NODATA },
+ { "qos-cf-ack-poll", IEEE80211_FC0_SUBTYPE_QOS |
+ IEEE80211_FC0_SUBTYPE_NODATA_CF_ACKPOLL },
+ { "qos-cf-poll", IEEE80211_FC0_SUBTYPE_QOS |
+ IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL },
+ { "qos-data", IEEE80211_FC0_SUBTYPE_QOS |
+ IEEE80211_FC0_SUBTYPE_DATA },
+ { "qos-data-cf-ack", IEEE80211_FC0_SUBTYPE_QOS |
+ IEEE80211_FC0_SUBTYPE_DATA_CF_ACK },
+ { "qos-data-cf-ack-poll", IEEE80211_FC0_SUBTYPE_QOS |
+ IEEE80211_FC0_SUBTYPE_DATA_CF_ACKPOLL },
+ { "qos-data-cf-poll", IEEE80211_FC0_SUBTYPE_QOS |
+ IEEE80211_FC0_SUBTYPE_DATA_CF_POLL },
+ { "reassoc-req", IEEE80211_FC0_SUBTYPE_REASSOC_REQ },
+ { "reassoc-resp", IEEE80211_FC0_SUBTYPE_REASSOC_RESP },
+ { "reassocreq", IEEE80211_FC0_SUBTYPE_REASSOC_REQ },
+ { "reassocresp", IEEE80211_FC0_SUBTYPE_REASSOC_RESP },
+ { "rts", IEEE80211_FC0_SUBTYPE_RTS }
+};
+
+static int
+kw_cmp(const void *str, const void *ent)
+{
+ return strcasecmp(str, ((const struct keywords *)ent)->k_name);
+}
+
+static const struct keywords *
+kw_match(const char *str, const struct keywords *tbl, size_t len)
+{
+ return bsearch(str, tbl, len / sizeof(*tbl), sizeof(*tbl), kw_cmp);
+}
+
static struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF };
static void
@@ -305,22 +399,11 @@ reason: NUM { $$ = $1; }
}
;
-action: ID { if (strcasecmp($1, "pass") == 0 ||
- strcasecmp($1, "accept") == 0)
- $$ = PF_PASS;
- else if (strcasecmp($1, "drop") == 0 ||
- strcasecmp($1, "block") == 0)
- $$ = PF_DROP;
- else if (strcasecmp($1, "match") == 0)
- $$ = PF_MATCH;
- else if (strcasecmp($1, "rdr") == 0)
- $$ = PF_RDR;
- else if (strcasecmp($1, "nat") == 0)
- $$ = PF_NAT;
- else if (strcasecmp($1, "binat") == 0)
- $$ = PF_BINAT;
- else if (strcasecmp($1, "scrub") == 0)
- $$ = PF_SCRUB;
+action: ID { const struct keywords *p;
+ p = kw_match($1, pf_actions,
+ sizeof(pf_actions));
+ if (p != NULL)
+ $$ = p->k_val;
else
bpf_error("unknown PF action");
}
@@ -339,61 +422,33 @@ p80211: TYPE type SUBTYPE subtype
;
type: NUM
- | ID { if (strcasecmp($1, "data") == 0)
- $$ = IEEE80211_FC0_TYPE_DATA;
- else if (strcasecmp($1, "mgt") == 0 ||
- strcasecmp($1, "management") == 0)
- $$ = IEEE80211_FC0_TYPE_MGT;
- else if (strcasecmp($1, "ctl") == 0 ||
- strcasecmp($1, "control") == 0)
- $$ = IEEE80211_FC0_TYPE_CTL;
- else
- bpf_error("unknown 802.11 type");
+ | ID { const struct keywords *p;
+ p = kw_match($1, ieee80211_types,
+ sizeof(ieee80211_types));
+ if (p != NULL)
+ $$ = p->k_val;
+ else
+ bpf_error("unknown 802.11 type");
}
;
subtype: NUM
- | ID { if (strcasecmp($1, "assocreq") == 0)
- $$ = IEEE80211_FC0_SUBTYPE_ASSOC_REQ;
- else if (strcasecmp($1, "assocresp") == 0)
- $$ = IEEE80211_FC0_SUBTYPE_ASSOC_RESP;
- else if (strcasecmp($1, "reassocreq") == 0)
- $$ = IEEE80211_FC0_SUBTYPE_REASSOC_REQ;
- else if (strcasecmp($1, "reassocresp") == 0)
- $$ = IEEE80211_FC0_SUBTYPE_REASSOC_RESP;
- else if (strcasecmp($1, "probereq") == 0)
- $$ = IEEE80211_FC0_SUBTYPE_PROBE_REQ;
- else if (strcasecmp($1, "proberesp") == 0)
- $$ = IEEE80211_FC0_SUBTYPE_PROBE_RESP;
- else if (strcasecmp($1, "beacon") == 0)
- $$ = IEEE80211_FC0_SUBTYPE_BEACON;
- else if (strcasecmp($1, "atim") == 0)
- $$ = IEEE80211_FC0_SUBTYPE_ATIM;
- else if (strcasecmp($1, "disassoc") == 0 ||
- strcasecmp($1, "disassociation") == 0)
- $$ = IEEE80211_FC0_SUBTYPE_DISASSOC;
- else if (strcasecmp($1, "auth") == 0 ||
- strcasecmp($1, "authentication") == 0)
- $$ = IEEE80211_FC0_SUBTYPE_AUTH;
- else if (strcasecmp($1, "deauth") == 0 ||
- strcasecmp($1, "deauthentication") == 0)
- $$ = IEEE80211_FC0_SUBTYPE_DEAUTH;
- else if (strcasecmp($1, "data") == 0)
- $$ = IEEE80211_FC0_SUBTYPE_DATA;
+ | ID { const struct keywords *p;
+ p = kw_match($1, ieee80211_subtypes,
+ sizeof(ieee80211_subtypes));
+ if (p != NULL)
+ $$ = p->k_val;
else
- bpf_error("unknown 802.11 subtype");
- }
+ bpf_error("unknown 802.11 subtype");
+ }
;
dir: NUM
- | ID { if (strcasecmp($1, "nods") == 0)
- $$ = IEEE80211_FC1_DIR_NODS;
- else if (strcasecmp($1, "tods") == 0)
- $$ = IEEE80211_FC1_DIR_TODS;
- else if (strcasecmp($1, "fromds") == 0)
- $$ = IEEE80211_FC1_DIR_FROMDS;
- else if (strcasecmp($1, "dstods") == 0)
- $$ = IEEE80211_FC1_DIR_DSTODS;
+ | ID { const struct keywords *p;
+ p = kw_match($1, ieee80211_dirs,
+ sizeof(ieee80211_dirs));
+ if (p != NULL)
+ $$ = p->k_val;
else
bpf_error("unknown 802.11 direction");
}
> Todd Carson <toc@daybefore.net> wrote:
>
>>
>>
>> Many of the subtype keywords for matching various 802.11 frame types
>> which are documented in the tcpdump(8) and pcap-filter(5) manpages
>> aren't implemented in the grammar and result in an
>> "unknown 802.11 subtype" when used.
>>
>> They are found in the grammar in upstream libpcap from tcpdump.org.
>>
>> The diff below adds the missing subtype keywords mentioned in the
>> manpages.
>> Tested with real traffic on a few subtypes; the rest by sanity-checking
>> compiled BPF printed with 'tcpdump -d'.
>>
>> I don't know if this requires bumping the libpcap minor version so I
>> left that alone.
>>
>> diff /usr/src
>> commit - 6c24eb55e021991196003dc7f0a643e806b14295
>> path + /usr/src
>> blob - 0c7db1641efc8c73baae467b25ca33c0b1bccbed
>> file + lib/libpcap/grammar.y
>> --- lib/libpcap/grammar.y
>> +++ lib/libpcap/grammar.y
>> @@ -353,17 +353,23 @@ type: NUM
>> ;
>>
>> subtype: NUM
>> - | ID { if (strcasecmp($1, "assocreq") == 0)
>> + | ID { if (strcasecmp($1, "assocreq") == 0 ||
>> + strcasecmp($1, "assoc-req") == 0)
>> $$ = IEEE80211_FC0_SUBTYPE_ASSOC_REQ;
>> - else if (strcasecmp($1, "assocresp") == 0)
>> + else if (strcasecmp($1, "assocresp") == 0 ||
>> + strcasecmp($1, "assoc-resp") == 0)
>> $$ = IEEE80211_FC0_SUBTYPE_ASSOC_RESP;
>> - else if (strcasecmp($1, "reassocreq") == 0)
>> + else if (strcasecmp($1, "reassocreq") == 0 ||
>> + strcasecmp($1, "reassoc-req") == 0)
>> $$ = IEEE80211_FC0_SUBTYPE_REASSOC_REQ;
>> - else if (strcasecmp($1, "reassocresp") == 0)
>> + else if (strcasecmp($1, "reassocresp") == 0 ||
>> + strcasecmp($1, "reassoc-resp") == 0)
>> $$ = IEEE80211_FC0_SUBTYPE_REASSOC_RESP;
>> - else if (strcasecmp($1, "probereq") == 0)
>> + else if (strcasecmp($1, "probereq") == 0 ||
>> + strcasecmp($1, "probe-req") == 0)
>> $$ = IEEE80211_FC0_SUBTYPE_PROBE_REQ;
>> - else if (strcasecmp($1, "proberesp") == 0)
>> + else if (strcasecmp($1, "proberesp") == 0 ||
>> + strcasecmp($1, "probe-resp") == 0)
>> $$ = IEEE80211_FC0_SUBTYPE_PROBE_RESP;
>> else if (strcasecmp($1, "beacon") == 0)
>> $$ = IEEE80211_FC0_SUBTYPE_BEACON;
>> @@ -378,8 +384,55 @@ subtype: NUM
>> else if (strcasecmp($1, "deauth") == 0 ||
>> strcasecmp($1, "deauthentication") == 0)
>> $$ = IEEE80211_FC0_SUBTYPE_DEAUTH;
>> + else if (strcasecmp($1, "ps-poll") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_PS_POLL;
>> + else if (strcasecmp($1, "rts") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_RTS;
>> + else if (strcasecmp($1, "cts") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_CTS;
>> + else if (strcasecmp($1, "ack") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_ACK;
>> + else if (strcasecmp($1, "cf-end") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_CF_END;
>> + else if (strcasecmp($1, "cf-end-ack") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_CF_END_ACK;
>> else if (strcasecmp($1, "data") == 0)
>> $$ = IEEE80211_FC0_SUBTYPE_DATA;
>> + else if (strcasecmp($1, "data-cf-ack") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_DATA_CF_ACK;
>> + else if (strcasecmp($1, "data-cf-poll") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_DATA_CF_POLL;
>> + else if (strcasecmp($1, "data-cf-ack-poll") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_DATA_CF_ACKPOLL;
>> + else if (strcasecmp($1, "null") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_NODATA;
>> + else if (strcasecmp($1, "cf-ack") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_NODATA_CF_ACK;
>> + else if (strcasecmp($1, "cf-poll") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL;
>> + else if (strcasecmp($1, "cf-ack-poll") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_NODATA_CF_ACKPOLL;
>> + else if (strcasecmp($1, "qos-data") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_QOS|
>> + IEEE80211_FC0_SUBTYPE_DATA;
>> + else if (strcasecmp($1, "qos-data-cf-ack") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_QOS|
>> + IEEE80211_FC0_SUBTYPE_DATA_CF_ACK;
>> + else if (strcasecmp($1, "qos-data-cf-poll") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_QOS|
>> + IEEE80211_FC0_SUBTYPE_DATA_CF_POLL;
>> + else if (strcasecmp($1, "qos-data-cf-ack-poll") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_QOS|
>> + IEEE80211_FC0_SUBTYPE_DATA_CF_ACKPOLL;
>> + else if (strcasecmp($1, "qos") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_QOS|
>> + IEEE80211_FC0_SUBTYPE_NODATA;
>> + else if (strcasecmp($1, "qos-cf-poll") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_QOS|
>> + IEEE80211_FC0_SUBTYPE_NODATA_CF_POLL;
>> + else if (strcasecmp($1, "qos-cf-ack-poll") == 0)
>> + $$ = IEEE80211_FC0_SUBTYPE_QOS|
>> + IEEE80211_FC0_SUBTYPE_NODATA_CF_ACKPOLL;
>> else
>> bpf_error("unknown 802.11 subtype");
>> }
>>
pcap: add missing 802.11 subtype keywords