diff options
Diffstat (limited to 'src/modules')
-rw-r--r-- | src/modules/extra/m_ldap.cpp | 647 | ||||
-rw-r--r-- | src/modules/extra/m_ssl_gnutls.cpp | 132 | ||||
-rw-r--r-- | src/modules/extra/m_ssl_openssl.cpp | 25 | ||||
-rw-r--r-- | src/modules/m_alias.cpp | 18 | ||||
-rw-r--r-- | src/modules/m_callerid.cpp | 6 | ||||
-rw-r--r-- | src/modules/m_close.cpp | 4 | ||||
-rw-r--r-- | src/modules/m_hidechans.cpp | 14 | ||||
-rw-r--r-- | src/modules/m_hideoper.cpp | 11 | ||||
-rw-r--r-- | src/modules/m_jumpserver.cpp | 4 | ||||
-rw-r--r-- | src/modules/m_nationalchars.cpp | 4 | ||||
-rw-r--r-- | src/modules/m_services_account.cpp | 8 | ||||
-rw-r--r-- | src/modules/m_servprotect.cpp | 7 | ||||
-rw-r--r-- | src/modules/m_silence.cpp | 10 | ||||
-rw-r--r-- | src/modules/m_spanningtree/nick.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_spanningtree/nickcollide.cpp | 6 | ||||
-rw-r--r-- | src/modules/m_spanningtree/uid.cpp | 4 | ||||
-rw-r--r-- | src/modules/m_spanningtree/utils.cpp | 1 | ||||
-rw-r--r-- | src/modules/m_spanningtree/utils.h | 2 |
18 files changed, 535 insertions, 370 deletions
diff --git a/src/modules/extra/m_ldap.cpp b/src/modules/extra/m_ldap.cpp index 10469f370..c11025836 100644 --- a/src/modules/extra/m_ldap.cpp +++ b/src/modules/extra/m_ldap.cpp @@ -1,8 +1,8 @@ /* * InspIRCd -- Internet Relay Chat Daemon * - * Copyright (C) 2013-2014 Adam <Adam@anope.org> - * Copyright (C) 2003-2014 Anope Team <team@anope.org> + * Copyright (C) 2013-2015 Adam <Adam@anope.org> + * Copyright (C) 2003-2015 Anope Team <team@anope.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public @@ -29,6 +29,140 @@ /* $LinkerFlags: -lldap_r */ +class LDAPService; + +class LDAPRequest +{ + public: + LDAPService* service; + LDAPInterface* inter; + LDAPMessage* message; /* message returned by ldap_ */ + LDAPResult* result; /* final result */ + struct timeval tv; + QueryType type; + + LDAPRequest(LDAPService* s, LDAPInterface* i) + : service(s) + , inter(i) + , message(NULL) + , result(NULL) + { + type = QUERY_UNKNOWN; + tv.tv_sec = 0; + tv.tv_usec = 100000; + } + + virtual ~LDAPRequest() + { + delete result; + if (message != NULL) + ldap_msgfree(message); + } + + virtual int run() = 0; +}; + +class LDAPBind : public LDAPRequest +{ + std::string who, pass; + + public: + LDAPBind(LDAPService* s, LDAPInterface* i, const std::string& w, const std::string& p) + : LDAPRequest(s, i) + , who(w) + , pass(p) + { + type = QUERY_BIND; + } + + int run() CXX11_OVERRIDE; +}; + +class LDAPSearch : public LDAPRequest +{ + std::string base; + int searchscope; + std::string filter; + + public: + LDAPSearch(LDAPService* s, LDAPInterface* i, const std::string& b, int se, const std::string& f) + : LDAPRequest(s, i) + , base(b) + , searchscope(se) + , filter(f) + { + type = QUERY_SEARCH; + } + + int run() CXX11_OVERRIDE; +}; + +class LDAPAdd : public LDAPRequest +{ + std::string dn; + LDAPMods attributes; + + public: + LDAPAdd(LDAPService* s, LDAPInterface* i, const std::string& d, const LDAPMods& attr) + : LDAPRequest(s, i) + , dn(d) + , attributes(attr) + { + type = QUERY_ADD; + } + + int run() CXX11_OVERRIDE; +}; + +class LDAPDel : public LDAPRequest +{ + std::string dn; + + public: + LDAPDel(LDAPService* s, LDAPInterface* i, const std::string& d) + : LDAPRequest(s, i) + , dn(d) + { + type = QUERY_DELETE; + } + + int run() CXX11_OVERRIDE; +}; + +class LDAPModify : public LDAPRequest +{ + std::string base; + LDAPMods attributes; + + public: + LDAPModify(LDAPService* s, LDAPInterface* i, const std::string& b, const LDAPMods& attr) + : LDAPRequest(s, i) + , base(b) + , attributes(attr) + { + type = QUERY_MODIFY; + } + + int run() CXX11_OVERRIDE; +}; + +class LDAPCompare : public LDAPRequest +{ + std::string dn, attr, val; + + public: + LDAPCompare(LDAPService* s, LDAPInterface* i, const std::string& d, const std::string& a, const std::string& v) + : LDAPRequest(s, i) + , dn(d) + , attr(a) + , val(v) + { + type = QUERY_COMPARE; + } + + int run() CXX11_OVERRIDE; +}; + class LDAPService : public LDAPProvider, public SocketThread { LDAP* con; @@ -38,7 +172,8 @@ class LDAPService : public LDAPProvider, public SocketThread time_t timeout; time_t last_timeout_check; - LDAPMod** BuildMods(const LDAPMods& attributes) + public: + static LDAPMod** BuildMods(const LDAPMods& attributes) { LDAPMod** mods = new LDAPMod*[attributes.size() + 1]; memset(mods, 0, sizeof(LDAPMod*) * (attributes.size() + 1)); @@ -69,7 +204,7 @@ class LDAPService : public LDAPProvider, public SocketThread return mods; } - void FreeMods(LDAPMod** mods) + static void FreeMods(LDAPMod** mods) { for (unsigned int i = 0; mods[i] != NULL; ++i) { @@ -86,6 +221,7 @@ class LDAPService : public LDAPProvider, public SocketThread delete[] mods; } + private: void Reconnect() { // Only try one connect a minute. It is an expensive blocking operation @@ -97,48 +233,17 @@ class LDAPService : public LDAPProvider, public SocketThread Connect(); } - void SaveInterface(LDAPInterface* i, LDAPQuery msgid) + void QueueRequest(LDAPRequest* r) { - if (i != NULL) - { - this->LockQueue(); - this->queries[msgid] = std::make_pair(ServerInstance->Time(), i); - this->UnlockQueueWakeup(); - } - } - - void Timeout() - { - if (last_timeout_check == ServerInstance->Time()) - return; - last_timeout_check = ServerInstance->Time(); - - for (query_queue::iterator it = this->queries.begin(); it != this->queries.end(); ) - { - LDAPQuery msgid = it->first; - time_t created = it->second.first; - LDAPInterface* i = it->second.second; - ++it; - - if (ServerInstance->Time() > created + timeout) - { - LDAPResult* ldap_result = new LDAPResult(); - ldap_result->id = msgid; - ldap_result->error = "Query timed out"; - - this->queries.erase(msgid); - this->results.push_back(std::make_pair(i, ldap_result)); - - this->NotifyParent(); - } - } + this->LockQueue(); + this->queries.push_back(r); + this->UnlockQueueWakeup(); } public: - typedef std::map<LDAPQuery, std::pair<time_t, LDAPInterface*> > query_queue; - typedef std::vector<std::pair<LDAPInterface*, LDAPResult*> > result_queue; - query_queue queries; - result_queue results; + typedef std::vector<LDAPRequest*> query_queue; + query_queue queries, results; + Mutex process_mutex; /* held when processing requests not in either queue */ LDAPService(Module* c, ConfigTag* tag) : LDAPProvider(c, "LDAP/" + tag->getString("id")) @@ -160,30 +265,29 @@ class LDAPService : public LDAPProvider, public SocketThread { this->LockQueue(); - for (query_queue::iterator i = this->queries.begin(); i != this->queries.end(); ++i) + for (unsigned int i = 0; i < this->queries.size(); ++i) { - LDAPQuery msgid = i->first; - LDAPInterface* inter = i->second.second; + LDAPRequest* req = this->queries[i]; - ldap_abandon_ext(this->con, msgid, NULL, NULL); + /* queries have no results yet */ + req->result = new LDAPResult(); + req->result->type = req->type; + req->result->error = "LDAP Interface is going away"; + req->inter->OnError(*req->result); - if (inter) - { - LDAPResult r; - r.error = "LDAP Interface is going away"; - inter->OnError(r); - } + delete req; } this->queries.clear(); - for (result_queue::iterator i = this->results.begin(); i != this->results.end(); ++i) + for (unsigned int i = 0; i < this->results.size(); ++i) { - LDAPInterface* inter = i->first; - LDAPResult* r = i->second; + LDAPRequest* req = this->results[i]; + + /* even though this may have already finished successfully we return that it didn't */ + req->result->error = "LDAP Interface is going away"; + req->inter->OnError(*req->result); - r->error = "LDAP Interface is going away"; - if (inter) - inter->OnError(*r); + delete req; } this->results.clear(); @@ -218,316 +322,192 @@ class LDAPService : public LDAPProvider, public SocketThread } } - LDAPQuery BindAsManager(LDAPInterface* i) CXX11_OVERRIDE + void BindAsManager(LDAPInterface* i) CXX11_OVERRIDE { std::string binddn = config->getString("binddn"); std::string bindauth = config->getString("bindauth"); - return this->Bind(i, binddn, bindauth); + this->Bind(i, binddn, bindauth); } - LDAPQuery Bind(LDAPInterface* i, const std::string& who, const std::string& pass) CXX11_OVERRIDE + void Bind(LDAPInterface* i, const std::string& who, const std::string& pass) CXX11_OVERRIDE { - berval cred; - cred.bv_val = strdup(pass.c_str()); - cred.bv_len = pass.length(); - - LDAPQuery msgid; - int ret = ldap_sasl_bind(con, who.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, &msgid); - free(cred.bv_val); - if (ret != LDAP_SUCCESS) - { - if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT) - { - this->Reconnect(); - return this->Bind(i, who, pass); - } - else - throw LDAPException(ldap_err2string(ret)); - } - - SaveInterface(i, msgid); - return msgid; + LDAPBind* b = new LDAPBind(this, i, who, pass); + QueueRequest(b); } - LDAPQuery Search(LDAPInterface* i, const std::string& base, const std::string& filter) CXX11_OVERRIDE + void Search(LDAPInterface* i, const std::string& base, const std::string& filter) CXX11_OVERRIDE { if (i == NULL) throw LDAPException("No interface"); - LDAPQuery msgid; - int ret = ldap_search_ext(this->con, base.c_str(), searchscope, filter.c_str(), NULL, 0, NULL, NULL, NULL, 0, &msgid); - if (ret != LDAP_SUCCESS) - { - if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT) - { - this->Reconnect(); - return this->Search(i, base, filter); - } - else - throw LDAPException(ldap_err2string(ret)); - } - - SaveInterface(i, msgid); - return msgid; + LDAPSearch* s = new LDAPSearch(this, i, base, searchscope, filter); + QueueRequest(s); } - LDAPQuery Add(LDAPInterface* i, const std::string& dn, LDAPMods& attributes) CXX11_OVERRIDE + void Add(LDAPInterface* i, const std::string& dn, LDAPMods& attributes) CXX11_OVERRIDE { - LDAPMod** mods = this->BuildMods(attributes); - LDAPQuery msgid; - int ret = ldap_add_ext(this->con, dn.c_str(), mods, NULL, NULL, &msgid); - this->FreeMods(mods); - - if (ret != LDAP_SUCCESS) - { - if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT) - { - this->Reconnect(); - return this->Add(i, dn, attributes); - } - else - throw LDAPException(ldap_err2string(ret)); - } - - SaveInterface(i, msgid); - return msgid; + LDAPAdd* add = new LDAPAdd(this, i, dn, attributes); + QueueRequest(add); } - LDAPQuery Del(LDAPInterface* i, const std::string& dn) CXX11_OVERRIDE + void Del(LDAPInterface* i, const std::string& dn) CXX11_OVERRIDE { - LDAPQuery msgid; - int ret = ldap_delete_ext(this->con, dn.c_str(), NULL, NULL, &msgid); - - if (ret != LDAP_SUCCESS) - { - if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT) - { - this->Reconnect(); - return this->Del(i, dn); - } - else - throw LDAPException(ldap_err2string(ret)); - } - - SaveInterface(i, msgid); - return msgid; + LDAPDel* del = new LDAPDel(this, i, dn); + QueueRequest(del); } - LDAPQuery Modify(LDAPInterface* i, const std::string& base, LDAPMods& attributes) CXX11_OVERRIDE + void Modify(LDAPInterface* i, const std::string& base, LDAPMods& attributes) CXX11_OVERRIDE { - LDAPMod** mods = this->BuildMods(attributes); - LDAPQuery msgid; - int ret = ldap_modify_ext(this->con, base.c_str(), mods, NULL, NULL, &msgid); - this->FreeMods(mods); - - if (ret != LDAP_SUCCESS) - { - if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT) - { - this->Reconnect(); - return this->Modify(i, base, attributes); - } - else - throw LDAPException(ldap_err2string(ret)); - } + LDAPModify* mod = new LDAPModify(this, i, base, attributes); + QueueRequest(mod); + } - SaveInterface(i, msgid); - return msgid; + void Compare(LDAPInterface* i, const std::string& dn, const std::string& attr, const std::string& val) CXX11_OVERRIDE + { + LDAPCompare* comp = new LDAPCompare(this, i, dn, attr, val); + QueueRequest(comp); } - LDAPQuery Compare(LDAPInterface* i, const std::string& dn, const std::string& attr, const std::string& val) CXX11_OVERRIDE + private: + void BuildReply(int res, LDAPRequest* req) { - berval cred; - cred.bv_val = strdup(val.c_str()); - cred.bv_len = val.length(); + LDAPResult* ldap_result = req->result = new LDAPResult(); + req->result->type = req->type; - LDAPQuery msgid; - int ret = ldap_compare_ext(con, dn.c_str(), attr.c_str(), &cred, NULL, NULL, &msgid); - free(cred.bv_val); + if (res != LDAP_SUCCESS) + { + ldap_result->error = ldap_err2string(res); + return; + } - if (ret != LDAP_SUCCESS) + if (req->message == NULL) { - if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT) - { - this->Reconnect(); - return this->Compare(i, dn, attr, val); - } - else - throw LDAPException(ldap_err2string(ret)); + return; } - SaveInterface(i, msgid); - return msgid; - } + /* a search result */ - void Run() CXX11_OVERRIDE - { - while (!this->GetExitFlag()) + for (LDAPMessage* cur = ldap_first_message(this->con, req->message); cur; cur = ldap_next_message(this->con, cur)) { - this->LockQueue(); - if (this->queries.empty()) + LDAPAttributes attributes; + + char* dn = ldap_get_dn(this->con, cur); + if (dn != NULL) { - this->WaitForQueue(); - this->UnlockQueue(); - continue; + attributes["dn"].push_back(dn); + ldap_memfree(dn); + dn = NULL; } - this->Timeout(); - this->UnlockQueue(); - struct timeval tv = { 1, 0 }; - LDAPMessage* result; - int rtype = ldap_result(this->con, LDAP_RES_ANY, 1, &tv, &result); - if (rtype <= 0 || this->GetExitFlag()) - continue; + BerElement* ber = NULL; - int cur_id = ldap_msgid(result); + for (char* attr = ldap_first_attribute(this->con, cur, &ber); attr; attr = ldap_next_attribute(this->con, cur, ber)) + { + berval** vals = ldap_get_values_len(this->con, cur, attr); + int count = ldap_count_values_len(vals); - this->LockQueue(); + std::vector<std::string> attrs; + for (int j = 0; j < count; ++j) + attrs.push_back(vals[j]->bv_val); + attributes[attr] = attrs; - query_queue::iterator it = this->queries.find(cur_id); - if (it == this->queries.end()) - { - this->UnlockQueue(); - ldap_msgfree(result); - continue; + ldap_value_free_len(vals); + ldap_memfree(attr); } - LDAPInterface* i = it->second.second; - this->queries.erase(it); + if (ber != NULL) + ber_free(ber, 0); - this->UnlockQueue(); + ldap_result->messages.push_back(attributes); + } + } - LDAPResult* ldap_result = new LDAPResult(); - ldap_result->id = cur_id; + void SendRequests() + { + process_mutex.Lock(); - for (LDAPMessage* cur = ldap_first_message(this->con, result); cur; cur = ldap_next_message(this->con, cur)) - { - int cur_type = ldap_msgtype(cur); + query_queue q; + this->LockQueue(); + queries.swap(q); + this->UnlockQueue(); - LDAPAttributes attributes; + if (q.empty()) + { + process_mutex.Unlock(); + return; + } - { - char* dn = ldap_get_dn(this->con, cur); - if (dn != NULL) - { - attributes["dn"].push_back(dn); - ldap_memfree(dn); - } - } + for (unsigned int i = 0; i < q.size(); ++i) + { + LDAPRequest* req = q[i]; + int ret = req->run(); - switch (cur_type) + if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT) + { + /* try again */ + try { - case LDAP_RES_BIND: - ldap_result->type = LDAPResult::QUERY_BIND; - break; - case LDAP_RES_SEARCH_ENTRY: - ldap_result->type = LDAPResult::QUERY_SEARCH; - break; - case LDAP_RES_ADD: - ldap_result->type = LDAPResult::QUERY_ADD; - break; - case LDAP_RES_DELETE: - ldap_result->type = LDAPResult::QUERY_DELETE; - break; - case LDAP_RES_MODIFY: - ldap_result->type = LDAPResult::QUERY_MODIFY; - break; - case LDAP_RES_SEARCH_RESULT: - // If we get here and ldap_result->type is LDAPResult::QUERY_UNKNOWN - // then the result set is empty - ldap_result->type = LDAPResult::QUERY_SEARCH; - break; - case LDAP_RES_COMPARE: - ldap_result->type = LDAPResult::QUERY_COMPARE; - break; - default: - continue; + Reconnect(); } - - switch (cur_type) + catch (const LDAPException &) { - case LDAP_RES_SEARCH_ENTRY: - { - BerElement* ber = NULL; - for (char* attr = ldap_first_attribute(this->con, cur, &ber); attr; attr = ldap_next_attribute(this->con, cur, ber)) - { - berval** vals = ldap_get_values_len(this->con, cur, attr); - int count = ldap_count_values_len(vals); - - std::vector<std::string> attrs; - for (int j = 0; j < count; ++j) - attrs.push_back(vals[j]->bv_val); - attributes[attr] = attrs; - - ldap_value_free_len(vals); - ldap_memfree(attr); - } - if (ber != NULL) - ber_free(ber, 0); - - break; - } - case LDAP_RES_BIND: - case LDAP_RES_ADD: - case LDAP_RES_DELETE: - case LDAP_RES_MODIFY: - case LDAP_RES_COMPARE: - { - int errcode = -1; - int parse_result = ldap_parse_result(this->con, cur, &errcode, NULL, NULL, NULL, NULL, 0); - if (parse_result != LDAP_SUCCESS) - { - ldap_result->error = ldap_err2string(parse_result); - } - else - { - if (cur_type == LDAP_RES_COMPARE) - { - if (errcode != LDAP_COMPARE_TRUE) - ldap_result->error = ldap_err2string(errcode); - } - else if (errcode != LDAP_SUCCESS) - ldap_result->error = ldap_err2string(errcode); - } - break; - } - default: - continue; } - ldap_result->messages.push_back(attributes); + ret = req->run(); } - ldap_msgfree(result); + BuildReply(ret, req); this->LockQueue(); - this->results.push_back(std::make_pair(i, ldap_result)); - this->UnlockQueueWakeup(); + this->results.push_back(req); + this->UnlockQueue(); + } + + this->NotifyParent(); + + process_mutex.Unlock(); + } - this->NotifyParent(); + public: + void Run() CXX11_OVERRIDE + { + while (!this->GetExitFlag()) + { + this->LockQueue(); + if (this->queries.empty()) + this->WaitForQueue(); + this->UnlockQueue(); + + SendRequests(); } } void OnNotify() CXX11_OVERRIDE { - LDAPService::result_queue r; + query_queue r; this->LockQueue(); this->results.swap(r); this->UnlockQueue(); - for (LDAPService::result_queue::iterator i = r.begin(); i != r.end(); ++i) + for (unsigned int i = 0; i < r.size(); ++i) { - LDAPInterface* li = i->first; - LDAPResult* res = i->second; + LDAPRequest* req = r[i]; + LDAPInterface* li = req->inter; + LDAPResult* res = req->result; if (!res->error.empty()) li->OnError(*res); else li->OnResult(*res); - delete res; + delete req; } } + + LDAP* GetConnection() + { + return con; + } }; class ModuleLDAP : public Module @@ -583,28 +563,36 @@ class ModuleLDAP : public Module for (ServiceMap::iterator it = this->LDAPServices.begin(); it != this->LDAPServices.end(); ++it) { LDAPService* s = it->second; + + s->process_mutex.Lock(); s->LockQueue(); - for (LDAPService::query_queue::iterator it2 = s->queries.begin(); it2 != s->queries.end();) + + for (unsigned int i = s->queries.size(); i > 0; --i) { - int msgid = it2->first; - LDAPInterface* i = it2->second.second; - ++it2; + LDAPRequest* req = s->queries[i - 1]; + LDAPInterface* li = req->inter; - if (i->creator == m) - s->queries.erase(msgid); + if (li->creator == m) + { + s->queries.erase(s->queries.begin() + i - 1); + delete req; + } } + for (unsigned int i = s->results.size(); i > 0; --i) { - LDAPInterface* li = s->results[i - 1].first; - LDAPResult* r = s->results[i - 1].second; + LDAPRequest* req = s->results[i - 1]; + LDAPInterface* li = req->inter; if (li->creator == m) { s->results.erase(s->results.begin() + i - 1); - delete r; + delete req; } } + s->UnlockQueue(); + s->process_mutex.Unlock(); } } @@ -625,4 +613,57 @@ class ModuleLDAP : public Module } }; +int LDAPBind::run() +{ + berval cred; + cred.bv_val = strdup(pass.c_str()); + cred.bv_len = pass.length(); + + int i = ldap_sasl_bind_s(service->GetConnection(), who.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL); + + free(cred.bv_val); + + return i; +} + +int LDAPSearch::run() +{ + return ldap_search_ext_s(service->GetConnection(), base.c_str(), searchscope, filter.c_str(), NULL, 0, NULL, NULL, &tv, 0, &message); +} + +int LDAPAdd::run() +{ + LDAPMod** mods = LDAPService::BuildMods(attributes); + int i = ldap_add_ext_s(service->GetConnection(), dn.c_str(), mods, NULL, NULL); + LDAPService::FreeMods(mods); + return i; +} + +int LDAPDel::run() +{ + return ldap_delete_ext_s(service->GetConnection(), dn.c_str(), NULL, NULL); +} + +int LDAPModify::run() +{ + LDAPMod** mods = LDAPService::BuildMods(attributes); + int i = ldap_modify_ext_s(service->GetConnection(), base.c_str(), mods, NULL, NULL); + LDAPService::FreeMods(mods); + return i; +} + +int LDAPCompare::run() +{ + berval cred; + cred.bv_val = strdup(val.c_str()); + cred.bv_len = val.length(); + + int ret = ldap_compare_ext_s(service->GetConnection(), dn.c_str(), attr.c_str(), &cred, NULL, NULL); + + free(cred.bv_val); + + return ret; + +} + MODULE_INIT(ModuleLDAP) diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp index d33403aba..962e80d28 100644 --- a/src/modules/extra/m_ssl_gnutls.cpp +++ b/src/modules/extra/m_ssl_gnutls.cpp @@ -37,6 +37,7 @@ #ifndef GNUTLS_VERSION_NUMBER #define GNUTLS_VERSION_NUMBER LIBGNUTLS_VERSION_NUMBER +#define GNUTLS_VERSION LIBGNUTLS_VERSION #endif // Check if the GnuTLS library is at least version major.minor.patch @@ -92,6 +93,10 @@ typedef unsigned int inspircd_gnutls_session_init_flags_t; typedef gnutls_connection_end_t inspircd_gnutls_session_init_flags_t; #endif +#if INSPIRCD_GNUTLS_HAS_VERSION(3, 1, 9) +#define INSPIRCD_GNUTLS_HAS_CORK +#endif + class RandGen : public HandlerBase2<void, char*, size_t> { public: @@ -531,14 +536,20 @@ namespace GnuTLS */ Priority priority; + /** Rough max size of records to send + */ + const unsigned int outrecsize; + Profile(const std::string& profilename, const std::string& certstr, const std::string& keystr, std::auto_ptr<DHParams>& DH, unsigned int mindh, const std::string& hashstr, - const std::string& priostr, std::auto_ptr<X509CertList>& CA, std::auto_ptr<X509CRL>& CRL) + const std::string& priostr, std::auto_ptr<X509CertList>& CA, std::auto_ptr<X509CRL>& CRL, + unsigned int recsize) : name(profilename) , x509cred(certstr, keystr) , min_dh_bits(mindh) , hash(hashstr) , priority(priostr) + , outrecsize(recsize) { x509cred.SetDH(DH); x509cred.SetCA(CA, CRL); @@ -587,7 +598,13 @@ namespace GnuTLS crl.reset(new X509CRL(ReadFile(filename))); } - return new Profile(profilename, certstr, keystr, dh, mindh, hashstr, priostr, ca, crl); +#ifdef INSPIRCD_GNUTLS_HAS_CORK + // If cork support is available outrecsize represents the (rough) max amount of data we give GnuTLS while corked + unsigned int outrecsize = tag->getInt("outrecsize", 2048, 512); +#else + unsigned int outrecsize = tag->getInt("outrecsize", 2048, 512, 16384); +#endif + return new Profile(profilename, certstr, keystr, dh, mindh, hashstr, priostr, ca, crl, outrecsize); } /** Set up the given session with the settings in this profile @@ -605,6 +622,7 @@ namespace GnuTLS const std::string& GetName() const { return name; } X509Credentials& GetX509Credentials() { return x509cred; } gnutls_digest_algorithm_t GetHash() const { return hash.get(); } + unsigned int GetOutgoingRecordSize() const { return outrecsize; } }; } @@ -614,6 +632,9 @@ class GnuTLSIOHook : public SSLIOHook gnutls_session_t sess; issl_status status; reference<GnuTLS::Profile> profile; +#ifdef INSPIRCD_GNUTLS_HAS_CORK + size_t gbuffersize; +#endif void CloseSession() { @@ -793,6 +814,43 @@ info_done_dealloc: return -1; } +#ifdef INSPIRCD_GNUTLS_HAS_CORK + int FlushBuffer(StreamSocket* sock) + { + // If GnuTLS has some data buffered, write it + if (gbuffersize) + return HandleWriteRet(sock, gnutls_record_uncork(this->sess, 0)); + return 1; + } +#endif + + int HandleWriteRet(StreamSocket* sock, int ret) + { + if (ret > 0) + { +#ifdef INSPIRCD_GNUTLS_HAS_CORK + gbuffersize -= ret; + if (gbuffersize) + { + SocketEngine::ChangeEventMask(sock, FD_WANT_SINGLE_WRITE); + return 0; + } +#endif + return ret; + } + else if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED || ret == 0) + { + SocketEngine::ChangeEventMask(sock, FD_WANT_SINGLE_WRITE); + return 0; + } + else // (ret < 0) + { + sock->SetError(gnutls_strerror(ret)); + CloseSession(); + return -1; + } + } + static const char* UnknownIfNULL(const char* str) { return str ? str : "UNKNOWN"; @@ -913,6 +971,9 @@ info_done_dealloc: , sess(NULL) , status(ISSL_NONE) , profile(sslprofile) +#ifdef INSPIRCD_GNUTLS_HAS_CORK + , gbuffersize(0) +#endif { gnutls_init(&sess, flags); gnutls_transport_set_ptr(sess, reinterpret_cast<gnutls_transport_ptr_t>(sock)); @@ -968,7 +1029,7 @@ info_done_dealloc: } } - int OnStreamSocketWrite(StreamSocket* user, std::string& sendq) CXX11_OVERRIDE + int OnStreamSocketWrite(StreamSocket* user) CXX11_OVERRIDE { // Finish handshake if needed int prepret = PrepareIO(user); @@ -976,34 +1037,60 @@ info_done_dealloc: return prepret; // Session is ready for transferring application data - int ret = 0; + StreamSocket::SendQueue& sendq = user->GetSendQ(); +#ifdef INSPIRCD_GNUTLS_HAS_CORK + while (true) { - ret = gnutls_record_send(this->sess, sendq.data(), sendq.length()); - - if (ret == (int)sendq.length()) - { - SocketEngine::ChangeEventMask(user, FD_WANT_NO_WRITE); - return 1; - } - else if (ret > 0) + // If there is something in the GnuTLS buffer try to send() it + int ret = FlushBuffer(user); + if (ret <= 0) + return ret; // Couldn't flush entire buffer, retry later (or close on error) + + // GnuTLS buffer is empty, if the sendq is empty as well then break to set FD_WANT_NO_WRITE + if (sendq.empty()) + break; + + // GnuTLS buffer is empty but sendq is not, begin sending data from the sendq + gnutls_record_cork(this->sess); + while ((!sendq.empty()) && (gbuffersize < profile->GetOutgoingRecordSize())) { - sendq.erase(0, ret); - SocketEngine::ChangeEventMask(user, FD_WANT_SINGLE_WRITE); - return 0; + const StreamSocket::SendQueue::Element& elem = sendq.front(); + gbuffersize += elem.length(); + ret = gnutls_record_send(this->sess, elem.data(), elem.length()); + if (ret < 0) + { + CloseSession(); + return -1; + } + sendq.pop_front(); } - else if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED || ret == 0) + } +#else + int ret = 0; + + while (!sendq.empty()) + { + FlattenSendQueue(sendq, profile->GetOutgoingRecordSize()); + const StreamSocket::SendQueue::Element& buffer = sendq.front(); + ret = HandleWriteRet(user, gnutls_record_send(this->sess, buffer.data(), buffer.length())); + + if (ret <= 0) + return ret; + else if (ret < (int)buffer.length()) { + sendq.erase_front(ret); SocketEngine::ChangeEventMask(user, FD_WANT_SINGLE_WRITE); return 0; } - else // (ret < 0) - { - user->SetError(gnutls_strerror(ret)); - CloseSession(); - return -1; - } + + // Wrote entire record, continue sending + sendq.pop_front(); } +#endif + + SocketEngine::ChangeEventMask(user, FD_WANT_NO_WRITE); + return 1; } void TellCiphersAndFingerprint(LocalUser* user) @@ -1155,6 +1242,7 @@ class ModuleSSLGnuTLS : public Module void init() CXX11_OVERRIDE { + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "GnuTLS lib version %s module was compiled for " GNUTLS_VERSION, gnutls_check_version(NULL)); ReadProfiles(); ServerInstance->GenRandom = &randhandler; } diff --git a/src/modules/extra/m_ssl_openssl.cpp b/src/modules/extra/m_ssl_openssl.cpp index c8a035fac..e313ca7b5 100644 --- a/src/modules/extra/m_ssl_openssl.cpp +++ b/src/modules/extra/m_ssl_openssl.cpp @@ -238,6 +238,10 @@ namespace OpenSSL */ const bool allowrenego; + /** Rough max size of records to send + */ + const unsigned int outrecsize; + static int error_callback(const char* str, size_t len, void* u) { Profile* profile = reinterpret_cast<Profile*>(u); @@ -278,6 +282,7 @@ namespace OpenSSL , ctx(SSL_CTX_new(SSLv23_server_method())) , clictx(SSL_CTX_new(SSLv23_client_method())) , allowrenego(tag->getBool("renegotiation", true)) + , outrecsize(tag->getInt("outrecsize", 2048, 512, 16384)) { if ((!ctx.SetDH(dh)) || (!clictx.SetDH(dh))) throw Exception("Couldn't set DH parameters"); @@ -337,6 +342,7 @@ namespace OpenSSL SSL* CreateClientSession() { return clictx.CreateClientSession(); } const EVP_MD* GetDigest() { return digest; } bool AllowRenegotiation() const { return allowrenego; } + unsigned int GetOutgoingRecordSize() const { return outrecsize; } }; } @@ -601,7 +607,7 @@ class OpenSSLIOHook : public SSLIOHook } } - int OnStreamSocketWrite(StreamSocket* user, std::string& buffer) CXX11_OVERRIDE + int OnStreamSocketWrite(StreamSocket* user) CXX11_OVERRIDE { // Finish handshake if needed int prepret = PrepareIO(user); @@ -611,8 +617,12 @@ class OpenSSLIOHook : public SSLIOHook data_to_write = true; // Session is ready for transferring application data + StreamSocket::SendQueue& sendq = user->GetSendQ(); + while (!sendq.empty()) { ERR_clear_error(); + FlattenSendQueue(sendq, profile->GetOutgoingRecordSize()); + const StreamSocket::SendQueue::Element& buffer = sendq.front(); int ret = SSL_write(sess, buffer.data(), buffer.size()); #ifdef INSPIRCD_OPENSSL_ENABLE_RENEGO_DETECTION @@ -622,13 +632,12 @@ class OpenSSLIOHook : public SSLIOHook if (ret == (int)buffer.length()) { - data_to_write = false; - SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); - return 1; + // Wrote entire record, continue sending + sendq.pop_front(); } else if (ret > 0) { - buffer.erase(0, ret); + sendq.erase_front(ret); SocketEngine::ChangeEventMask(user, FD_WANT_SINGLE_WRITE); return 0; } @@ -658,6 +667,10 @@ class OpenSSLIOHook : public SSLIOHook } } } + + data_to_write = false; + SocketEngine::ChangeEventMask(user, FD_WANT_POLL_READ | FD_WANT_NO_WRITE); + return 1; } void TellCiphersAndFingerprint(LocalUser* user) @@ -787,6 +800,8 @@ class ModuleSSLOpenSSL : public Module void init() CXX11_OVERRIDE { + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "OpenSSL lib version \"%s\" module was compiled for \"" OPENSSL_VERSION_TEXT "\"", SSLeay_version(SSLEAY_VERSION)); + // Register application specific data char exdatastr[] = "inspircd"; exdataindex = SSL_get_ex_new_index(0, exdatastr, NULL, NULL, NULL); diff --git a/src/modules/m_alias.cpp b/src/modules/m_alias.cpp index 6bd59a780..1076b0a9a 100644 --- a/src/modules/m_alias.cpp +++ b/src/modules/m_alias.cpp @@ -57,7 +57,7 @@ class Alias class ModuleAlias : public Module { - char fprefix; + std::string fprefix; /* We cant use a map, there may be multiple aliases with the same name. * We can, however, use a fancy invention: the multimap. Maps a key to one or more values. @@ -76,8 +76,8 @@ class ModuleAlias : public Module { ConfigTag* fantasy = ServerInstance->Config->ConfValue("fantasy"); AllowBots = fantasy->getBool("allowbots", false); - std::string fpre = fantasy->getString("prefix", "!"); - fprefix = fpre.empty() ? '!' : fpre[0]; + std::string fpre = fantasy->getString("prefix"); + fprefix = fpre.empty() ? "!" : fpre; Aliases.clear(); ConfigTagList tags = ServerInstance->Config->ConfTags("alias"); @@ -193,26 +193,26 @@ class ModuleAlias : public Module irc::spacesepstream ss(text); ss.GetToken(scommand); - if (scommand.empty()) + if (scommand.size() <= fprefix.size()) { return; // wtfbbq } // we don't want to touch non-fantasy stuff - if (*scommand.c_str() != fprefix) + if (scommand.compare(0, fprefix.size(), fprefix) != 0) { return; } // nor do we give a shit about the prefix - scommand.erase(scommand.begin()); + scommand.erase(0, fprefix.size()); std::pair<AliasMap::iterator, AliasMap::iterator> iters = Aliases.equal_range(scommand); if (iters.first == iters.second) return; /* The parameters for the command in their original form, with the command stripped off */ - std::string compare(text, scommand.length() + 1); + std::string compare(text, scommand.length() + fprefix.size()); while (*(compare.c_str()) == ' ') compare.erase(compare.begin()); @@ -220,8 +220,8 @@ class ModuleAlias : public Module { if (i->second.ChannelCommand) { - // We use substr(1) here to remove the fantasy prefix - if (DoAlias(user, c, &(i->second), compare, text.substr(1))) + // We use substr here to remove the fantasy prefix + if (DoAlias(user, c, &(i->second), compare, text.substr(fprefix.size()))) return; } } diff --git a/src/modules/m_callerid.cpp b/src/modules/m_callerid.cpp index 5c6d14a90..26b9d0da2 100644 --- a/src/modules/m_callerid.cpp +++ b/src/modules/m_callerid.cpp @@ -426,6 +426,12 @@ public: tracknick = tag->getBool("tracknick"); notify_cooldown = tag->getInt("cooldown", 60); } + + void Prioritize() CXX11_OVERRIDE + { + // Want to be after modules like silence or services_account + ServerInstance->Modules->SetPriority(this, I_OnUserPreMessage, PRIORITY_LAST); + } }; MODULE_INIT(ModuleCallerID) diff --git a/src/modules/m_close.cpp b/src/modules/m_close.cpp index f3c751f17..3f0eedaaf 100644 --- a/src/modules/m_close.cpp +++ b/src/modules/m_close.cpp @@ -36,9 +36,11 @@ class CommandClose : public Command std::map<std::string,int> closed; const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); - for (UserManager::LocalList::const_iterator u = list.begin(); u != list.end(); ++u) + for (UserManager::LocalList::const_iterator u = list.begin(); u != list.end(); ) { + // Quitting the user removes it from the list LocalUser* user = *u; + ++u; if (user->registered != REG_ALL) { ServerInstance->Users->QuitUser(user, "Closing all unknown connections per request"); diff --git a/src/modules/m_hidechans.cpp b/src/modules/m_hidechans.cpp index cd3ac2c26..431b7b968 100644 --- a/src/modules/m_hidechans.cpp +++ b/src/modules/m_hidechans.cpp @@ -28,12 +28,14 @@ class HideChans : public SimpleUserModeHandler HideChans(Module* Creator) : SimpleUserModeHandler(Creator, "hidechans", 'I') { } }; -class ModuleHideChans : public Module +class ModuleHideChans : public Module, public Whois::LineEventListener { bool AffectsOpers; HideChans hm; public: - ModuleHideChans() : hm(this) + ModuleHideChans() + : Whois::LineEventListener(this) + , hm(this) { } @@ -47,10 +49,10 @@ class ModuleHideChans : public Module AffectsOpers = ServerInstance->Config->ConfValue("hidechans")->getBool("affectsopers"); } - ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text) CXX11_OVERRIDE + ModResult OnWhoisLine(Whois::Context& whois, unsigned int& numeric, std::string& text) CXX11_OVERRIDE { /* always show to self */ - if (user == dest) + if (whois.IsSelfWhois()) return MOD_RES_PASSTHRU; /* don't touch anything except 319 */ @@ -58,7 +60,7 @@ class ModuleHideChans : public Module return MOD_RES_PASSTHRU; /* don't touch if -I */ - if (!dest->IsModeSet(hm)) + if (!whois.GetTarget()->IsModeSet(hm)) return MOD_RES_PASSTHRU; /* if it affects opers, we don't care if they are opered */ @@ -66,7 +68,7 @@ class ModuleHideChans : public Module return MOD_RES_DENY; /* doesn't affect opers, sender is opered */ - if (user->HasPrivPermission("users/auspex")) + if (whois.GetSource()->HasPrivPermission("users/auspex")) return MOD_RES_PASSTHRU; /* user must be opered, boned. */ diff --git a/src/modules/m_hideoper.cpp b/src/modules/m_hideoper.cpp index 81b9b888f..9f40d702e 100644 --- a/src/modules/m_hideoper.cpp +++ b/src/modules/m_hideoper.cpp @@ -32,12 +32,13 @@ class HideOper : public SimpleUserModeHandler } }; -class ModuleHideOper : public Module +class ModuleHideOper : public Module, public Whois::LineEventListener { HideOper hm; public: ModuleHideOper() - : hm(this) + : Whois::LineEventListener(this) + , hm(this) { } @@ -46,7 +47,7 @@ class ModuleHideOper : public Module return Version("Provides support for hiding oper status with user mode +H", VF_VENDOR); } - ModResult OnWhoisLine(User* user, User* dest, int &numeric, std::string &text) CXX11_OVERRIDE + ModResult OnWhoisLine(Whois::Context& whois, unsigned int& numeric, std::string& text) CXX11_OVERRIDE { /* Dont display numeric 313 (RPL_WHOISOPER) if they have +H set and the * person doing the WHOIS is not an oper @@ -54,10 +55,10 @@ class ModuleHideOper : public Module if (numeric != 313) return MOD_RES_PASSTHRU; - if (!dest->IsModeSet(hm)) + if (!whois.GetTarget()->IsModeSet(hm)) return MOD_RES_PASSTHRU; - if (!user->HasPrivPermission("users/auspex")) + if (!whois.GetSource()->HasPrivPermission("users/auspex")) return MOD_RES_DENY; return MOD_RES_PASSTHRU; diff --git a/src/modules/m_jumpserver.cpp b/src/modules/m_jumpserver.cpp index 599144448..e9c07f45f 100644 --- a/src/modules/m_jumpserver.cpp +++ b/src/modules/m_jumpserver.cpp @@ -109,9 +109,11 @@ class CommandJumpserver : public Command { /* Redirect everyone but the oper sending the command */ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); - for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i) + for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ) { + // Quitting the user removes it from the list LocalUser* t = *i; + ++i; if (!t->IsOper()) { t->WriteNumeric(RPL_REDIR, "%s %d :Please use this Server/Port instead", parameters[0].c_str(), GetPort(t)); diff --git a/src/modules/m_nationalchars.cpp b/src/modules/m_nationalchars.cpp index f77899ad4..8e74ee3e6 100644 --- a/src/modules/m_nationalchars.cpp +++ b/src/modules/m_nationalchars.cpp @@ -292,10 +292,12 @@ class ModuleNationalChars : public Module return; const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); - for (UserManager::LocalList::const_iterator iter = list.begin(); iter != list.end(); ++iter) + for (UserManager::LocalList::const_iterator iter = list.begin(); iter != list.end(); ) { /* Fix by Brain: Dont quit UID users */ + // Quitting the user removes it from the list User* n = *iter; + ++iter; if (!isdigit(n->nick[0]) && !ServerInstance->IsNick(n->nick)) ServerInstance->Users->QuitUser(n, message); } diff --git a/src/modules/m_services_account.cpp b/src/modules/m_services_account.cpp index 4ad339fcb..a11b05ca3 100644 --- a/src/modules/m_services_account.cpp +++ b/src/modules/m_services_account.cpp @@ -133,7 +133,7 @@ class AccountExtItemImpl : public AccountExtItem } }; -class ModuleServicesAccount : public Module +class ModuleServicesAccount : public Module, public Whois::EventListener { AChannel_R m1; AChannel_M m2; @@ -143,8 +143,10 @@ class ModuleServicesAccount : public Module AccountExtItemImpl accountname; bool checking_ban; public: - ModuleServicesAccount() : m1(this), m2(this), m3(this), m4(this), m5(this), - accountname(this) + ModuleServicesAccount() + : Whois::EventListener(this) + , m1(this), m2(this), m3(this), m4(this), m5(this) + , accountname(this) , checking_ban(false) { } diff --git a/src/modules/m_servprotect.cpp b/src/modules/m_servprotect.cpp index 2ed37b9e4..0445235dc 100644 --- a/src/modules/m_servprotect.cpp +++ b/src/modules/m_servprotect.cpp @@ -42,12 +42,13 @@ class ServProtectMode : public ModeHandler } }; -class ModuleServProtectMode : public Module, public Whois::EventListener +class ModuleServProtectMode : public Module, public Whois::EventListener, public Whois::LineEventListener { ServProtectMode bm; public: ModuleServProtectMode() : Whois::EventListener(this) + , Whois::LineEventListener(this) , bm(this) { } @@ -120,9 +121,9 @@ class ModuleServProtectMode : public Module, public Whois::EventListener return MOD_RES_PASSTHRU; } - ModResult OnWhoisLine(User* src, User* dst, int &numeric, std::string &text) CXX11_OVERRIDE + ModResult OnWhoisLine(Whois::Context& whois, unsigned int& numeric, std::string& text) CXX11_OVERRIDE { - return ((numeric == 319) && dst->IsModeSet(bm)) ? MOD_RES_DENY : MOD_RES_PASSTHRU; + return ((numeric == 319) && whois.GetTarget()->IsModeSet(bm)) ? MOD_RES_DENY : MOD_RES_PASSTHRU; } }; diff --git a/src/modules/m_silence.cpp b/src/modules/m_silence.cpp index 502f947f4..f2ac26fb3 100644 --- a/src/modules/m_silence.cpp +++ b/src/modules/m_silence.cpp @@ -45,8 +45,8 @@ // pair of hostmask and flags typedef std::pair<std::string, int> silenceset; -// deque list of pairs -typedef std::deque<silenceset> silencelist; +// list of pairs +typedef std::vector<silenceset> silencelist; // intmasks for flags static int SILENCE_PRIVATE = 0x0001; /* p private messages */ @@ -212,7 +212,7 @@ class CommandSilence : public Command } if (((pattern & SILENCE_EXCLUDE) > 0)) { - sl->push_front(silenceset(mask,pattern)); + sl->insert(sl->begin(), silenceset(mask, pattern)); } else { @@ -318,7 +318,7 @@ class ModuleSilence : public Module tokens["SILENCE"] = ConvToStr(maxsilence); } - void OnBuildExemptList(MessageType message_type, Channel* chan, User* sender, char status, CUList &exempt_list, const std::string &text) + void BuildExemptList(MessageType message_type, Channel* chan, User* sender, CUList& exempt_list) { int public_silence = (message_type == MSG_PRIVMSG ? SILENCE_CHANNEL : SILENCE_CNOTICE); @@ -344,7 +344,7 @@ class ModuleSilence : public Module else if (target_type == TYPE_CHANNEL) { Channel* chan = (Channel*)dest; - this->OnBuildExemptList(msgtype, chan, user, status, exempt_list, ""); + BuildExemptList(msgtype, chan, user, exempt_list); } return MOD_RES_PASSTHRU; } diff --git a/src/modules/m_spanningtree/nick.cpp b/src/modules/m_spanningtree/nick.cpp index 9496c2874..1d853a2df 100644 --- a/src/modules/m_spanningtree/nick.cpp +++ b/src/modules/m_spanningtree/nick.cpp @@ -47,7 +47,7 @@ CmdResult CommandNick::HandleRemote(RemoteUser* user, std::vector<std::string>& { // 'x' is the already existing user using the same nick as params[0] // 'user' is the user trying to change nick to the in use nick - bool they_change = Utils->DoCollision(x, TreeServer::Get(user), newts, user->ident, user->GetIPString(), user->uuid); + bool they_change = Utils->DoCollision(x, TreeServer::Get(user), newts, user->ident, user->GetIPString(), user->uuid, "NICK"); if (they_change) { // Remote client lost, or both lost, rewrite this nick change as a change to uuid before diff --git a/src/modules/m_spanningtree/nickcollide.cpp b/src/modules/m_spanningtree/nickcollide.cpp index 3401041aa..62e200921 100644 --- a/src/modules/m_spanningtree/nickcollide.cpp +++ b/src/modules/m_spanningtree/nickcollide.cpp @@ -33,7 +33,7 @@ * Sends SAVEs as appropriate and forces nick change of the user 'u' if our side loses or if both lose. * Does not change the nick of the user that is trying to claim the nick of 'u', i.e. the "remote" user. */ -bool SpanningTreeUtilities::DoCollision(User* u, TreeServer* server, time_t remotets, const std::string& remoteident, const std::string& remoteip, const std::string& remoteuid) +bool SpanningTreeUtilities::DoCollision(User* u, TreeServer* server, time_t remotets, const std::string& remoteident, const std::string& remoteip, const std::string& remoteuid, const char* collidecmd) { // At this point we're sure that a collision happened, increment the counter regardless of who wins ServerInstance->stats.Collisions++; @@ -86,6 +86,10 @@ bool SpanningTreeUtilities::DoCollision(User* u, TreeServer* server, time_t remo } } + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Nick collision on \"%s\" caused by %s: %s/%lu/%s@%s %d <-> %s/%lu/%s@%s %d", u->nick.c_str(), collidecmd, + u->uuid.c_str(), (unsigned long)localts, u->ident.c_str(), u->GetIPString().c_str(), bChangeLocal, + remoteuid.c_str(), (unsigned long)remotets, remoteident.c_str(), remoteip.c_str(), bChangeRemote); + /* * Send SAVE and accept the losing client with its UID (as we know the SAVE will * not fail under any circumstances -- UIDs are netwide exclusive). diff --git a/src/modules/m_spanningtree/uid.cpp b/src/modules/m_spanningtree/uid.cpp index 72361af38..a3b804579 100644 --- a/src/modules/m_spanningtree/uid.cpp +++ b/src/modules/m_spanningtree/uid.cpp @@ -59,9 +59,7 @@ CmdResult CommandUID::HandleServer(TreeServer* remoteserver, std::vector<std::st else if (collideswith) { // The user on this side is registered, handle the collision - bool they_change = Utils->DoCollision(collideswith, remoteserver, age_t, params[5], params[6], params[0]); - ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Collision on %s %d", params[2].c_str(), they_change); - + bool they_change = Utils->DoCollision(collideswith, remoteserver, age_t, params[5], params[6], params[0], "UID"); if (they_change) { // The client being introduced needs to change nick to uuid, change the nick in the message before diff --git a/src/modules/m_spanningtree/utils.cpp b/src/modules/m_spanningtree/utils.cpp index 0cd6c76c2..bbda2634d 100644 --- a/src/modules/m_spanningtree/utils.cpp +++ b/src/modules/m_spanningtree/utils.cpp @@ -117,6 +117,7 @@ TreeServer* SpanningTreeUtilities::FindServerID(const std::string &id) SpanningTreeUtilities::SpanningTreeUtilities(ModuleSpanningTree* C) : Creator(C), TreeRoot(NULL) + , PingFreq(60) // XXX: TreeServer constructor reads this and TreeRoot is created before the config is read, so init it to something (value doesn't matter) to avoid a valgrind warning in TimerManager on unload { ServerInstance->Timers.AddTimer(&RefreshTimer); } diff --git a/src/modules/m_spanningtree/utils.h b/src/modules/m_spanningtree/utils.h index 5aa8e925e..84637bf01 100644 --- a/src/modules/m_spanningtree/utils.h +++ b/src/modules/m_spanningtree/utils.h @@ -135,7 +135,7 @@ class SpanningTreeUtilities : public classbase /** Handle nick collision */ - bool DoCollision(User* u, TreeServer* server, time_t remotets, const std::string& remoteident, const std::string& remoteip, const std::string& remoteuid); + bool DoCollision(User* u, TreeServer* server, time_t remotets, const std::string& remoteident, const std::string& remoteip, const std::string& remoteuid, const char* collidecmd); /** Compile a list of servers which contain members of channel c */ |