diff --git a/CMakeLists.txt b/CMakeLists.txt
index bb81ee0..249e023 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,6 +4,8 @@ project(tawashi_top VERSION 0.1.11 LANGUAGES NONE)
include(CTest)
+option(TAWASHI_WITH_IP_LOGGING "Enable code in Tawashi that may result in users IPs being stored in the DB or in logs" ON)
+
set(INCREDIS_FORCE_DISABLE_TESTS ON)
set(TAWASHI_SOURCE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}")
set(TAWASHI_GEN_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/include")
diff --git a/src/tawashiConfig.h.in b/src/tawashiConfig.h.in
index 43f9e5a..1956ee2 100644
--- a/src/tawashiConfig.h.in
+++ b/src/tawashiConfig.h.in
@@ -23,3 +23,4 @@
#define VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define VERSION_MINOR @PROJECT_VERSION_MINOR@
#define VERSION_PATCH @PROJECT_VERSION_PATCH@
+#cmakedefine TAWASHI_WITH_IP_LOGGING
diff --git a/src/tawashi_implem/CMakeLists.txt b/src/tawashi_implem/CMakeLists.txt
index 9ea67ea..074cd66 100644
--- a/src/tawashi_implem/CMakeLists.txt
+++ b/src/tawashi_implem/CMakeLists.txt
@@ -28,6 +28,7 @@ add_library(${PROJECT_NAME} STATIC
tawashi_exception.cpp
http_header.cpp
quick_submit_paste_response.cpp
+ ip_utils.cpp
)
target_include_directories(${PROJECT_NAME}
diff --git a/src/tawashi_implem/cgi_env.cpp b/src/tawashi_implem/cgi_env.cpp
index 284e60f..a601219 100644
--- a/src/tawashi_implem/cgi_env.cpp
+++ b/src/tawashi_implem/cgi_env.cpp
@@ -150,6 +150,14 @@ namespace cgi {
return m_cgi_env[CGIVars::QUERY_STRING];
}
+ const std::string& Env::http_client_ip() const {
+ return m_cgi_env[CGIVars::HTTP_CLIENT_IP];
+ }
+
+ const std::string& Env::http_x_forwarded_for() const {
+ return m_cgi_env[CGIVars::HTTP_X_FORWARDED_FOR];
+ }
+
const std::string& Env::remote_addr() const {
return m_cgi_env[CGIVars::REMOTE_ADDR];
}
diff --git a/src/tawashi_implem/cgi_env.hpp b/src/tawashi_implem/cgi_env.hpp
index 9fda7c7..c41905c 100644
--- a/src/tawashi_implem/cgi_env.hpp
+++ b/src/tawashi_implem/cgi_env.hpp
@@ -52,6 +52,8 @@ namespace tawashi {
boost::string_ref path_info() const;
const std::string& path_translated() const;
const std::string& query_string() const;
+ const std::string& http_client_ip() const;
+ const std::string& http_x_forwarded_for() const;
const std::string& remote_addr() const;
const std::string& remote_host() const;
const std::string& remote_ident() const;
diff --git a/src/tawashi_implem/cgi_environment_vars.hpp b/src/tawashi_implem/cgi_environment_vars.hpp
index 6ee4124..fa5475e 100644
--- a/src/tawashi_implem/cgi_environment_vars.hpp
+++ b/src/tawashi_implem/cgi_environment_vars.hpp
@@ -28,9 +28,11 @@ namespace tawashi {
CONTENT_TYPE,
DOCUMENT_ROOT, //The root directory of your server
GATEWAY_INTERFACE,
+ HTTP_CLIENT_IP,
HTTP_COOKIE, //The visitor's cookie, if one is set
HTTP_HOST, //The hostname of your server
HTTP_REFERER, //The URL of the page that called your script
+ HTTP_X_FORWARDED_FOR,
HTTPS, //"on" if the script is being called through a secure server
HTTP_USER_AGENT, //The browser type of your visitor
PATH, //The system path your server is running under
diff --git a/src/tawashi_implem/ip_utils.cpp b/src/tawashi_implem/ip_utils.cpp
new file mode 100644
index 0000000..9a0c9fd
--- /dev/null
+++ b/src/tawashi_implem/ip_utils.cpp
@@ -0,0 +1,83 @@
+/* Copyright 2017, Michele Santullo
+ * This file is part of "tawashi".
+ *
+ * "tawashi" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * "tawashi" is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with "tawashi". If not, see .
+ */
+
+#include "ip_utils.hpp"
+#include "duckhandy/lexical_cast.hpp"
+#include "duckhandy/int_to_string_ary.hpp"
+#include "cgi_env.hpp"
+#include "tawashiConfig.h"
+#include
+#include
+#include
+#include
+
+#if !defined(TAWASHI_WITH_IP_LOGGING)
+extern "C" void tiger (const char* parStr, uint64_t parLength, uint64_t parHash[3], char parPadding);
+#endif
+
+namespace tawashi {
+ namespace {
+ std::string hash_if_configured (const std::string& parIP) a_always_inline;
+
+#if !defined(TAWASHI_WITH_IP_LOGGING)
+ std::string hashed_ip (const std::string& parIP) {
+ using dhandy::tags::hex;
+
+ uint64_t hash[3];
+ tiger(parIP.data(), parIP.size(), hash, 0x80);
+
+ auto h1 = dhandy::int_to_string_ary(hash[0]);
+ auto h2 = dhandy::int_to_string_ary(hash[1]);
+ auto h3 = dhandy::int_to_string_ary(hash[2]);
+
+ std::string retval(2 * sizeof(uint64_t) * 3, '0');
+ assert(h1.size() <= 2 * sizeof(uint64_t));
+ std::copy(h1.begin(), h1.end(), retval.begin() + 2 * sizeof(uint64_t) * 0 + 2 * sizeof(uint64_t) - h1.size());
+ assert(h2.size() <= 2 * sizeof(uint64_t));
+ std::copy(h2.begin(), h2.end(), retval.begin() + 2 * sizeof(uint64_t) * 1 + 2 * sizeof(uint64_t) - h2.size());
+ assert(h3.size() <= 2 * sizeof(uint64_t));
+ std::copy(h3.begin(), h3.end(), retval.begin() + 2 * sizeof(uint64_t) * 2 + 2 * sizeof(uint64_t) - h3.size());
+
+ SPDLOG_DEBUG(spdlog::get("statuslog"), "IP \"{}\" hashed -> \"{}\"", parIP, retval);
+ assert(retval.size() == 16 * 3);
+ return retval;
+ }
+#endif
+
+ inline std::string hash_if_configured (const std::string& parIP) {
+#if defined(TAWASHI_WITH_IP_LOGGING)
+ return parIP;
+#else
+ return hashed_ip(parIP);
+#endif
+ }
+
+ } //unnamed namespace
+
+ //see: https://stackoverflow.com/questions/18799808/how-do-i-count-unique-visitors-to-my-site
+ std::string guess_real_remote_ip (const cgi::Env& parCgiEnv) {
+ if (not parCgiEnv.http_client_ip().empty()) {
+ return hash_if_configured(parCgiEnv.http_client_ip());
+ }
+ else if (not parCgiEnv.http_x_forwarded_for().empty()) {
+ return hash_if_configured(parCgiEnv.http_x_forwarded_for());
+ }
+ else {
+ return hash_if_configured(parCgiEnv.remote_addr());
+ }
+ }
+} //namespace tawashi
diff --git a/src/tawashi_implem/ip_utils.hpp b/src/tawashi_implem/ip_utils.hpp
new file mode 100644
index 0000000..548bf7e
--- /dev/null
+++ b/src/tawashi_implem/ip_utils.hpp
@@ -0,0 +1,29 @@
+/* Copyright 2017, Michele Santullo
+ * This file is part of "tawashi".
+ *
+ * "tawashi" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * "tawashi" is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with "tawashi". If not, see .
+ */
+
+#pragma once
+
+#include "duckhandy/compatibility.h"
+#include
+
+namespace tawashi {
+ namespace cgi {
+ class Env;
+ } //namespace cgi
+
+ std::string guess_real_remote_ip (const cgi::Env& parCgiEnv) a_pure;
+} //namespace tawashi
diff --git a/src/tawashi_implem/submit_paste_response.cpp b/src/tawashi_implem/submit_paste_response.cpp
index 8c9a13f..b70d87c 100644
--- a/src/tawashi_implem/submit_paste_response.cpp
+++ b/src/tawashi_implem/submit_paste_response.cpp
@@ -18,21 +18,18 @@
#include "submit_paste_response.hpp"
#include "incredis/incredis.hpp"
#include "cgi_post.hpp"
-#include "cgi_env.hpp"
#include "num_to_token.hpp"
#include "settings_bag.hpp"
#include "duckhandy/compatibility.h"
#include "duckhandy/lexical_cast.hpp"
-#include "duckhandy/int_to_string_ary.hpp"
#include "tawashi_exception.hpp"
+#include "ip_utils.hpp"
#include
#include
#include
#include
#include
-extern "C" void tiger (const char* parStr, uint64_t parLength, uint64_t parHash[3], char parPadding);
-
namespace tawashi {
namespace {
const char g_post_key[] = "pastie";
@@ -75,29 +72,6 @@ namespace tawashi {
return boost::string_ref();
}
}
-
- std::string hashed_ip (const std::string& parIP) {
- using dhandy::tags::hex;
-
- uint64_t hash[3];
- tiger(parIP.data(), parIP.size(), hash, 0x80);
-
- auto h1 = dhandy::int_to_string_ary(hash[0]);
- auto h2 = dhandy::int_to_string_ary(hash[1]);
- auto h3 = dhandy::int_to_string_ary(hash[2]);
-
- std::string retval(2 * sizeof(uint64_t) * 3, '0');
- assert(h1.size() <= 2 * sizeof(uint64_t));
- std::copy(h1.begin(), h1.end(), retval.begin() + 2 * sizeof(uint64_t) * 0 + 2 * sizeof(uint64_t) - h1.size());
- assert(h2.size() <= 2 * sizeof(uint64_t));
- std::copy(h2.begin(), h2.end(), retval.begin() + 2 * sizeof(uint64_t) * 1 + 2 * sizeof(uint64_t) - h2.size());
- assert(h3.size() <= 2 * sizeof(uint64_t));
- std::copy(h3.begin(), h3.end(), retval.begin() + 2 * sizeof(uint64_t) * 2 + 2 * sizeof(uint64_t) - h3.size());
-
- SPDLOG_DEBUG(spdlog::get("statuslog"), "IP \"{}\" hashed -> \"{}\"", parIP, retval);
- assert(retval.size() == 16 * 3);
- return retval;
- }
} //unnamed namespace
SubmitPasteResponse::SubmitPasteResponse (
@@ -174,8 +148,8 @@ namespace tawashi {
return std::make_pair(boost::optional(), make_error_redirect(ErrorReasons::RedisDisconnected));
}
- std::string ip_hash = hashed_ip(cgi_env().remote_addr());
- if (redis.get(ip_hash)) {
+ std::string remote_ip = guess_real_remote_ip(cgi_env());
+ if (redis.get(remote_ip)) {
//please wait and submit again
return std::make_pair(boost::optional(), make_error_redirect(ErrorReasons::UserFlooding));
}
@@ -188,8 +162,8 @@ namespace tawashi {
"max_ttl", dhandy::lexical_cast(parExpiry),
"lang", parLang)
) {
- redis.set(ip_hash, "");
- redis.expire(ip_hash, settings().as("resubmit_wait"));
+ redis.set(remote_ip, "");
+ redis.expire(remote_ip, settings().as("resubmit_wait"));
if (redis.expire(token, parExpiry))
return std::make_pair(boost::make_optional(token), HttpHeader());
}