[PATCH] Write client (dis)associations to a logfile

Stefan Tomanek stefan.tomanek at wertarbyte.de
Sun Jan 11 05:22:30 EST 2015


This change adds the configuration option "assoc_log_file" to hostapd, making
it possible to specify a log file to which clients joining and parting the
corresponding BSS are written.

Every BSS can have an individual log file, and each entry written contains a
timestamp, an indicator whether the client is associating (+) or disaccociating
(-), the client and the bss hardware addresses and the SSID identifier of the
affected network. This makes it easy to join the file with the leases database
of an DHCP server like dnsmasq.

Signed-off-by: Stefan Tomanek <stefan.tomanek at wertarbyte.de>
---
 hostapd/config_file.c |  3 +++
 hostapd/hostapd.conf  |  3 +++
 hostapd/main.c        |  6 ++++++
 src/ap/ap_config.c    | 27 +++++++++++++++++++++++++++
 src/ap/ap_config.h    |  5 +++++
 src/ap/ap_mlme.c      | 25 +++++++++++++++++++++++++
 src/ap/hostapd.c      |  4 ++++
 src/ap/hostapd.h      |  2 ++
 8 files changed, 75 insertions(+)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index e30efbe..145fad1 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1881,6 +1881,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 		bss->logger_syslog = atoi(pos);
 	} else if (os_strcmp(buf, "logger_stdout") == 0) {
 		bss->logger_stdout = atoi(pos);
+	} else if (os_strcmp(buf, "assoc_log_file") == 0) {
+		os_free(bss->assoc_log_file);
+		bss->assoc_log_file = os_strdup(pos);
 	} else if (os_strcmp(buf, "dump_file") == 0) {
 		wpa_printf(MSG_INFO, "Line %d: DEPRECATED: 'dump_file' configuration variable is not used anymore",
 			   line);
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 2f6126c..6635d9b 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -54,6 +54,9 @@ logger_syslog_level=2
 logger_stdout=-1
 logger_stdout_level=2
 
+# Clients joining or departing the AP can be logged to a separate file.
+assoc_log_file=/tmp/assoc_log-wlan0
+
 # Interface for separate control program. If this is specified, hostapd
 # will create this directory and a UNIX domain socket for listening to requests
 # from external programs (CLI/GUI, etc.) for status information and
diff --git a/hostapd/main.c b/hostapd/main.c
index 3ecd009..40dba1d 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -265,6 +265,12 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
 		return NULL;
 	}
 
+	for (k = 0; k < iface->conf->num_bss; k++) {
+		int r = hostapd_open_assoc_log(iface->bss[k]);
+		if (r < 0)
+			return NULL;
+	}
+
 	return iface;
 }
 
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 1c0ed7a..cc1ff46 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -6,6 +6,8 @@
  * See README for more details.
  */
 
+#include <fcntl.h>
+
 #include "utils/includes.h"
 
 #include "utils/common.h"
@@ -18,6 +20,7 @@
 #include "wpa_auth.h"
 #include "sta_info.h"
 #include "ap_config.h"
+#include "hostapd.h"
 
 
 static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
@@ -201,6 +204,30 @@ int hostapd_mac_comp_empty(const void *a)
 	return os_memcmp(a, empty, sizeof(macaddr));
 }
 
