1
0
Fork 0
mirror of https://github.com/KingDuckZ/kamokan.git synced 2024-12-27 21:35:41 +00:00

Move ip requesting code into a separate file and make hashing configurable at build time.

New code tries to guess a per-visitor IP address and uses
that (or its hash) to tell users apart.
This patch also adds a TAWASHI_WITH_IP_LOGGING cmake option
to enable or disable logging the IP address of your visitors
in various places (just one right now but don't assume things
to remain this way).
Also added a couple new CGI environment variables.
This commit is contained in:
King_DuckZ 2017-05-24 09:34:52 +01:00
parent 1507c79503
commit 9fff9d793c
9 changed files with 133 additions and 31 deletions

View file

@ -4,6 +4,8 @@ project(tawashi_top VERSION 0.1.11 LANGUAGES NONE)
include(CTest) 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(INCREDIS_FORCE_DISABLE_TESTS ON)
set(TAWASHI_SOURCE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}") set(TAWASHI_SOURCE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}")
set(TAWASHI_GEN_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/include") set(TAWASHI_GEN_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/include")

View file

@ -23,3 +23,4 @@
#define VERSION_MAJOR @PROJECT_VERSION_MAJOR@ #define VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define VERSION_MINOR @PROJECT_VERSION_MINOR@ #define VERSION_MINOR @PROJECT_VERSION_MINOR@
#define VERSION_PATCH @PROJECT_VERSION_PATCH@ #define VERSION_PATCH @PROJECT_VERSION_PATCH@
#cmakedefine TAWASHI_WITH_IP_LOGGING

View file

@ -28,6 +28,7 @@ add_library(${PROJECT_NAME} STATIC
tawashi_exception.cpp tawashi_exception.cpp
http_header.cpp http_header.cpp
quick_submit_paste_response.cpp quick_submit_paste_response.cpp
ip_utils.cpp
) )
target_include_directories(${PROJECT_NAME} target_include_directories(${PROJECT_NAME}

View file

@ -150,6 +150,14 @@ namespace cgi {
return m_cgi_env[CGIVars::QUERY_STRING]; 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 { const std::string& Env::remote_addr() const {
return m_cgi_env[CGIVars::REMOTE_ADDR]; return m_cgi_env[CGIVars::REMOTE_ADDR];
} }

View file

@ -52,6 +52,8 @@ namespace tawashi {
boost::string_ref path_info() const; boost::string_ref path_info() const;
const std::string& path_translated() const; const std::string& path_translated() const;
const std::string& query_string() 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_addr() const;
const std::string& remote_host() const; const std::string& remote_host() const;
const std::string& remote_ident() const; const std::string& remote_ident() const;

View file

@ -28,9 +28,11 @@ namespace tawashi {
CONTENT_TYPE, CONTENT_TYPE,
DOCUMENT_ROOT, //The root directory of your server DOCUMENT_ROOT, //The root directory of your server
GATEWAY_INTERFACE, GATEWAY_INTERFACE,
HTTP_CLIENT_IP,
HTTP_COOKIE, //The visitor's cookie, if one is set HTTP_COOKIE, //The visitor's cookie, if one is set
HTTP_HOST, //The hostname of your server HTTP_HOST, //The hostname of your server
HTTP_REFERER, //The URL of the page that called your script 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 HTTPS, //"on" if the script is being called through a secure server
HTTP_USER_AGENT, //The browser type of your visitor HTTP_USER_AGENT, //The browser type of your visitor
PATH, //The system path your server is running under PATH, //The system path your server is running under

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "ip_utils.hpp"
#include "duckhandy/lexical_cast.hpp"
#include "duckhandy/int_to_string_ary.hpp"
#include "cgi_env.hpp"
#include "tawashiConfig.h"
#include <spdlog/spdlog.h>
#include <cassert>
#include <algorithm>
#include <ciso646>
#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<char, hex>(hash[0]);
auto h2 = dhandy::int_to_string_ary<char, hex>(hash[1]);
auto h3 = dhandy::int_to_string_ary<char, hex>(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

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "duckhandy/compatibility.h"
#include <string>
namespace tawashi {
namespace cgi {
class Env;
} //namespace cgi
std::string guess_real_remote_ip (const cgi::Env& parCgiEnv) a_pure;
} //namespace tawashi

View file

@ -18,21 +18,18 @@
#include "submit_paste_response.hpp" #include "submit_paste_response.hpp"
#include "incredis/incredis.hpp" #include "incredis/incredis.hpp"
#include "cgi_post.hpp" #include "cgi_post.hpp"
#include "cgi_env.hpp"
#include "num_to_token.hpp" #include "num_to_token.hpp"
#include "settings_bag.hpp" #include "settings_bag.hpp"
#include "duckhandy/compatibility.h" #include "duckhandy/compatibility.h"
#include "duckhandy/lexical_cast.hpp" #include "duckhandy/lexical_cast.hpp"
#include "duckhandy/int_to_string_ary.hpp"
#include "tawashi_exception.hpp" #include "tawashi_exception.hpp"
#include "ip_utils.hpp"
#include <ciso646> #include <ciso646>
#include <algorithm> #include <algorithm>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <cstdint> #include <cstdint>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
extern "C" void tiger (const char* parStr, uint64_t parLength, uint64_t parHash[3], char parPadding);
namespace tawashi { namespace tawashi {
namespace { namespace {
const char g_post_key[] = "pastie"; const char g_post_key[] = "pastie";
@ -75,29 +72,6 @@ namespace tawashi {
return boost::string_ref(); 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<char, hex>(hash[0]);
auto h2 = dhandy::int_to_string_ary<char, hex>(hash[1]);
auto h3 = dhandy::int_to_string_ary<char, hex>(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 } //unnamed namespace
SubmitPasteResponse::SubmitPasteResponse ( SubmitPasteResponse::SubmitPasteResponse (
@ -174,8 +148,8 @@ namespace tawashi {
return std::make_pair(boost::optional<std::string>(), make_error_redirect(ErrorReasons::RedisDisconnected)); return std::make_pair(boost::optional<std::string>(), make_error_redirect(ErrorReasons::RedisDisconnected));
} }
std::string ip_hash = hashed_ip(cgi_env().remote_addr()); std::string remote_ip = guess_real_remote_ip(cgi_env());
if (redis.get(ip_hash)) { if (redis.get(remote_ip)) {
//please wait and submit again //please wait and submit again
return std::make_pair(boost::optional<std::string>(), make_error_redirect(ErrorReasons::UserFlooding)); return std::make_pair(boost::optional<std::string>(), make_error_redirect(ErrorReasons::UserFlooding));
} }
@ -188,8 +162,8 @@ namespace tawashi {
"max_ttl", dhandy::lexical_cast<std::string>(parExpiry), "max_ttl", dhandy::lexical_cast<std::string>(parExpiry),
"lang", parLang) "lang", parLang)
) { ) {
redis.set(ip_hash, ""); redis.set(remote_ip, "");
redis.expire(ip_hash, settings().as<uint32_t>("resubmit_wait")); redis.expire(remote_ip, settings().as<uint32_t>("resubmit_wait"));
if (redis.expire(token, parExpiry)) if (redis.expire(token, parExpiry))
return std::make_pair(boost::make_optional(token), HttpHeader()); return std::make_pair(boost::make_optional(token), HttpHeader());
} }