diff options
author | 2006-06-27 18:14:59 +0000 | |
---|---|---|
committer | 2006-06-27 18:14:59 +0000 | |
commit | 9a571ad92f0369e28994ebefe4761c6127d9efb3 (patch) | |
tree | 3aa0381dfeb3beb6965616b0066dfd3ed21714e0 | |
parent | don't set BGE_DEBUG by default, reduces the bloat a bit. noticed by deraadt. (diff) | |
download | wireguard-openbsd-9a571ad92f0369e28994ebefe4761c6127d9efb3.tar.xz wireguard-openbsd-9a571ad92f0369e28994ebefe4761c6127d9efb3.zip |
add new event rules to match optional elements of radiotap headers:
signal percentage, transmit rate and channel frequency.
ok and hints by jsg@ jmc@
-rw-r--r-- | usr.sbin/hostapd/handle.c | 127 | ||||
-rw-r--r-- | usr.sbin/hostapd/hostapd.conf.5 | 56 | ||||
-rw-r--r-- | usr.sbin/hostapd/hostapd.h | 31 | ||||
-rw-r--r-- | usr.sbin/hostapd/parse.y | 160 |
4 files changed, 364 insertions, 10 deletions
diff --git a/usr.sbin/hostapd/handle.c b/usr.sbin/hostapd/handle.c index bbe169a0a1f..58c3477b58a 100644 --- a/usr.sbin/hostapd/handle.c +++ b/usr.sbin/hostapd/handle.c @@ -1,7 +1,7 @@ -/* $OpenBSD: handle.c,v 1.9 2006/06/01 22:09:09 reyk Exp $ */ +/* $OpenBSD: handle.c,v 1.10 2006/06/27 18:14:59 reyk Exp $ */ /* - * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2005, 2006 Reyk Floeter <reyk@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -33,6 +33,9 @@ #include <netinet/if_ether.h> #include <arpa/inet.h> +#include <net80211/ieee80211.h> +#include <net80211/ieee80211_radiotap.h> + #include <fcntl.h> #include <stdlib.h> #include <stdio.h> @@ -49,6 +52,9 @@ void hostapd_handle_addr(const u_int32_t, u_int32_t *, u_int8_t *, u_int8_t *, struct hostapd_table *); void hostapd_handle_ref(u_int, u_int, u_int8_t *, u_int8_t *, u_int8_t *, u_int8_t *); +int hostapd_handle_radiotap(struct hostapd_radiotap *, u_int8_t *, + const u_int); +int hostapd_cmp(enum hostapd_op, int, int); int hostapd_handle_input(struct hostapd_apme *apme, u_int8_t *buf, u_int len) @@ -103,12 +109,14 @@ int hostapd_handle_frame(struct hostapd_apme *apme, struct hostapd_frame *frame, u_int8_t *buf, const u_int len) { + struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg; struct ieee80211_frame *wh; struct hostapd_ieee80211_frame *mh; + struct hostapd_radiotap rtap; u_int8_t *wfrom, *wto, *wbssid; struct timeval t_now; u_int32_t flags; - int offset, min_rate = 0; + int offset, min_rate = 0, val; if ((offset = hostapd_apme_offset(apme, buf, len)) < 0) return (0); @@ -203,6 +211,35 @@ hostapd_handle_frame(struct hostapd_apme *apme, struct hostapd_frame *frame, hostapd_handle_addr(HOSTAPD_FRAME_F_BSSID_M, &flags, wbssid, mh->i_bssid, frame->f_bssid); + /* parse the optional radiotap header if required */ + if (frame->f_radiotap) { + if (hostapd_handle_radiotap(&rtap, buf, len) != 0) + return (0); + else if ((rtap.r_present & frame->f_radiotap) != + frame->f_radiotap) { + cfg->c_stats.cn_rtap_miss++; + return (0); + } + if (flags & HOSTAPD_FRAME_F_RSSI && rtap.r_max_rssi) { + val = ((float)rtap.r_rssi / rtap.r_max_rssi) * 100; + if (hostapd_cmp(frame->f_rssi_op, + val, frame->f_rssi)) + flags &= ~HOSTAPD_FRAME_F_RSSI; + } + if (flags & HOSTAPD_FRAME_F_RATE) { + val = rtap.r_txrate; + if (hostapd_cmp(frame->f_txrate_op, + val, frame->f_txrate)) + flags &= ~HOSTAPD_FRAME_F_RATE; + } + if (flags & HOSTAPD_FRAME_F_CHANNEL) { + val = rtap.r_chan; + if (hostapd_cmp(frame->f_chan_op, + val, frame->f_chan)) + flags &= ~HOSTAPD_FRAME_F_CHANNEL; + } + } + /* Handle if frame matches */ if ((flags & HOSTAPD_FRAME_F_M) != 0) return (0); @@ -347,3 +384,87 @@ hostapd_handle_action(struct hostapd_apme *apme, struct hostapd_frame *frame, return (ret); } + +int +hostapd_handle_radiotap(struct hostapd_radiotap *rtap, + u_int8_t *buf, const u_int len) +{ + struct ieee80211_radiotap_header *rh = + (struct ieee80211_radiotap_header*)buf; + u_int8_t *t, *ptr = NULL; + u_int rh_len; + const u_int8_t *snapend = buf + len; + + TCHECK(*rh); + + rh_len = letoh16(rh->it_len); + if (rh->it_version != 0) + return (EINVAL); + if (len <= rh_len) + goto trunc; + + bzero(rtap, sizeof(struct hostapd_radiotap)); + + t = (u_int8_t*)buf + sizeof(struct ieee80211_radiotap_header); + if ((rtap->r_present = letoh32(rh->it_present)) == 0) + return (0); + +#define RADIOTAP(_x, _len) \ + if (rtap->r_present & HOSTAPD_RADIOTAP_F(_x)) { \ + TCHECK2(*t, _len); \ + ptr = t; \ + t += _len; \ + } else \ + ptr = NULL; + + /* radiotap doesn't use TLV header fields, ugh */ + RADIOTAP(TSFT, 8); + RADIOTAP(FLAGS, 1); + + RADIOTAP(RATE, 1); + if (ptr != NULL) { + rtap->r_txrate = *(u_int8_t *)ptr; + } + + RADIOTAP(CHANNEL, 4); + if (ptr != NULL) { + rtap->r_chan = letoh16(*(u_int16_t*)ptr); + rtap->r_chan_flags = letoh16(*(u_int16_t*)ptr + 1); + } + + RADIOTAP(FHSS, 2); + RADIOTAP(DBM_ANTSIGNAL, 1); + RADIOTAP(DBM_ANTNOISE, 1); + RADIOTAP(LOCK_QUALITY, 2); + RADIOTAP(TX_ATTENUATION, 2); + RADIOTAP(DB_TX_ATTENUATION, 2); + RADIOTAP(DBM_TX_POWER, 1); + RADIOTAP(ANTENNA, 1); + RADIOTAP(DB_ANTSIGNAL, 1); + RADIOTAP(DB_ANTNOISE, 1); + RADIOTAP(FCS, 4); + + RADIOTAP(RSSI, 2); + if (ptr != NULL) { + rtap->r_rssi = *(u_int8_t *)ptr; + rtap->r_max_rssi = *(u_int8_t *)ptr + 1; + } + + return (0); + + trunc: + return (EINVAL); +} + +int +hostapd_cmp(enum hostapd_op op, int val1, int val2) +{ + if ((op == HOSTAPD_OP_EQ && val1 == val2) || + (op == HOSTAPD_OP_NE && val1 != val2) || + (op == HOSTAPD_OP_LE && val1 <= val2) || + (op == HOSTAPD_OP_LT && val1 < val2) || + (op == HOSTAPD_OP_GE && val1 >= val2) || + (op == HOSTAPD_OP_GT && val1 > val2)) + return (1); + return (0); +} diff --git a/usr.sbin/hostapd/hostapd.conf.5 b/usr.sbin/hostapd/hostapd.conf.5 index d012beddd84..9a46a936a4f 100644 --- a/usr.sbin/hostapd/hostapd.conf.5 +++ b/usr.sbin/hostapd/hostapd.conf.5 @@ -1,6 +1,6 @@ -.\" $OpenBSD: hostapd.conf.5,v 1.32 2006/05/15 21:09:49 reyk Exp $ +.\" $OpenBSD: hostapd.conf.5,v 1.33 2006/06/27 18:14:59 reyk Exp $ .\" -.\" Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org> +.\" Copyright (c) 2004, 2005, 2006 Reyk Floeter <reyk@openbsd.org> .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -304,6 +304,7 @@ Match all frames. .Op Ar from .Op Ar to .Op Ar bssid +.Op Ar radiotap .Xc Apply rules to frames matching the given parameters. The parameters are explained below. @@ -360,6 +361,51 @@ section below for available direction specifications. .El .Pp The +.Ar radiotap +rules allow parsing and matching of the extra information reported by +the radiotap header. +Support for the specified radiotap headers is optional and the +specific parameters depend on the radiotap elements reported +by the wireless interface. +Support for the radiotap data link type can be verified with the +.Xr tcpdump 8 +command. +These rules require +.Ic hostap mode radiotap +in the global configuration. +.Bl -tag -width Ds +.It Xo +.Ic signal +.Op Ic operator +.Ar percentage Ic % +.Xc +Match the signal quality of the received frame. +.It Xo +.Ic freq +.Op Ic operator +.Ar value Ic ( GHz \*(Ba MHz ) +.Xc +Match the transmit rate of the received frame. +.It Xo +.Ic txrate +.Op Ic operator +.Ar rate Ic Mb +.Xc +Match the frequency of the received frame. +.El +.Pp +The radiotap rules support the following operators. +If omitted, the specified value will be checked if it is equal or not. +.Bd -literal -offset indent += (equal) +!= (not equal) +\*(Lt (less than) +\*(Le (less than or equal) +\*(Gt (greater than) +\*(Ge (greater than or equal) +.Ed +.Pp +The .Ar from , to , and .Ar bssid @@ -667,6 +713,12 @@ hostap handle on ath0 type management subtype auth with resend # Remove a blacklisted node from the kernel node tree hostap handle type management subtype auth from <blacklist> \e with node delete &from + +# Log rogue accesspoints with a strong signal quality on +# channel 3 (2.422GHz) transmitting frames with 1Mb. +hostap handle type management subtype beacon bssid !<myess> \e + signal >= 50% txrate 1Mb freq 2.422GHz \e + with log .Ed .Sh IP ROAMING In a traditional wireless network, multiple access points are diff --git a/usr.sbin/hostapd/hostapd.h b/usr.sbin/hostapd/hostapd.h index 1d5c439c3e9..e29f460e631 100644 --- a/usr.sbin/hostapd/hostapd.h +++ b/usr.sbin/hostapd/hostapd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hostapd.h,v 1.17 2006/05/15 20:53:02 reyk Exp $ */ +/* $OpenBSD: hostapd.h,v 1.18 2006/06/27 18:14:59 reyk Exp $ */ /* * Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org> @@ -73,6 +73,7 @@ struct hostapd_counter { u_int64_t cn_tx_iapp; /* sent IAPP messages */ u_int64_t cn_rx_apme; /* received Host AP messages */ u_int64_t cn_tx_apme; /* sent Host AP messages */ + u_int64_t cn_rtap_miss; /* missing radiotap field */ }; #define HOSTAPD_ENTRY_MASK_ADD(_a, _m) do { \ @@ -139,6 +140,16 @@ struct hostapd_table { TAILQ_ENTRY(hostapd_table) t_entries; }; +struct hostapd_radiotap { + u_int32_t r_present; + u_int8_t r_txrate; + u_int16_t r_chan; + u_int16_t r_chan_flags; + u_int8_t r_rssi; + u_int8_t r_max_rssi; +}; +#define HOSTAPD_RADIOTAP_F(_x) (1 << IEEE80211_RADIOTAP_##_x) + struct hostapd_ieee80211_frame { u_int8_t i_fc[2]; u_int8_t i_dur[2]; @@ -160,6 +171,15 @@ enum hostapd_action { HOSTAPD_ACTION_RESEND = 6 }; +enum hostapd_op { + HOSTAPD_OP_EQ = 0, + HOSTAPD_OP_NE = 1, + HOSTAPD_OP_LE = 2, + HOSTAPD_OP_LT = 3, + HOSTAPD_OP_GE = 4, + HOSTAPD_OP_GT = 5 +}; + struct hostapd_action_data { union { struct hostapd_ieee80211_frame u_frame; @@ -188,6 +208,8 @@ struct hostapd_action_data { struct hostapd_frame { struct hostapd_ieee80211_frame f_frame; + u_int32_t f_radiotap; + u_int32_t f_flags; #define HOSTAPD_FRAME_F_TYPE 0x00000001 @@ -211,6 +233,10 @@ struct hostapd_frame { #define HOSTAPD_FRAME_F_APME 0x00008000 #define HOSTAPD_FRAME_F_APME_N 0x00010000 #define HOSTAPD_FRAME_F_APME_M 0x00018000 +#define HOSTAPD_FRAME_F_RSSI 0x00020000 +#define HOSTAPD_FRAME_F_RATE 0x00040000 +#define HOSTAPD_FRAME_F_CHANNEL 0x00080000 +#define HOSTAPD_FRAME_F_RADIOTAP_M 0x000e0000 #define HOSTAPD_FRAME_F_M 0x0fffffff #define HOSTAPD_FRAME_F_RET_OK 0x00000000 #define HOSTAPD_FRAME_F_RET_QUICK 0x10000000 @@ -231,6 +257,9 @@ struct hostapd_frame { long f_rate, f_rate_intval; long f_rate_cnt, f_rate_delay; + enum hostapd_op f_rssi_op, f_txrate_op, f_chan_op; + short f_rssi, f_txrate, f_chan; + enum hostapd_action f_action; u_int32_t f_action_flags; diff --git a/usr.sbin/hostapd/parse.y b/usr.sbin/hostapd/parse.y index 0ac01148b82..8ca6cd902c5 100644 --- a/usr.sbin/hostapd/parse.y +++ b/usr.sbin/hostapd/parse.y @@ -1,7 +1,7 @@ -/* $OpenBSD: parse.y,v 1.23 2006/06/01 22:09:09 reyk Exp $ */ +/* $OpenBSD: parse.y,v 1.24 2006/06/27 18:14:59 reyk Exp $ */ /* - * Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2004, 2005, 2006 Reyk Floeter <reyk@openbsd.org> * Copyright (c) 2002 - 2005 Henning Brauer <henning@openbsd.org> * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. @@ -40,6 +40,9 @@ #include <netinet/if_ether.h> #include <arpa/inet.h> +#include <net80211/ieee80211.h> +#include <net80211/ieee80211_radiotap.h> + #include <ctype.h> #include <errno.h> #include <event.h> @@ -101,6 +104,7 @@ typedef struct { char *string; long val; u_int16_t reason; + enum hostapd_op op; } v; int lineno; } YYSTYPE; @@ -119,12 +123,23 @@ u_int negative; frame.f_flags |= HOSTAPD_FRAME_F_##_m##_TABLE | (negative ? \ HOSTAPD_FRAME_F_##_m##_N : HOSTAPD_FRAME_F_##_m); \ } +#define HOSTAPD_MATCH_RADIOTAP(_x) { \ + if (hostapd_cfg.c_apme_dlt == DLT_IEEE802_11 || \ + (hostapd_cfg.c_apme_dlt == 0 && \ + HOSTAPD_DLT == DLT_IEEE802_11)) { \ + yyerror("option %s requires radiotap headers", #_x); \ + YYERROR; \ + } \ + frame.f_radiotap |= HOSTAPD_RADIOTAP_F(RSSI); \ + frame.f_flags |= HOSTAPD_FRAME_F_##_x; \ +} #define HOSTAPD_IAPP_FLAG(_f) { \ if (negative) \ hostapd_cfg.c_iapp.i_flags &= ~(HOSTAPD_IAPP_F_##_f); \ else \ hostapd_cfg.c_iapp.i_flags |= (HOSTAPD_IAPP_F_##_f); \ } + %} %token MODE INTERFACE IAPP HOSTAP MULTICAST BROADCAST SET SEC USEC @@ -134,7 +149,7 @@ u_int negative; %token ERROR CONST TABLE NODE DELETE ADD LOG VERBOSE LIMIT QUICK SKIP %token REASON UNSPECIFIED EXPIRE LEAVE ASSOC TOOMANY NOT AUTHED ASSOCED %token RESERVED RSN REQUIRED INCONSISTENT IE INVALID MIC FAILURE OPEN -%token ADDRESS PORT ON NOTIFY TTL INCLUDE ROUTE ROAMING +%token ADDRESS PORT ON NOTIFY TTL INCLUDE ROUTE ROAMING RSSI TXRATE FREQ %token <v.string> STRING %token <v.val> VALUE %type <v.val> number @@ -144,6 +159,10 @@ u_int negative; %type <v.string> table %type <v.string> string %type <v.authalg> authalg +%type <v.op> unaryop +%type <v.val> percent +%type <v.val> txrate +%type <v.val> freq %% @@ -410,7 +429,7 @@ nodeopt : DELETE frmmatch : ANY | frm frmmatchtype frmmatchdir frmmatchfrom frmmatchto - frmmatchbssid + frmmatchbssid frmmatchrtap ; frm : /* empty */ @@ -710,6 +729,42 @@ frmmatchbssid : /* any */ } ; +frmmatchrtap : /* empty */ + | frmmatchrtap_l + ; + +frmmatchrtap_l : frmmatchrtap_l frmmatchrtapopt + | frmmatchrtapopt + ; + +frmmatchrtapopt : RSSI unaryop percent + { + if (($2 == HOSTAPD_OP_GT && $3 == 100) || + ($2 == HOSTAPD_OP_LE && $3 == 100) || + ($2 == HOSTAPD_OP_LT && $3 == 0) || + ($2 == HOSTAPD_OP_GE && $3 == 0)) { + yyerror("absurd unary comparison"); + YYERROR; + } + + frame.f_rssi_op = $2; + frame.f_rssi = $3; + HOSTAPD_MATCH_RADIOTAP(RSSI); + } + | TXRATE unaryop txrate + { + frame.f_txrate_op = $2; + frame.f_txrate = $3; + HOSTAPD_MATCH_RADIOTAP(RATE); + } + | FREQ unaryop freq + { + frame.f_chan_op = $2; + frame.f_chan = $3; + HOSTAPD_MATCH_RADIOTAP(CHANNEL); + } + ; + frmmatchaddr : ANY { $$.flags = 0; @@ -997,6 +1052,100 @@ not : /* empty */ } ; +unaryop : /* any */ + { + $$ = HOSTAPD_OP_EQ; + } + | '=' + { + $$ = HOSTAPD_OP_EQ; + } + | '==' + { + $$ = HOSTAPD_OP_EQ; + } + | '!' + { + $$ = HOSTAPD_OP_NE; + } + | '!' '=' + { + $$ = HOSTAPD_OP_NE; + } + | '<' '=' + { + $$ = HOSTAPD_OP_LE; + } + | '<' + { + $$ = HOSTAPD_OP_LT; + } + | '>' '=' + { + $$ = HOSTAPD_OP_GE; + } + | '>' + { + $$ = HOSTAPD_OP_GT; + } + ; + +percent : STRING + { + double val; + char *cp; + + val = strtod($1, &cp); + if (cp == NULL || strcmp(cp, "%") != 0 || + val < 0 || val > 100) { + yyerror("invalid percentage: %s", $1); + free($1); + YYERROR; + } + free($1); + $$ = val; + } + ; + +txrate : STRING + { + double val; + char *cp; + + val = strtod($1, &cp) * 2; + if (cp == NULL || strcasecmp(cp, "mb") != 0 || + val != (int)val) { + yyerror("invalid rate: %s", $1); + free($1); + YYERROR; + } + free($1); + $$ = val; + } + ; + +freq : STRING + { + double val; + char *cp; + + val = strtod($1, &cp); + if (cp != NULL) { + if (strcasecmp(cp, "ghz") == 0) { + $$ = val * 1000; + } else if (strcasecmp(cp, "mhz") == 0) { + $$ = val; + } else + cp = NULL; + } + if (cp == NULL) { + yyerror("invalid frequency: %s", $1); + free($1); + YYERROR; + } + free($1); + } + ; %% /* @@ -1040,6 +1189,7 @@ lookup(char *token) { "expire", EXPIRE }, { "failure", FAILURE }, { "frame", FRAME }, + { "freq", FREQ }, { "from", FROM }, { "handle", HANDLE }, { "hostap", HOSTAP }, @@ -1083,12 +1233,14 @@ lookup(char *token) { "rsn", RSN }, { "sec", SEC }, { "set", SET }, + { "signal", RSSI }, { "skip", SKIP }, { "subtype", SUBTYPE }, { "table", TABLE }, { "to", TO }, { "toomany", TOOMANY }, { "ttl", TTL }, + { "txrate", TXRATE }, { "type", TYPE }, { "unspecified", UNSPECIFIED }, { "usec", USEC }, |