+int hostapd_open_assoc_log(struct hostapd_data *bss)
+{
+	char *alog = bss->conf->assoc_log_file;
+	if (alog) {
+		int fd = open(alog, O_WRONLY | O_APPEND | O_CREAT | O_NOFOLLOW, 0600);
+		if (fd < 0) {
+			wpa_printf(MSG_ERROR, "Error opening association log file '%s'\n", alog);
+			return -1;
+		}
+		bss->assoc_log_fd = fd;
+		return 1;
+	} else {
+		bss->assoc_log_fd = -1;
+	}
+	return 0;
+}
+
+void hostapd_close_assoc_log(struct hostapd_data *bss)
+{
+	if (bss->assoc_log_fd != -1) {
+		close(bss->assoc_log_fd);
+		bss->assoc_log_fd = -1;
+	}
+}
 
 static int hostapd_config_read_wpa_psk(const char *fname,
 				       struct hostapd_ssid *ssid)
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 58af6cb..e0e4fe8 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -221,6 +221,8 @@ struct hostapd_bss_config {
 	unsigned int logger_syslog; /* module bitfield */
 	unsigned int logger_stdout; /* module bitfield */
 
+	char *assoc_log_file;
+
 	int max_num_sta; /* maximum number of STAs in station table */
 
 	int dtim_period;
@@ -640,6 +642,9 @@ struct hostapd_config {
 #endif /* CONFIG_ACS */
 };
 
+struct hostapd_data;
+int hostapd_open_assoc_log(struct hostapd_data *bss);
+void hostapd_close_assoc_log(struct hostapd_data *bss);
 
 int hostapd_mac_comp(const void *a, const void *b);
 int hostapd_mac_comp_empty(const void *a);
diff --git a/src/ap/ap_mlme.c b/src/ap/ap_mlme.c
index 13604ed..067158a 100644
--- a/src/ap/ap_mlme.c
+++ b/src/ap/ap_mlme.c
@@ -35,6 +35,22 @@ static const char * mlme_auth_alg_str(int alg)
 }
 #endif /* CONFIG_NO_HOSTAPD_LOGGER */
 
+static void write_assoc_log(struct hostapd_data *hapd, struct sta_info *sta, char op) {
+	struct os_time now;
+	int fd = hapd->assoc_log_fd;
+	if (fd >= 0) {
+		os_get_time(&now);
+		char msg[100];
+		sprintf(msg,
+		        "%lu\t%c\t" MACSTR "\t" MACSTR "\t'%s'\n",
+		        now.sec,
+			op,
+		        MAC2STR(sta->addr),
+		        MAC2STR(hapd->own_addr),
+		        wpa_ssid_txt(sta->ssid->ssid, sta->ssid->ssid_len));
+		write(fd, msg, strlen(msg));
+	}
+}
 
 /**
  * mlme_authenticate_indication - Report the establishment of an authentication
@@ -104,6 +120,9 @@ void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
 		       HOSTAPD_LEVEL_DEBUG,
 		       "MLME-ASSOCIATE.indication(" MACSTR ")",
 		       MAC2STR(sta->addr));
+
+	write_assoc_log(hapd, sta, '+');
+
 	if (sta->auth_alg != WLAN_AUTH_FT)
 		mlme_deletekeys_request(hapd, sta);
 }
@@ -128,6 +147,9 @@ void mlme_reassociate_indication(struct hostapd_data *hapd,
 		       HOSTAPD_LEVEL_DEBUG,
 		       "MLME-REASSOCIATE.indication(" MACSTR ")",
 		       MAC2STR(sta->addr));
+
+	write_assoc_log(hapd, sta, '@');
+
 	if (sta->auth_alg != WLAN_AUTH_FT)
 		mlme_deletekeys_request(hapd, sta);
 }
@@ -152,6 +174,9 @@ void mlme_disassociate_indication(struct hostapd_data *hapd,
 		       HOSTAPD_LEVEL_DEBUG,
 		       "MLME-DISASSOCIATE.indication(" MACSTR ", %d)",
 		       MAC2STR(sta->addr), reason_code);
+
+	write_assoc_log(hapd, sta, '-');
+
 	mlme_deletekeys_request(hapd, sta);
 }
 
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 6e4169b..a449e78 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -73,6 +73,10 @@ static void hostapd_reload_bss(struct hostapd_data *hapd)
 	radius_client_reconfig(hapd->radius, hapd->conf->radius);
 #endif /* CONFIG_NO_RADIUS */
 
+	/* close and reopen assoc_log */
+	hostapd_close_assoc_log(hapd);
+	hostapd_open_assoc_log(hapd);
+
 	ssid = &hapd->conf->ssid;
 	if (!ssid->wpa_psk_set && ssid->wpa_psk && !ssid->wpa_psk->next &&
 	    ssid->wpa_passphrase_set && ssid->wpa_passphrase) {
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 8e2c70e..91018a8 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -114,6 +114,8 @@ struct hostapd_data {
 #define STA_HASH(sta) (sta[5])
 	struct sta_info *sta_hash[STA_HASH_SIZE];
 
+	int assoc_log_fd;
+
 	/*
 	 * Bitfield for indicating which AIDs are allocated. Only AID values
 	 * 1-2007 are used and as such, the bit at index 0 corresponds to AID
-- 
2.1.3


More information about the HostAP mailing list