From 0d79f50fb052bf47c6b823bd922dd6092f62f919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benoit=20Gr=C3=A9goire?= Date: Thu, 28 Jun 2007 01:48:01 +0000 Subject: [PATCH] * util.c: Fix while loop initialisation bug * conf.h: Forgot to change the value of NUM_EXT_INTERFACE_DETECT_RETRY to actually make it wait forever. * Remove hardcoded authserver paths. Can now be defined in the config file (auth server section). * Centralise browser redirect code to simplify code * Add manual logout URL, based in part on work by David Bird * Release 1.1.3 final --- ChangeLog | 8 ++ configure.in | 2 +- contrib/build-openwrt-ipk/wifidog/Makefile | 2 +- src/auth.c | 96 +++---------- src/centralserver.c | 19 ++- src/centralserver.h | 9 ++ src/conf.c | 46 ++++++ src/conf.h | 14 +- src/firewall.c | 7 +- src/fw_iptables.c | 6 +- src/http.c | 155 ++++++++++++++++----- src/http.h | 4 + src/ping_thread.c | 12 +- src/util.c | 9 +- wifidog.conf | 19 ++- 15 files changed, 264 insertions(+), 144 deletions(-) diff --git a/ChangeLog b/ChangeLog index 509b26c3..ad07a3c9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,12 @@ # $Id$ +2007-06-27 Benoit Grégoire + * util.c: Fix while loop initialisation bug + * conf.h: Forgot to change the value of NUM_EXT_INTERFACE_DETECT_RETRY to actually make it wait forever. + * Remove hardcoded authserver paths. Can now be defined in the config file (auth server section). + * Centralise browser redirect code to simplify code + * Add manual logout URL, based in part on work by David Bird + * Release 1.1.3 final + 2007-06-24 Benoit Grégoire * Close #321: Make the Gateway retry forever if it cannot find it's interface. You never know when someone may finally replug the network cable or something... * Close #332: Apply patch from Laurent Marchal. biguphpcgmailcom diff --git a/configure.in b/configure.in index fd74093d..c86f3834 100644 --- a/configure.in +++ b/configure.in @@ -20,7 +20,7 @@ AC_SUBST(BUILDROOT) WIFIDOG_MAJOR_VERSION=1 WIFIDOG_MINOR_VERSION=1 -WIFIDOG_MICRO_VERSION=3_rc1 +WIFIDOG_MICRO_VERSION=3 WIFIDOG_VERSION=$WIFIDOG_MAJOR_VERSION.$WIFIDOG_MINOR_VERSION.$WIFIDOG_MICRO_VERSION AC_SUBST(WIFIDOG_MAJOR_VERSION) diff --git a/contrib/build-openwrt-ipk/wifidog/Makefile b/contrib/build-openwrt-ipk/wifidog/Makefile index 3a6c34bc..1f79477a 100644 --- a/contrib/build-openwrt-ipk/wifidog/Makefile +++ b/contrib/build-openwrt-ipk/wifidog/Makefile @@ -6,7 +6,7 @@ endif include $(TOPDIR)/rules.mk PKG_NAME:=wifidog -PKG_VERSION:=1.1.3_rc1 +PKG_VERSION:=1.1.3 PKG_RELEASE:=1 PKG_MD5SUM:=842b21e1b02d0a90677b289d794e0e21 PKG_SOURCE_URL:= @SF/$(PKG_NAME) diff --git a/src/auth.c b/src/auth.c index a7eee6b6..907eaaac 100644 --- a/src/auth.c +++ b/src/auth.c @@ -98,11 +98,9 @@ authenticate_client(request *r) char *ip, *mac, *token; - char *newlocation = NULL; - char *protocol = NULL; + char *urlFragment = NULL; s_config *config = NULL; t_auth_serv *auth_server = NULL; - int port = 80; LOCK_CLIENT_LIST(); @@ -146,14 +144,6 @@ authenticate_client(request *r) config = config_get_config(); auth_server = get_auth_server(); - if (auth_server->authserv_use_ssl) { - protocol = "https"; - port = auth_server->authserv_ssl_port; - } else { - protocol = "http"; - port = auth_server->authserv_http_port; - } - switch(auth_response.authcode) { case AUTH_ERROR: @@ -167,23 +157,12 @@ authenticate_client(request *r) case AUTH_DENIED: /* Central server said invalid token */ debug(LOG_INFO, "Got DENIED from central server authenticating token %s from %s at %s - redirecting them to denied message", client->token, client->ip, client->mac); - safe_asprintf(&newlocation, "Location: %s://%s:%d%sgw_message.php?message=denied", - protocol, - auth_server->authserv_hostname, - port, - auth_server->authserv_path - ); - httpdSetResponse(r, "307 Redirect to denied message\n"); - httpdAddHeader(r, newlocation); - free(newlocation); - http_wifidog_header(r, "Redirection to message"); - httpdPrintf(r, "Please click here.", - protocol, - auth_server->authserv_hostname, - port, - auth_server->authserv_path + safe_asprintf(&urlFragment, "%smessage=%s", + auth_server->authserv_msg_script_path_fragment, + GATEWAY_MESSAGE_DENIED ); - http_wifidog_footer(r); + http_send_redirect_to_auth(r, urlFragment, "Redirect to denied message"); + free(urlFragment); break; case AUTH_VALIDATION: @@ -193,23 +172,12 @@ authenticate_client(request *r) client->ip, client->mac); client->fw_connection_state = FW_MARK_PROBATION; fw_allow(client->ip, client->mac, FW_MARK_PROBATION); - safe_asprintf(&newlocation, "Location: %s://%s:%d%sgw_message.php?message=activate", - protocol, - auth_server->authserv_hostname, - port, - auth_server->authserv_path - ); - httpdSetResponse(r, "307 Redirect to activate message\n"); - httpdAddHeader(r, newlocation); - free(newlocation); - http_wifidog_header(r, "Redirection to message"); - httpdPrintf(r, "Please click here.", - protocol, - auth_server->authserv_hostname, - port, - auth_server->authserv_path + safe_asprintf(&urlFragment, "%smessage=%s", + auth_server->authserv_msg_script_path_fragment, + GATEWAY_MESSAGE_ACTIVATE_ACCOUNT ); - http_wifidog_footer(r); + http_send_redirect_to_auth(r, urlFragment, "Redirect to activate message"); + free(urlFragment); break; case AUTH_ALLOWED: @@ -219,48 +187,24 @@ authenticate_client(request *r) client->fw_connection_state = FW_MARK_KNOWN; fw_allow(client->ip, client->mac, FW_MARK_KNOWN); served_this_session++; - safe_asprintf(&newlocation, "Location: %s://%s:%d%sportal/?gw_id=%s", - protocol, - auth_server->authserv_hostname, - port, - auth_server->authserv_path, + safe_asprintf(&urlFragment, "%sgw_id=%s", + auth_server->authserv_portal_script_path_fragment, config->gw_id ); - httpdSetResponse(r, "307 Redirect to portal\n"); - httpdAddHeader(r, newlocation); - free(newlocation); - http_wifidog_header(r, "Redirection to portal"); - httpdPrintf(r, "Please click here for the portal.", - protocol, - auth_server->authserv_hostname, - port, - auth_server->authserv_path, - config->gw_id - ); - http_wifidog_footer(r); + http_send_redirect_to_auth(r, urlFragment, "Redirect to portal"); + free(urlFragment); break; case AUTH_VALIDATION_FAILED: /* Client had X minutes to validate account by email and didn't = too late */ debug(LOG_INFO, "Got VALIDATION_FAILED from central server authenticating token %s from %s at %s " "- redirecting them to failed_validation message", client->token, client->ip, client->mac); - safe_asprintf(&newlocation, "Location: %s://%s:%d%sgw_message.php?message=failed_validation", - protocol, - auth_server->authserv_hostname, - port, - auth_server->authserv_path + safe_asprintf(&urlFragment, "%smessage=%s", + auth_server->authserv_msg_script_path_fragment, + GATEWAY_MESSAGE_ACCOUNT_VALIDATION_FAILED ); - httpdSetResponse(r, "307 Redirect to failed validation message\n"); - httpdAddHeader(r, newlocation); - free(newlocation); - http_wifidog_header(r, "Redirection to message"); - httpdPrintf(r, "Please click here.", - protocol, - auth_server->authserv_hostname, - port, - auth_server->authserv_path - ); - http_wifidog_footer(r); + http_send_redirect_to_auth(r, urlFragment, "Redirect to failed validation message"); + free(urlFragment); break; default: diff --git a/src/centralserver.c b/src/centralserver.c index 7ff37bb3..43118551 100644 --- a/src/centralserver.c +++ b/src/centralserver.c @@ -69,7 +69,9 @@ auth_server_request(t_authresponse *authresponse, char *request_type, char *ip, int done, nfds; fd_set readfds; struct timeval timeout; - + t_auth_serv *auth_server = NULL; + auth_server = get_auth_server(); + /* Blanket default is error. */ authresponse->authcode = AUTH_ERROR; @@ -85,13 +87,20 @@ auth_server_request(t_authresponse *authresponse, char *request_type, char *ip, */ memset(buf, 0, sizeof(buf)); snprintf(buf, (sizeof(buf) - 1), - "GET %sauth/?stage=%s&ip=%s&mac=%s&token=%s&incoming=%llu&outgoing=%llu HTTP/1.0\r\n" + "GET %s%sstage=%s&ip=%s&mac=%s&token=%s&incoming=%llu&outgoing=%llu HTTP/1.0\r\n" "User-Agent: WiFiDog %s\r\n" "Host: %s\r\n" "\r\n", - config_get_config()->auth_servers->authserv_path, request_type, ip, mac, token, incoming, outgoing, - VERSION, - config_get_config()->auth_servers->authserv_hostname + auth_server->authserv_path, + auth_server->authserv_auth_script_path_fragment, + request_type, + ip, + mac, + token, + incoming, + outgoing, + VERSION, + auth_server->authserv_hostname ); debug(LOG_DEBUG, "Sending HTTP request to auth server: [%s]\n", buf); diff --git a/src/centralserver.h b/src/centralserver.h index 96cbe09c..6ddb1203 100644 --- a/src/centralserver.h +++ b/src/centralserver.h @@ -34,6 +34,15 @@ /** @brief Update the central server's traffic counters */ #define REQUEST_TYPE_COUNTERS "counters" +/** @brief Sent when the user's token is denied by the central server */ +#define GATEWAY_MESSAGE_DENIED "denied" +/** @brief Sent when the user's token is accepted, but user is on probation */ +#define GATEWAY_MESSAGE_ACTIVATE_ACCOUNT "activate" +/** @brief Sent when the user's token is denied by the central server because the probation period is over */ +#define GATEWAY_MESSAGE_ACCOUNT_VALIDATION_FAILED "failed_validation" +/** @brief Sent after the user performed a manual log-out on the gateway */ +#define GATEWAY_MESSAGE_ACCOUNT_LOGGED_OUT "logged-out" + /** @brief Initiates a transaction with the auth server */ t_authcode auth_server_request(t_authresponse *authresponse, char *request_type, char *ip, char *mac, char *token, unsigned long long int incoming, unsigned long long int outgoing); diff --git a/src/conf.c b/src/conf.c index aad99567..670ed88b 100644 --- a/src/conf.c +++ b/src/conf.c @@ -22,6 +22,7 @@ /** @file conf.c @brief Config file parsing @author Copyright (C) 2004 Philippe April + @author Copyright (C) 2007 Benoit Grégoire, Technologies Coeus inc. */ #define _GNU_SOURCE @@ -76,6 +77,11 @@ typedef enum { oAuthServSSLPort, oAuthServHTTPPort, oAuthServPath, + oAuthServLoginScriptPathFragment, + oAuthServPortalScriptPathFragment, + oAuthServMsgScriptPathFragment, + oAuthServPingScriptPathFragment, + oAuthServAuthScriptPathFragment, oHTTPDMaxConn, oHTTPDName, oClientTimeout, @@ -113,6 +119,11 @@ static const struct { { "sslport", oAuthServSSLPort }, { "httpport", oAuthServHTTPPort }, { "path", oAuthServPath }, + { "loginscriptpathfragment", oAuthServLoginScriptPathFragment }, + { "portalscriptpathfragment", oAuthServPortalScriptPathFragment }, + { "msgscriptpathfragment", oAuthServMsgScriptPathFragment }, + { "pingscriptpathfragment", oAuthServPingScriptPathFragment }, + { "authscriptpathfragment", oAuthServAuthScriptPathFragment }, { "firewallruleset", oFirewallRuleSet }, { "firewallrule", oFirewallRule }, { "trustedmaclist", oTrustedMACList }, @@ -190,6 +201,11 @@ parse_auth_server(FILE *file, char *filename, int *linenum) { char *host = NULL, *path = NULL, + *loginscriptpathfragment = NULL, + *portalscriptpathfragment = NULL, + *msgscriptpathfragment = NULL, + *pingscriptpathfragment = NULL, + *authscriptpathfragment = NULL, line[MAX_BUF], *p1, *p2; @@ -202,6 +218,11 @@ parse_auth_server(FILE *file, char *filename, int *linenum) /* Defaults */ path = safe_strdup(DEFAULT_AUTHSERVPATH); + loginscriptpathfragment = safe_strdup(DEFAULT_AUTHSERVLOGINPATHFRAGMENT); + portalscriptpathfragment = safe_strdup(DEFAULT_AUTHSERVPORTALPATHFRAGMENT); + msgscriptpathfragment = safe_strdup(DEFAULT_AUTHSERVMSGPATHFRAGMENT); + pingscriptpathfragment = safe_strdup(DEFAULT_AUTHSERVPINGPATHFRAGMENT); + authscriptpathfragment = safe_strdup(DEFAULT_AUTHSERVAUTHPATHFRAGMENT); http_port = DEFAULT_AUTHSERVPORT; ssl_port = DEFAULT_AUTHSERVSSLPORT; ssl_available = DEFAULT_AUTHSERVSSLAVAILABLE; @@ -251,6 +272,26 @@ parse_auth_server(FILE *file, char *filename, int *linenum) free(path); path = safe_strdup(p2); break; + case oAuthServLoginScriptPathFragment: + free(loginscriptpathfragment); + loginscriptpathfragment = safe_strdup(p2); + break; + case oAuthServPortalScriptPathFragment: + free(portalscriptpathfragment); + portalscriptpathfragment = safe_strdup(p2); + break; + case oAuthServMsgScriptPathFragment: + free(msgscriptpathfragment); + msgscriptpathfragment = safe_strdup(p2); + break; + case oAuthServPingScriptPathFragment: + free(pingscriptpathfragment); + pingscriptpathfragment = safe_strdup(p2); + break; + case oAuthServAuthScriptPathFragment: + free(authscriptpathfragment); + authscriptpathfragment = safe_strdup(p2); + break; case oAuthServSSLPort: ssl_port = atoi(p2); break; @@ -294,6 +335,11 @@ parse_auth_server(FILE *file, char *filename, int *linenum) new->authserv_hostname = host; new->authserv_use_ssl = ssl_available; new->authserv_path = path; + new->authserv_login_script_path_fragment = loginscriptpathfragment; + new->authserv_portal_script_path_fragment = portalscriptpathfragment; + new->authserv_msg_script_path_fragment = msgscriptpathfragment; + new->authserv_ping_script_path_fragment = pingscriptpathfragment; + new->authserv_auth_script_path_fragment = authscriptpathfragment; new->authserv_http_port = http_port; new->authserv_ssl_port = ssl_port; diff --git a/src/conf.h b/src/conf.h index 28983cde..63156c62 100644 --- a/src/conf.h +++ b/src/conf.h @@ -30,8 +30,8 @@ /*@{*/ /** Defines */ /** How many times should we try detecting the interface with the default route - * (in seconds) */ -#define NUM_EXT_INTERFACE_DETECT_RETRY 120 + * (in seconds). If set to 0, it will keep retrying forever */ +#define NUM_EXT_INTERFACE_DETECT_RETRY 0 /** How often should we try to detect the interface with the default route * if it isn't up yet (interval in seconds) */ #define EXT_INTERFACE_DETECT_RETRY_INTERVAL 1 @@ -60,6 +60,11 @@ #define DEFAULT_AUTHSERVSSLAVAILABLE 0 /** Note: The path must be prefixed by /, and must be suffixed /. Put / for the server root.*/ #define DEFAULT_AUTHSERVPATH "/wifidog/" +#define DEFAULT_AUTHSERVLOGINPATHFRAGMENT "login/?" +#define DEFAULT_AUTHSERVPORTALPATHFRAGMENT "portal/?" +#define DEFAULT_AUTHSERVMSGPATHFRAGMENT "gw_message.php?" +#define DEFAULT_AUTHSERVPINGPATHFRAGMENT "ping/?" +#define DEFAULT_AUTHSERVAUTHPATHFRAGMENT "auth/?" /*@}*/ /** @@ -68,6 +73,11 @@ typedef struct _auth_serv_t { char *authserv_hostname; /**< @brief Hostname of the central server */ char *authserv_path; /**< @brief Path where wifidog resides */ + char *authserv_login_script_path_fragment; /**< @brief This is the script the user will be sent to for login. */ + char *authserv_portal_script_path_fragment; /**< @brief This is the script the user will be sent to after a successfull login. */ + char *authserv_msg_script_path_fragment; /**< @brief This is the script the user will be sent to upon error to read a readable message. */ + char *authserv_ping_script_path_fragment; /**< @brief This is the ping heartbeating script. */ + char *authserv_auth_script_path_fragment; /**< @brief This is the script that talks the wifidog gateway protocol. */ int authserv_http_port; /**< @brief Http port the central server listens on */ int authserv_ssl_port; /**< @brief Https port the central server diff --git a/src/firewall.c b/src/firewall.c index 3ecd4ef8..667129c4 100644 --- a/src/firewall.c +++ b/src/firewall.c @@ -253,11 +253,14 @@ fw_sync_with_authserver(void) if (!(p1 = client_list_find(ip, mac))) { debug(LOG_ERR, "Node %s was freed while being re-validated!", ip); } else { + time_t current_time=time(NULL); + debug(LOG_INFO, "Checking client %s for timeout: Last updated %ld (%ld seconds ago), timeout delay %ld seconds, current time %ld, ", + p1->ip, p1->counters.last_updated, current_time-p1->counters.last_updated, config->checkinterval * config->clienttimeout, current_time); if (p1->counters.last_updated + (config->checkinterval * config->clienttimeout) - <= time(NULL)) { + <= current_time) { /* Timing out user */ - debug(LOG_INFO, "%s - Inactive for %ld seconds, removing client and denying in firewall", + debug(LOG_INFO, "%s - Inactive for more than %ld seconds, removing client and denying in firewall", p1->ip, config->checkinterval * config->clienttimeout); fw_deny(p1->ip, p1->mac, p1->fw_connection_state); client_list_delete(p1); diff --git a/src/fw_iptables.c b/src/fw_iptables.c index 3cb2d06e..3349bc9d 100644 --- a/src/fw_iptables.c +++ b/src/fw_iptables.c @@ -502,13 +502,13 @@ iptables_fw_counters_update(void) debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip); continue; } - debug(LOG_DEBUG, "Outgoing %s Bytes=%llu", ip, counter); + debug(LOG_DEBUG, "Read outgoing traffic for %s: Bytes=%llu", ip, counter); LOCK_CLIENT_LIST(); if ((p1 = client_list_find_by_ip(ip))) { if ((p1->counters.outgoing - p1->counters.outgoing_history) < counter) { p1->counters.outgoing = p1->counters.outgoing_history + counter; p1->counters.last_updated = time(NULL); - debug(LOG_DEBUG, "%s - Updated counter.outgoing to %llu bytes", ip, counter); + debug(LOG_DEBUG, "%s - Updated counter.outgoing to %llu bytes. Updated last_updated to %d", ip, counter, p1->counters.last_updated); } } else { debug(LOG_ERR, "Could not find %s in client list", ip); @@ -540,7 +540,7 @@ iptables_fw_counters_update(void) debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip); continue; } - debug(LOG_DEBUG, "Incoming %s Bytes=%llu", ip, counter); + debug(LOG_DEBUG, "Read incoming traffic for %s: Bytes=%llu", ip, counter); LOCK_CLIENT_LIST(); if ((p1 = client_list_find_by_ip(ip))) { if ((p1->counters.incoming - p1->counters.incoming_history) < counter) { diff --git a/src/http.c b/src/http.c index 9336d13b..482281c2 100644 --- a/src/http.c +++ b/src/http.c @@ -22,6 +22,9 @@ /** @file http.c @brief HTTP IO functions @author Copyright (C) 2004 Philippe April + @author Copyright (C) 2007 Benoit Grégoire + @author Copyright (C) 2007 David Bird + */ #define _GNU_SOURCE @@ -44,6 +47,7 @@ #include "httpd.h" #include "client_list.h" #include "common.h" +#include "centralserver.h" #include "util.h" @@ -55,22 +59,12 @@ extern pthread_mutex_t client_list_mutex; void http_callback_404(httpd *webserver, request *r) { - char *newlocation, - *protocol, + char *urlFragment, tmp_url[MAX_BUF], *url; - int port; s_config *config = config_get_config(); t_auth_serv *auth_server = get_auth_server(); - if (auth_server->authserv_use_ssl) { - protocol = "https"; - port = auth_server->authserv_ssl_port; - } else { - protocol = "http"; - port = auth_server->authserv_http_port; - } - memset(tmp_url, 0, sizeof(tmp_url)); /* * XXX Note the code belows assume that the client's request is a plain @@ -105,32 +99,16 @@ http_callback_404(httpd *webserver, request *r) } else { /* Re-direct them to auth server */ - safe_asprintf(&newlocation, "Location: %s://%s:%d%slogin?gw_address=%s&gw_port=%d&gw_id=%s&url=%s", - protocol, - auth_server->authserv_hostname, - port, - auth_server->authserv_path, + safe_asprintf(&urlFragment, "%sgw_address=%s&gw_port=%d&gw_id=%s&url=%s", + auth_server->authserv_login_script_path_fragment, config->gw_address, config->gw_port, config->gw_id, url); - httpdSetResponse(r, "307 Please authenticate yourself here\n"); - httpdAddHeader(r, newlocation); - http_wifidog_header(r, "Redirection"); - httpdPrintf(r, "Please click here to login", - protocol, - auth_server->authserv_hostname, - port, - auth_server->authserv_path, - config->gw_address, - config->gw_port, - config->gw_id, - url); - http_wifidog_footer(r); - debug(LOG_INFO, "Captured %s requesting [%s] and re-directed them to login page", r->clientAddr, url); - free(newlocation); + debug(LOG_INFO, "Captured %s requesting [%s] and re-directing them to login page", r->clientAddr, url); + http_send_redirect_to_auth(r, urlFragment, "Redirect to login page"); + free(urlFragment); } - free(url); } @@ -162,6 +140,75 @@ http_callback_status(httpd *webserver, request *r) http_wifidog_footer(r); free(status); } +/** @brief Convenience function to redirect the web browser to the authe server + * @param r The request + * @param urlFragment The end of the auth server URL to redirect to (the part after path) + * @param text The text to include in the redirect header ant the mnual redirect title */ +void http_send_redirect_to_auth(request *r, char *urlFragment, char *text) +{ + char *protocol = NULL; + int port = 80; + t_auth_serv *auth_server = get_auth_server(); + + if (auth_server->authserv_use_ssl) { + protocol = "https"; + port = auth_server->authserv_ssl_port; + } else { + protocol = "http"; + port = auth_server->authserv_http_port; + } + + char *url = NULL; + safe_asprintf(&url, "%s://%s:%d%s%s", + protocol, + auth_server->authserv_hostname, + port, + auth_server->authserv_path, + urlFragment + ); + http_send_redirect(r, url, text); + free(url); +} + +/** @brief Sends a redirect to the web browser + * @param r The request + * @param url The url to redirect to + * @param text The text to include in the redirect header and the manual redirect link title. NULL is acceptable */ +void http_send_redirect(request *r, char *url, char *text) +{ + char *header = NULL; + char *response = NULL; + /* Re-direct them to auth server */ + debug(LOG_DEBUG, "Redirecting client browser to %s", url); + safe_asprintf(&header, "Location: %s", + url + ); + if(text) { + safe_asprintf(&response, "307 %s\n", + text + ); + } + else { + safe_asprintf(&response, "307 %s\n", + "Redirecting" + ); + } + httpdSetResponse(r, response); + httpdAddHeader(r, header); + free(response); + free(header); + if(text) { + http_wifidog_header(r, text); + } + else { + http_wifidog_header(r, "Redirection to message"); + } + + httpdPrintf(r, "Please click here.", + url + ); + http_wifidog_footer(r); +} void http_callback_auth(httpd *webserver, request *r) @@ -169,7 +216,7 @@ http_callback_auth(httpd *webserver, request *r) t_client *client; httpVar * token; char *mac; - + httpVar *logout = httpdGetVariableByName(r, "logout"); if ((token = httpdGetVariableByName(r, "token"))) { /* They supplied variable "token" */ if (!(mac = arp_get(r->clientAddr))) { @@ -186,13 +233,45 @@ http_callback_auth(httpd *webserver, request *r) if ((client = client_list_find(r->clientAddr, mac)) == NULL) { debug(LOG_DEBUG, "New client for %s", r->clientAddr); client_list_append(r->clientAddr, mac, token->value); - } else { - debug(LOG_DEBUG, "Node for %s already exists", client->ip); + } else if (logout) { + t_authresponse authresponse; + s_config *config = config_get_config(); + unsigned long long incoming = client->counters.incoming; + unsigned long long outgoing = client->counters.outgoing; + char *ip = safe_strdup(client->ip); + char *urlFragment = NULL; + t_auth_serv *auth_server = get_auth_server(); + + fw_deny(client->ip, client->mac, client->fw_connection_state); + client_list_delete(client); + debug(LOG_DEBUG, "Got logout from %s", client->ip); + + /* Advertise the logout if we have an auth server */ + if (config->auth_servers != NULL) { + UNLOCK_CLIENT_LIST(); + auth_server_request(&authresponse, REQUEST_TYPE_LOGOUT, ip, mac, token->value, + incoming, outgoing); + LOCK_CLIENT_LIST(); + + /* Re-direct them to auth server */ + debug(LOG_INFO, "Got manual logout from client ip %s, mac %s, token %s" + "- redirecting them to logout message", client->ip, client->mac, client->token); + safe_asprintf(&urlFragment, "%smessage=%s", + auth_server->authserv_msg_script_path_fragment, + GATEWAY_MESSAGE_ACCOUNT_LOGGED_OUT + ); + http_send_redirect_to_auth(r, urlFragment, "Redirect to logout message"); + free(urlFragment); + } + free(ip); + } + else { + debug(LOG_DEBUG, "Client for %s is already in the client list", client->ip); } - UNLOCK_CLIENT_LIST(); - - authenticate_client(r); + if (!logout) { + authenticate_client(r); + } free(mac); } } else { diff --git a/src/http.h b/src/http.h index c17c6be9..1d4f7368 100644 --- a/src/http.h +++ b/src/http.h @@ -45,4 +45,8 @@ void http_wifidog_header(request *r, char *title); /** @brief Sends HTML footer to web browser */ void http_wifidog_footer(request *r); +/** @brief Sends a redirect to the web browser */ +void http_send_redirect(request *r, char *url, char *text); +/** @brief Convenience function to redirect the web browser to the authe server */ +void http_send_redirect_to_auth(request *r, char *urlFragment, char *text); #endif /* _HTTP_H_ */ diff --git a/src/ping_thread.c b/src/ping_thread.c index 4b079bf7..699e4baa 100644 --- a/src/ping_thread.c +++ b/src/ping_thread.c @@ -102,8 +102,9 @@ ping(void) unsigned long int sys_uptime = 0; unsigned int sys_memfree = 0; float sys_load = 0; - - + t_auth_serv *auth_server = NULL; + auth_server = get_auth_server(); + debug(LOG_DEBUG, "Entering ping()"); /* @@ -148,18 +149,19 @@ ping(void) * Prep & send request */ snprintf(request, sizeof(request) - 1, - "GET %sping/?gw_id=%s&sys_uptime=%lu&sys_memfree=%u&sys_load=%.2f&wifidog_uptime=%lu HTTP/1.0\r\n" + "GET %s%sgw_id=%s&sys_uptime=%lu&sys_memfree=%u&sys_load=%.2f&wifidog_uptime=%lu HTTP/1.0\r\n" "User-Agent: WiFiDog %s\r\n" "Host: %s\r\n" "\r\n", - config_get_config()->auth_servers->authserv_path, + auth_server->authserv_path, + auth_server->authserv_ping_script_path_fragment, config_get_config()->gw_id, sys_uptime, sys_memfree, sys_load, (long unsigned int)((long unsigned int)time(NULL) - (long unsigned int)started_time), VERSION, - config_get_config()->auth_servers->authserv_hostname); + auth_server->authserv_hostname); debug(LOG_DEBUG, "HTTP Request to Server: [%s]", request); diff --git a/src/util.c b/src/util.c index 848d7d36..dea2527a 100644 --- a/src/util.c +++ b/src/util.c @@ -222,7 +222,7 @@ char *get_ext_iface (void) { #ifdef __linux__ FILE *input; char *device, *gw; - int i; + int i = 1; int keep_detecting = 1; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t cond_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -241,7 +241,7 @@ char *get_ext_iface (void) { } } fclose(input); - debug(LOG_ERR, "get_ext_iface(): Failed to detect the external interface after try %d of %d (maybe the interface is not up yet?)", i, NUM_EXT_INTERFACE_DETECT_RETRY); + debug(LOG_ERR, "get_ext_iface(): Failed to detect the external interface after try %d (maybe the interface is not up yet?). Retry limit: %d", i, NUM_EXT_INTERFACE_DETECT_RETRY); /* Sleep for EXT_INTERFACE_DETECT_RETRY_INTERVAL seconds */ timeout.tv_sec = time(NULL) + EXT_INTERFACE_DETECT_RETRY_INTERVAL; timeout.tv_nsec = 0; @@ -252,11 +252,12 @@ char *get_ext_iface (void) { /* No longer needs to be locked */ pthread_mutex_unlock(&cond_mutex); //for (i=1; i<=NUM_EXT_INTERFACE_DETECT_RETRY; i++) { - if (NUM_EXT_INTERFACE_DETECT_RETRY != 0 && i>=NUM_EXT_INTERFACE_DETECT_RETRY) { + if (NUM_EXT_INTERFACE_DETECT_RETRY != 0 && i>NUM_EXT_INTERFACE_DETECT_RETRY) { keep_detecting = 0; } + i++; } - debug(LOG_ERR, "get_ext_iface(): Failed to detect the external interface after %d tries, aborting", NUM_EXT_INTERFACE_DETECT_RETRY); + debug(LOG_ERR, "get_ext_iface(): Failed to detect the external interface after %d tries, aborting", i); exit(1); free(device); free(gw); diff --git a/wifidog.conf b/wifidog.conf index 756d7975..2b67abdc 100644 --- a/wifidog.conf +++ b/wifidog.conf @@ -30,7 +30,7 @@ # Set this to the internal interface (typically your wifi interface). # Typically br0 for OpenWrt, and eth1, wlan0, ath0, etc. otherwise -GatewayInterface eth1 +GatewayInterface br0 # Parameter: GatewayAddress # Default: Find it from GatewayInterface @@ -48,11 +48,16 @@ GatewayInterface eth1 # Set this to the hostname or IP of your auth server(s), the path where # WiFiDog-auth resides in and the port it listens on. #AuthServer { -# Hostname (Mandatory; Default: NONE) -# SSLAvailable (Optional; Default: no; Possible values: yes, no) -# SSLPort 443 (Optional; Default: 443) -# HTTPPort 80 (Optional; Default: 80) -# Path wifidog/ (Optional; Default: /wifidog/ Note: The path must be both prefixed and suffixed by /. Use a single / for server root.) +# Hostname (Mandatory; Default: NONE) +# SSLAvailable (Optional; Default: no; Possible values: yes, no) +# SSLPort (Optional; Default: 443) +# HTTPPort (Optional; Default: 80) +# Path (Optional; Default: /wifidog/ Note: The path must be both prefixed and suffixed by /. Use a single / for server root.) +# LoginScriptPathFragment (Optional; Default: login/? Note: This is the script the user will be sent to for login.) +# PortalScriptPathFragment (Optional; Default: portal/? Note: This is the script the user will be sent to after a successfull login.) +# MsgScriptPathFragment (Optional; Default: gw_message.php? Note: This is the script the user will be sent to upon error to read a readable message.) +# PingScriptPathFragment (Optional; Default: ping/? Note: This is the script the user will be sent to upon error to read a readable message.) +# AuthScriptPathFragment (Optional; Default: auth/? Note: This is the script the user will be sent to upon error to read a readable message.) #} #AuthServer { @@ -183,7 +188,7 @@ FirewallRuleSet unknown-users { # Rule Set: locked-users # -# Used for users that have been locked out. +# Not currently used FirewallRuleSet locked-users { FirewallRule block to 0.0.0.0/0 }