diff --git a/include/HostPools.h b/include/HostPools.h index c4e0f3c852..f8fb02898f 100644 --- a/include/HostPools.h +++ b/include/HostPools.h @@ -39,6 +39,7 @@ public: void reloadPools(); u_int16_t getPool(Host *h); void addToPool(u_int32_t client_ipv4, u_int16_t user_pool_id, bool permanentAuthorization); + void addToPool(char *host_or_mac, u_int16_t user_pool_id, bool permanentAuthorization); void purgeExpiredMembers(); }; diff --git a/include/ntop_includes.h b/include/ntop_includes.h index df9077102d..c0d85df794 100644 --- a/include/ntop_includes.h +++ b/include/ntop_includes.h @@ -151,6 +151,7 @@ using namespace std; #include "FlowProfile.h" #include "FlowProfiles.h" #include "CounterTrend.h" +#include "LRUMacIP.h" #ifdef HAVE_LDAP #include "LdapAuthenticator.h" #endif diff --git a/src/HTTPserver.cpp b/src/HTTPserver.cpp index 3486794b5c..48c4c9bdfa 100644 --- a/src/HTTPserver.cpp +++ b/src/HTTPserver.cpp @@ -71,10 +71,10 @@ static void redirect_to_ssl(struct mg_connection *conn, const struct mg_request_info *request_info) { const char *host = mg_get_header(conn, "Host"); // u_int16_t port = ntop->get_HTTPserver()->get_port(); - + if(host != NULL) { const char *p = strchr(host, ':'); - + if(p) mg_printf(conn, "HTTP/1.1 302 Found\r\n" "Location: https://%.*s:%u/%s\r\n\r\n", @@ -245,18 +245,26 @@ static void redirect_to_login(struct mg_connection *conn, const struct mg_request_info *request_info) { char session_id[33], buf[128]; +#ifdef DEBUG + ntop->getTrace()->traceEvent(TRACE_NORMAL, "[LOGIN] [Host: %s][URI: %s]", (char*)mg_get_header(conn, "Host"), request_info->uri); +#endif + mg_get_cookie(conn, "session", session_id, sizeof(session_id)); ntop->getTrace()->traceEvent(TRACE_INFO, "[HTTP] %s(%s)", __FUNCTION__, session_id); - mg_printf(conn, + mg_printf(conn, "HTTP/1.1 302 Found\r\n" // "HTTP/1.1 401 Unauthorized\r\n" // "WWW-Authenticate: Basic\r\n" "Set-Cookie: session=%s; path=/; expires=Thu, 01-Jan-1970 00:00:01 GMT; max-age=0; HttpOnly\r\n" // Session ID - "Location: %s%s?referer=%s%s%s\r\n\r\n", + "Location: http%s://192.168.1.131:%u%s%s?referer=%s%s%s%s\r\n\r\n", /* FIX */ session_id, - ntop->getPrefs()->get_http_prefix(), + request_info->is_ssl ? "s" : "", + request_info->is_ssl ? ntop->getPrefs()->get_https_port() : ntop->getPrefs()->get_http_port(), + + ntop->getPrefs()->get_http_prefix(), Utils::getURL((char*)LOGIN_URL, buf, sizeof(buf)), + (char*)mg_get_header(conn, "Host"), conn->request_info.uri, conn->request_info.query_string ? "%3F" /* ? */: "", conn->request_info.query_string ? conn->request_info.query_string : ""); @@ -299,10 +307,98 @@ static void get_qsvar(const struct mg_request_info *request_info, /* ****************************************** */ +static int checkCaptive(struct mg_connection *conn, + const struct mg_request_info *request_info, + char *username) { +#ifdef NTOPNG_PRO + if(ntop->getPrefs()->isCaptivePortalEnabled() + && ntop->isCaptivePortalUser(username)) { + /* + This user logged onto ntopng via the captive portal + */ + char *referer = NULL; + u_int16_t host_pool_id; + const char *r = mg_get_header(conn, "Referer"); + +#ifdef DEBUG + char buf[32]; + + ntop->getTrace()->traceEvent(TRACE_NORMAL, "[CAPTIVE] %s @ %s/%08X [Redirecting to %s%s]", + username, Utils::intoaV4((unsigned int)conn->request_info.remote_ip, buf, sizeof(buf)), + (unsigned int)conn->request_info.remote_ip, + (char*)mg_get_header(conn, "Host"), request_info->uri); +#endif + + ntop->getUserHostPool(username, &host_pool_id); + ntop->addIPToLRUMatches(htonl((unsigned int)conn->request_info.remote_ip), + host_pool_id, + !ntop->hasUserLimitedLifetime(username)); + + /* + As this is a captive portal user, we are good so far and we + redirect to the requested web site + */ +#if 0 + ntop->getTrace()->traceEvent(TRACE_WARNING, "QUERY_STRING=%s", request_info->query_string ? request_info->query_string : ""); + ntop->getTrace()->traceEvent(TRACE_WARNING, "Referer=%s", r); +#endif + + if(r) { + char *k, *t1; + + k = strtok_r((char*)r, "?", &t1); + while(k != NULL) { + char *a, *b, *t2; + + if((a = strtok_r(k, "=", &t2)) != NULL) { + b = strtok_r(NULL, "=", &t2); + + if(!strcmp(a, "referer")) { + referer = strdup(b); + break; + } + } + + k = strtok_r(NULL, "&", &t1); + } + } + + if(referer == NULL) referer = strdup("www.ntop.org"); + +#ifdef DEBUG + ntop->getTrace()->traceEvent(TRACE_WARNING, "############# ==>>> Redirecting to http://%s", referer); +#endif + +#if 1 + mg_printf(conn, "HTTP/1.1 301 Moved Permanently\r\n" + "Location: http://%s\r\n\r\n", + referer); +#else + mg_printf(conn, "HTTP/1.1 200 OK\r\n" + "Set-Cookie: session=; path=/; expires=Thu, 01-Jan-1970 00:00:01 GMT; max-age=0; HttpOnly\r\n" // Session ID + "\r\n" + "\n
\nSuccessful Authentication. Ready to surf
", + referer); +#endif + + free(referer); + + return(1); + } +#endif + + return(0); +} + +/* ****************************************** */ + // A handler for the /authorize endpoint. // Login page form sends user name and password to this endpoint. static void authorize(struct mg_connection *conn, - const struct mg_request_info *request_info) { + const struct mg_request_info *request_info, + char *username) { char user[32], password[32], referer[256]; if(!strcmp(request_info->request_method, "POST")) { @@ -364,6 +460,10 @@ static int handle_lua_request(struct mg_connection *conn) { u_int len = (u_int)strlen(request_info->uri); char username[33] = { 0 }; +#ifdef DEBUG + ntop->getTrace()->traceEvent(TRACE_NORMAL, "[Host: %s][URI: %s]", (char*)mg_get_header(conn, "Host"), request_info->uri); +#endif + if((ntop->getGlobals()->isShutdown()) //|| (strcmp(request_info->request_method, "GET")) || (ntop->getRedis() == NULL /* Starting up... */) @@ -388,43 +488,15 @@ static int handle_lua_request(struct mg_connection *conn) { redirect_to_login(conn, request_info); return(1); } else if(strcmp(request_info->uri, AUTHORIZE_URL) == 0) { - authorize(conn, request_info); + authorize(conn, request_info, username); return(1); } -#ifdef NTOPNG_PRO - if(ntop->getPrefs()->isCaptivePortalEnabled() - && ntop->isCaptivePortalUser(username)) { - /* - This user logged onto ntopng via the captive portal - */ - char buf[32]; - u_int16_t host_pool_id; - - ntop->getTrace()->traceEvent(TRACE_NORMAL, "[CAPTIVE] %s @ %s/%08X", - username, Utils::intoaV4((unsigned int)conn->request_info.remote_ip, buf, sizeof(buf)), - (unsigned int)conn->request_info.remote_ip); - - ntop->getUserHostPool(username, &host_pool_id); - ntop->addIPToLRUMatches(htonl((unsigned int)conn->request_info.remote_ip), - host_pool_id, - !ntop->hasUserLimitedLifetime(username)); - - /* - As this is a captive portal user, we are good so far and we - redirect to the requested web site - */ - - mg_printf(conn, "HTTP/1.1 302 Found\r\n" - "Location: http%s://%s%s\r\n\r\n", - "" /* conn->request_info.is_ssl ? "s" : "" */, - (char*)mg_get_header(conn, "Host"), request_info->uri); - return(1); - } -#endif - ntop->getTrace()->traceEvent(TRACE_INFO, "[HTTP] %s", request_info->uri); + if(checkCaptive(conn, request_info, username)) + return(1); + if(strstr(request_info->uri, "//") || strstr(request_info->uri, "&&") || strstr(request_info->uri, "??") @@ -457,7 +529,7 @@ static int handle_lua_request(struct mg_connection *conn) { ntop->fixPath(path); found = ((stat(path, &buf) == 0) && (S_ISREG(buf.st_mode))) ? true : false; - + if(found) { Lua *l = new Lua(); @@ -509,7 +581,7 @@ HTTPserver::HTTPserver(u_int16_t _port, const char *_docs_dir, const char *_scri if(port == 0) use_http = false; if(use_http) - snprintf(ports, sizeof(ports), "%s%s%d", + snprintf(ports, sizeof(ports), "%s%s%d", http_binding_addr, (http_binding_addr[0] == '\0') ? "" : ":", port); @@ -523,9 +595,9 @@ HTTPserver::HTTPserver(u_int16_t _port, const char *_docs_dir, const char *_scri use_ssl = true; if(use_http) snprintf(ports, sizeof(ports), "%s%s%d,%s%s%ds", - http_binding_addr, + http_binding_addr, (http_binding_addr[0] == '\0') ? "" : ":", - port, + port, https_binding_addr, (https_binding_addr[0] == '\0') ? "" : ":", ntop->getPrefs()->get_https_port()); diff --git a/src/HostPools.cpp b/src/HostPools.cpp index ffdbc3c040..4953013def 100644 --- a/src/HostPools.cpp +++ b/src/HostPools.cpp @@ -174,32 +174,42 @@ u_int16_t HostPools::getPool(Host *h) { void HostPools::addToPool(u_int32_t client_ipv4 /* network byte order */, u_int16_t user_pool_id, bool permanentAuthorization) { - char key[128], host[128], buf[64], pool_buf[16]; + char buf[64], host[128]; snprintf(host, sizeof(host), "%s/32@0", Utils::intoaV4(ntohl(client_ipv4), buf, sizeof(buf))); + addToPool(host, user_pool_id, permanentAuthorization); +} + +/* *************************************** */ + +void HostPools::addToPool(char *host_or_mac, + u_int16_t user_pool_id, + bool permanentAuthorization) { + char key[128], pool_buf[16]; + snprintf(pool_buf, sizeof(pool_buf), "%u", user_pool_id); snprintf(key, sizeof(key), HOST_POOL_MEMBERS_KEY, iface->get_id(), pool_buf); - if(ntop->getRedis()->sadd(key, host) /* New member added */) { + if(ntop->getRedis()->sadd(key, host_or_mac) /* New member added */) { if(!permanentAuthorization) { snprintf(key, sizeof(key), HOST_POOL_VOLATILE_MEMBERS_KEY, iface->get_id(), pool_buf); - if(!ntop->getRedis()->sadd(key, host)) { + if(!ntop->getRedis()->sadd(key, host_or_mac)) { ntop->getTrace()->traceEvent(TRACE_WARNING, "Unable to add %s as VOLATILE host pool member [pool id: %s]", - host, pool_buf); + host_or_mac, pool_buf); return; } - snprintf(key, sizeof(key), HOST_POOL_VOLATILE_MEMBER_EXPIRE, iface->get_id(), host); + snprintf(key, sizeof(key), HOST_POOL_VOLATILE_MEMBER_EXPIRE, iface->get_id(), host_or_mac); if(ntop->getRedis()->set(key, - host, /* Just a placeholder, we only care about the expire time */ + host_or_mac, /* Just a placeholder, we only care about the expire time */ 3600 * 24 /* 1 Day, TODO: make it configurable */)) { ntop->getTrace()->traceEvent(TRACE_WARNING, "Unable to set expire key for VOLATILE pool member %s [pool id: %s]", - host, pool_buf); + host_or_mac, pool_buf); return; } } @@ -208,7 +218,7 @@ void HostPools::addToPool(u_int32_t client_ipv4 /* network byte order */, } else { ntop->getTrace()->traceEvent(TRACE_WARNING, "Unable to add %s as PERMANENT host pool member [pool id: %s]", - host, pool_buf); + host_or_mac, pool_buf); } } diff --git a/src/Lua.cpp b/src/Lua.cpp index 3231b3052c..4d1042c6dc 100644 --- a/src/Lua.cpp +++ b/src/Lua.cpp @@ -5934,6 +5934,8 @@ int Lua::handle_script_request(struct mg_connection *conn, char csrf[64] = { '\0' }; char user[64] = { '\0' }; int post_data_len = mg_read(conn, post_data, sizeof(post_data)); + u_int8_t valid_csrf = 1; + post_data[sizeof(post_data)-1] = '\0'; /* CSRF is mandatory in POST request */ @@ -5942,6 +5944,7 @@ int Lua::handle_script_request(struct mg_connection *conn, if((ntop->getRedis()->get(csrf, rsp, sizeof(rsp)) == -1) || (strcmp(rsp, user) != 0)) { +#if 0 const char *msg = "The submitted form is expired. Please reload the page and try again.[ Home ]"; ntop->getTrace()->traceEvent(TRACE_WARNING, @@ -5950,13 +5953,21 @@ int Lua::handle_script_request(struct mg_connection *conn, return(send_error(conn, 500 /* Internal server error */, msg, PAGE_ERROR, script_path, msg)); +#else + valid_csrf = 0; +#endif } else { /* Invalidate csrf */ ntop->getRedis()->del(csrf); } - /* CSRF is valid here, now fill the _POST table with POST parameters */ - setParamsTable(L, "_POST", post_data); + if(valid_csrf) { + /* CSRF is valid here, now fill the _POST table with POST parameters */ + setParamsTable(L, "_POST", post_data); + } else { + lua_newtable(L); + lua_setglobal(L, (char*)"_POST"); /* Empty */ + } if(request_info->query_string) { char *k, *t1;