Merge branch 'insp3' into master.

This commit is contained in:
Sadie Powell 2019-11-13 15:24:45 +00:00
commit 7b68936321
64 changed files with 952 additions and 227 deletions

View File

@ -1,10 +1,15 @@
---
name: Bug report
about: Report a non-security issue with InspIRCd.
---
<!--
---------------------------------------------------
GENERAL SUPPORT INFORMATION
---------------------------------------------------
The GitHub issue tracker is for bug reports and feature requests.
General support can be found at the following locations:
The GitHub issue tracker is for bug reports ONLY. General support can
be found at the following locations:
Docs: https://docs.inspircd.org
IRC: irc.inspircd.org #inspircd

View File

@ -0,0 +1,34 @@
---
name: Feature request
about: Request that a new feature is added to InspIRCd.
---
<!--
---------------------------------------------------
GENERAL SUPPORT INFORMATION
---------------------------------------------------
The GitHub issue tracker is for feature requests ONLY. General support
can be found at the following locations:
Docs: https://docs.inspircd.org
IRC: irc.inspircd.org #inspircd
Example configs:
3.0 (stable) - https://github.com/inspircd/inspircd/tree/insp3/docs/conf
2.0 (old stable) - https://github.com/inspircd/inspircd/tree/insp20/docs/conf
-->
**Description**
<!--
Briefly describe the problem you are having in a few paragraphs.
-->
**Why this would be useful**
<!--
Briefly describe why the feature would be useful.
-->

39
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,39 @@
<!--
Please fill in the template below. Pull requests that do not use this
template will be closed without warning.
-->
## Summary
<!--
Briefly describe what this pull request changes.
-->
## Rationale
<!--
Describe why you have made this change.
-->
## Testing Environment
<!--
Describe the environment in which you have tested this change:
-->
I have tested this pull request on:
**Operating system name and version:** <!-- e.g. Linux 3.11 -->
**Compiler name and version:** <!-- e.g. GCC 4.2.0 -->
## Checks
<!--
Tick the boxes for the checks you have made.
-->
I have ensured that:
- [ ] This pull request does not introduce any incompatible API changes.
- [ ] If ABI changes have been made I have incremented INSPIRCD_VERSION_API.
- [ ] I have documented any features added by this pull request.

22
.github/SECURITY.md vendored Normal file
View File

@ -0,0 +1,22 @@
# Security Policy
## Supported Versions
Currently the v2 (old stable) and v3 (stable) branches are actively receiving security fixes. Support for v2 will end on 2020-06-01.
The v4 branch is still early in development and only receives security fixes when they are synced from the v3 branch.
Version | Supported
------- | ---------
4.x.y | :warning:
3.x.y | :white_check_mark:
2.0.x | :white_check_mark:
1.2.y | :x:
1.1.y | :x:
1.0.y | :x:
## Reporting a Vulnerability
Please do not report security vulnerabilities on GitHub. Instead, get the attention of a developer in our [development IRC channel](https://kiwiirc.com/nextclient/irc.inspircd.org:+6697/#inspircd.dev) at irc.inspircd.org #inspircd.dev and PM them the details.
We will triage your issue as soon as possible and try to release a fixed version within a week of receiving your report.

View File

@ -16,7 +16,7 @@ InspIRCd is supported on on the following platforms:
Alternate platforms and toolchains may also work but are not officially supported by the InspIRCd team. Generally speaking if you are using a reasonably modern UNIX-like system you should be able to build InspIRCd on it.
If you encounter any bugs then [please file an issue](https://github.com/inspircd/inspircd/issues/new).
If you encounter any bugs then [please file an issue](https://github.com/inspircd/inspircd/issues/new/choose).
## Installation

1
configure vendored
View File

@ -323,6 +323,7 @@ if (prompt_bool $interactive, $question, 0) {
$config{MANUAL_DIR} = prompt_dir $interactive, 'In what directory are manual pages to be placed?', $config{MANUAL_DIR};
$config{MODULE_DIR} = prompt_dir $interactive, 'In what directory are modules to be placed?', $config{MODULE_DIR};
$config{SCRIPT_DIR} = prompt_dir $interactive, 'In what directory are scripts to be placed?', $config{SCRIPT_DIR};
$config{EXAMPLE_DIR} = $config{CONFIG_DIR} . '/examples';
}
# Configure module settings.

View File

@ -1000,6 +1000,7 @@ using their cloak when they quit.">
nonick Channel mode +N
nonotice Channel mode +T
regmoderated Channel mode +M
repeat Channel mode +E
stripcolor Channel mode +S
topiclock Channel mode +t

View File

@ -630,7 +630,7 @@
# the throttling when the server just booted.
#
#<connflood period="30" maxconns="3" timeout="30"
# quitmsg="Throttled" bootwait="10">
# quitmsg="Throttled" bootwait="2m">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
# Custom prefixes: Allows for channel prefixes to be configured.

View File

@ -3,7 +3,10 @@
# https://www.irccloud.com/networks for more information on supporting
# IRCloud on your network.
<connect name="IRCCloud" parent="main" globalmax="100" localmax="100">
<connect name="IRCCloud"
parent="main"
globalmax="100"
localmax="100">
<connect name="IRCCloud-Brockwell" parent="IRCCloud" allow="192.184.10.118">
<connect name="IRCCloud-Charlton" parent="IRCCloud" allow="192.184.9.112">

View File

@ -1,8 +1,19 @@
# This file contains connect classes which are used by KiwiIRC.com users.
# See https://kiwiirc.com for more information on KiwiIRC.com.
<connect name="KiwiIRC.com" parent="main" globalmax="100" localmax="100" registered="no">
<connect name="KiwiIRC.com"
parent="main"
globalmax="100"
localmax="100"
registered="no"
resolvehostnames="no"
usednsbl="no"
useident="no">
<connect name="KiwiIRC.com-1" parent="KiwiIRC.com" allow="107.161.19.10">
<connect name="KiwiIRC.com-2" parent="KiwiIRC.com" allow="107.161.19.53">
<connect name="KiwiIRC.com-1" parent="KiwiIRC.com" allow="107.161.19.53">
<connect name="KiwiIRC.com-2" parent="KiwiIRC.com" allow="107.161.19.109">
<connect name="KiwiIRC.com-3" parent="KiwiIRC.com" allow="109.169.31.4">
<exception host="*@107.161.19.53" reason="KiwiIRC.com WebIRC Gateway">
<exception host="*@107.161.19.109" reason="KiwiIRC.com WebIRC Gateway">
<exception host="*@107.169.31.4" reason="KiwiIRC.com WebIRC Gateway">

View File

@ -57,7 +57,23 @@ class Events::ModuleEventProvider : public ServiceProvider, private dynamic_refe
*/
const SubscriberList& GetSubscribers() const { return prov->subscribers; }
friend class ModuleEventListener;
/** Subscribes a listener to this event.
* @param subscriber The listener to subscribe.
*/
void Subscribe(ModuleEventListener* subscriber)
{
subscribers.insert(subscriber);
OnSubscribe(subscriber);
}
/** Unsubscribes a listener from this event.
* @param subscriber The listener to unsubscribe.
*/
void Unsubscribe(ModuleEventListener* subscriber)
{
subscribers.erase(subscriber);
OnUnsubscribe(subscriber);
}
private:
void OnCapture() override
@ -67,6 +83,16 @@ class Events::ModuleEventProvider : public ServiceProvider, private dynamic_refe
subscribers.clear();
}
/** Called when a listener subscribes to this event.
* @param subscriber The listener which subscribed.
*/
virtual void OnSubscribe(ModuleEventListener* subscriber) { }
/** Called when a listener unsubscribes from this event.
* @param subscriber The listener which unsubscribed.
*/
virtual void OnUnsubscribe(ModuleEventListener* subscriber) { }
/** Reference to the active provider for this event. In case multiple event providers
* exist for the same event, only one of them contains the list of subscribers.
* To handle the case when we are not the ones with the list, we get it from the provider
@ -95,7 +121,7 @@ class Events::ModuleEventListener : private dynamic_reference_base::CaptureHook
*/
void OnCapture() override
{
prov->subscribers.insert(this);
prov->Subscribe(this);
}
public:
@ -119,7 +145,7 @@ class Events::ModuleEventListener : private dynamic_reference_base::CaptureHook
~ModuleEventListener()
{
if (prov)
prov->subscribers.erase(this);
prov->Unsubscribe(this);
}
/** Retrieves the module which created this listener. */

View File

@ -119,7 +119,9 @@ class CoreExport ExtensionItem : public ServiceProvider, public usecountbase
* a flags variable, and each module defining bits within the flag as 'theirs' as it is less prone to conflict and
* supports arbitary data storage).
*/
class CoreExport Extensible : public classbase
class CoreExport Extensible
: public classbase
, public Serializable
{
public:
typedef insp::flat_map<reference<ExtensionItem>, void*> ExtensibleStore;
@ -151,6 +153,12 @@ class CoreExport Extensible : public classbase
* Free all extension items attached to this Extensible
*/
void FreeAllExtItems();
/** @copydoc Serializable::Deserialize. */
bool Deserialize(Data& data) override;
/** @copydoc Serializable::Deserialize. */
bool Serialize(Serializable::Data& data) override;
};
class CoreExport ExtensionManager

View File

@ -64,6 +64,7 @@ CoreExport extern InspIRCd* ServerInstance;
#include "dynref.h"
#include "consolecolors.h"
#include "cull_list.h"
#include "serialize.h"
#include "extensible.h"
#include "fileutils.h"
#include "ctables.h"

View File

@ -120,6 +120,9 @@ class CoreExport ListModeBase : public ModeHandler
*/
ListModeBase(Module* Creator, const std::string& Name, char modechar, const std::string& eolstr, unsigned int lnum, unsigned int eolnum, bool autotidy);
/** Determines whether some channels have longer lists than others. */
bool HasVariableLength() const { return chanlimits.size() > 1; }
/** Get limit of this mode on a channel
* @param channel The channel to inspect
* @return Maximum number of modes of this type that can be placed on the given channel

View File

@ -217,7 +217,7 @@ enum Implementation
I_OnUserConnect, I_OnUserPreQuit, I_OnUserQuit, I_OnUserDisconnect, I_OnUserJoin, I_OnUserPart,
I_OnSendSnotice, I_OnUserPreJoin, I_OnUserPreKick, I_OnUserKick, I_OnOper,
I_OnUserPreInvite, I_OnUserInvite, I_OnUserPreMessage, I_OnUserPreNick,
I_OnUserPostMessage, I_OnUserMessageBlocked, I_OnMode,
I_OnUserPostMessage, I_OnUserMessageBlocked, I_OnMode, I_OnShutdown,
I_OnDecodeMetaData, I_OnAcceptConnection, I_OnUserInit, I_OnUserPostInit,
I_OnChangeHost, I_OnChangeRealName, I_OnAddLine, I_OnDelLine, I_OnExpireLine,
I_OnUserPostNick, I_OnPreMode, I_On005Numeric, I_OnKill, I_OnLoadModule,
@ -950,6 +950,12 @@ class CoreExport Module : public classbase, public usecountbase
* disconnect the user, or MOD_RES_PASSTHRU to let another module handle the event.
*/
virtual ModResult OnConnectionFail(LocalUser* user, BufferedSocketError error);
/** Called before a server shuts down.
* @param reason The reason the server is shutting down.
* @param restart Whether the server is restarting.
*/
virtual void OnShutdown(const std::string& reason);
};
/** ModuleManager takes care of all things module-related

View File

@ -146,6 +146,7 @@ namespace DNS
virtual void Process(Request* req) = 0;
virtual void RemoveRequest(Request* req) = 0;
virtual std::string GetErrorStr(Error) = 0;
virtual std::string GetTypeStr(QueryType) = 0;
};
/** A DNS query.

View File

@ -56,15 +56,21 @@ class ServerProtocol::LinkEventListener
{
}
/** Fired when a server finishes burst
* @param server Server that recently linked and finished burst
/** Fired when a server has linked to the network.
* @param server Server that recently linked.
*/
virtual void OnServerLink(const Server* server) { }
/** Fired when a server splits
* @param server Server that split
*/
virtual void OnServerSplit(const Server* server) { }
/** Fired when a server has finished bursting.
* @param server Server that recently finished bursting.
*/
virtual void OnServerBurst(const Server* server) { }
/** Fired when a server splits
* @param server Server that split
* @param error Whether the server split because of an error.
*/
virtual void OnServerSplit(const Server* server, bool error) { }
};
class ServerProtocol::MessageEventListener

View File

@ -228,12 +228,19 @@ class SQL::Query : public classbase
*/
class SQL::Provider : public DataProvider
{
private:
/** The name of the database tag in the config. */
const std::string dbid;
public:
Provider(Module* Creator, const std::string& Name)
: DataProvider(Creator, Name)
: DataProvider(Creator, "SQL/" + Name)
{
}
/** Retrieves the name of the database tag in the config. */
const std::string& GetId() const { return dbid; }
/** Submit an asynchronous SQL query.
* @param callback The result reporting point
* @param query The hardcoded query string. If you have parameters to substitute, see below.

117
include/serialize.h Normal file
View File

@ -0,0 +1,117 @@
/*
* InspIRCd -- Internet Relay Chat Daemon
*
* Copyright (C) 2019 Peter Powell <petpow@saberuk.com>
*
* 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
* License as published by the Free Software Foundation, version 2.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
/** Base class for serializable elements. */
class CoreExport Serializable
{
protected:
Serializable() { }
public:
/** Encapsulates a chunk of serialised data. */
class CoreExport Data
{
public:
/** Maps keys to serialised data. */
typedef insp::flat_map<std::string, Data> ChildMap;
/** Maps keys to simple values. */
typedef insp::flat_map<std::string, std::string> EntryMap;
private:
/** A mapping of keys to serialised data. */
ChildMap children;
/** A mapping of keys to values. */
EntryMap entries;
public:
/** Retrieves the child elements. */
const ChildMap& GetChildren() const { return children; }
ChildMap& GetChildren() { return children; }
/** Retrieves the key/value map. */
const EntryMap& GetEntries() const { return entries; }
EntryMap& GetEntries() { return entries; }
/** Loads the serialised data with the specified key.
* @param key The key by which this serialised data is identified.
* @param out The location to store the serialised data for this key.
*/
Data& Load(const std::string& key, Data& out);
/** Loads the value with the specified key.
* @param key The key by which this data is identified.
* @param out The location to store the value for this keu
*/
Data& Load(const std::string& key, std::string& out);
/** Loads the value with the specified key. The value will be converted to the specified type.
* @param key The key by which this data is identified.
* @param out The location to store the value for this key.
*/
template <typename T>
Data& Load(const std::string& key, T& out)
{
// Attempt to load as a string.
std::string str;
Load(key, str);
std::stringstream ss(str);
ss >> out;
return *this;
}
/** Stores the serialised data against the specified key.
* @param key The key by which this serialised data should be stored against.
* @param out The serialised data to store.
*/
Data& Store(const std::string& key, const Data& value);
/** Stores the value against the specified key.
* @param key The key by which this value should be stored against.
* @param out The value to store.
*/
Data& Store(const std::string& key, const std::string& value);
/** Stores the value against the specified key. The value will be converted to a string using ConvToStr.
* @param key The key by which this value should be stored against.
* @param out The value to store.
*/
template <typename T>
Data& Store(const std::string& key, const T& value)
{
return Store(key, ConvToStr(value));
}
};
/** Deserializes the specified Data instance into this object.
* @param data The Data object to deserialize from.
* @return True if the deserialisation succeeded; otherwise, false.
*/
virtual bool Deserialize(Data& data) = 0;
/** Serializes the this object into the specified Data obect.
* @param data The Data object to serialize to.
* @return True if the serialisation succeeded; otherwise, false.
*/
virtual bool Serialize(Data& data) = 0;
};

View File

@ -22,6 +22,9 @@
class CoreExport Server : public classbase
{
protected:
/** The unique identifier for this server. */
const std::string id;
/** The name of this server
*/
const std::string name;
@ -44,8 +47,17 @@ class CoreExport Server : public classbase
friend class ConfigReaderThread;
public:
Server(const std::string& srvname, const std::string& srvdesc)
: name(srvname), description(srvdesc), uline(false), silentuline(false) { }
Server(const std::string& srvid, const std::string& srvname, const std::string& srvdesc)
: id(srvid)
, name(srvname)
, description(srvdesc)
, uline(false)
, silentuline(false)
{
}
/** Retrieves the unique identifier for this server (e.g. 36C). */
const std::string& GetId() const { return id; }
/**
* Returns the name of this server

View File

@ -592,6 +592,12 @@ class CoreExport User : public Extensible
*/
virtual ~User();
CullResult cull() override;
/** @copydoc Serializable::Deserialize. */
bool Deserialize(Data& data) override;
/** @copydoc Serializable::Deserialize. */
bool Serialize(Serializable::Data& data) override;
};
class CoreExport UserIOHandler : public StreamSocket
@ -645,6 +651,8 @@ class CoreExport LocalUser : public User, public insp::intrusive_list_node<Local
public:
LocalUser(int fd, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server);
LocalUser(int fd, const std::string& uuid, Serializable::Data& data);
CullResult cull() override;
UserIOHandler eh;
@ -788,6 +796,12 @@ class CoreExport LocalUser : public User, public insp::intrusive_list_node<Local
* @param msg Message to send.
*/
void Send(ClientProtocol::EventProvider& protoevprov, ClientProtocol::Message& msg);
/** @copydoc Serializable::Deserialize. */
bool Deserialize(Data& data) override;
/** @copydoc Serializable::Deserialize. */
bool Serialize(Serializable::Data& data) override;
};
class RemoteUser : public User
@ -801,13 +815,14 @@ class RemoteUser : public User
class CoreExport FakeUser : public User
{
public:
FakeUser(const std::string& uid, Server* srv) : User(uid, srv, USERTYPE_SERVER)
FakeUser(const std::string& uid, Server* srv)
: User(uid, srv, USERTYPE_SERVER)
{
nick = srv->GetName();
}
FakeUser(const std::string& uid, const std::string& sname, const std::string& sdesc)
: User(uid, new Server(sname, sdesc), USERTYPE_SERVER)
: User(uid, new Server(uid, sname, sdesc), USERTYPE_SERVER)
{
nick = sname;
}
@ -821,17 +836,17 @@ class CoreExport FakeUser : public User
/** Is a local user */
inline LocalUser* IS_LOCAL(User* u)
{
return u->usertype == USERTYPE_LOCAL ? static_cast<LocalUser*>(u) : NULL;
return (u != NULL && u->usertype == USERTYPE_LOCAL) ? static_cast<LocalUser*>(u) : NULL;
}
/** Is a remote user */
inline RemoteUser* IS_REMOTE(User* u)
{
return u->usertype == USERTYPE_REMOTE ? static_cast<RemoteUser*>(u) : NULL;
return (u != NULL && u->usertype == USERTYPE_REMOTE) ? static_cast<RemoteUser*>(u) : NULL;
}
/** Is a server fakeuser */
inline FakeUser* IS_SERVER(User* u)
{
return u->usertype == USERTYPE_SERVER ? static_cast<FakeUser*>(u) : NULL;
return (u != NULL && u->usertype == USERTYPE_SERVER) ? static_cast<FakeUser*>(u) : NULL;
}
inline bool User::IsModeSet(const ModeHandler* mh) const

View File

@ -20,6 +20,7 @@
BEGIN {
push @INC, $ENV{SOURCEPATH};
require 5.10.0;
unless (-f 'configure') {
print "Error: $0 must be run from the main source directory!\n";
@ -32,6 +33,8 @@ use warnings FATAL => qw(all);
use File::Basename qw(basename);
use make::common;
use constant {
BUILDPATH => $ENV{BUILDPATH},
SOURCEPATH => $ENV{SOURCEPATH}
@ -50,7 +53,7 @@ run;
exit 0;
sub run() {
mkdir BUILDPATH;
create_directory(BUILDPATH, 0770) or die "Could not create build directory: $!";
chdir BUILDPATH or die "Could not open build directory: $!";
unlink 'include';
symlink "${\SOURCEPATH}/include", 'include';

View File

@ -32,7 +32,7 @@
CXX = @CXX@ -std=c++14
COMPILER = @COMPILER_NAME@
SYSTEM = @SYSTEM_NAME@
BUILDPATH ?= $(dir $(realpath $(firstword $(MAKEFILE_LIST))))/build
BUILDPATH ?= $(dir $(realpath $(firstword $(MAKEFILE_LIST))))/build/@COMPILER_NAME@-@COMPILER_VERSION@
SOCKETENGINE = @SOCKETENGINE@
CORECXXFLAGS = -fPIC -fvisibility=hidden -fvisibility-inlines-hidden -pipe -Iinclude -Wall -Wextra -Wfatal-errors -Wno-unused-parameter -Wshadow
LDLIBS = -lstdc++

View File

@ -202,16 +202,22 @@ class CoreModChannel : public Module, public CheckExemption::EventListener
{
tokens["KEYLEN"] = ConvToStr(ModeChannelKey::maxkeylen);
// Build a map of limits to their mode character.
insp::flat_map<int, std::string> limits;
std::string vlist;
const ModeParser::ListModeList& listmodes = ServerInstance->Modes.GetListModes();
for (ModeParser::ListModeList::const_iterator iter = listmodes.begin(); iter != listmodes.end(); ++iter)
{
const unsigned int limit = (*iter)->GetLowerLimit();
limits[limit].push_back((*iter)->GetModeChar());
}
ListModeBase* lm = *iter;
const unsigned int limit = lm->GetLowerLimit();
limits[limit].push_back(lm->GetModeChar());
if (lm->HasVariableLength())
vlist.push_back(lm->GetModeChar());
}
if (!vlist.empty())
tokens["VLIST"] = vlist;
// Generate the MAXLIST token from the limits map.
std::string& buffer = tokens["MAXLIST"];
for (insp::flat_map<int, std::string>::const_iterator iter = limits.begin(); iter != limits.end(); ++iter)
{

View File

@ -538,6 +538,25 @@ class MyManager : public Manager, public Timer, public EventHandler
}
}
std::string GetTypeStr(QueryType qt) override
{
switch (qt)
{
case QUERY_A:
return "A";
case QUERY_AAAA:
return "AAAA";
case QUERY_CNAME:
return "CNAME";
case QUERY_PTR:
return "PTR";
case QUERY_TXT:
return "TXT";
default:
return "UNKNOWN";
}
}
void OnEventHandlerError(int errcode) override
{
ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "UDP socket got an error event");

View File

@ -23,19 +23,26 @@
namespace
{
IntExtItem* dl;
StringExtItem* ph;
}
/** Derived from Resolver, and performs user forward/reverse lookups.
*/
class UserResolver : public DNS::Request
{
private:
/** UUID we are looking up */
const std::string uuid;
/** True if the lookup is forward, false if is a reverse lookup
*/
const bool fwd;
/** Handles errors which happen during DNS resolution. */
static void HandleError(LocalUser* user, const std::string& message)
{
user->WriteNotice("*** " + message + "; using your IP address (" + user->GetIPString() + ") instead.");
bool display_is_real = user->GetDisplayedHost() == user->GetRealHost();
user->ChangeRealHost(user->GetIPString(), display_is_real);
dl->unset(user);
}
public:
/** Create a resolver.
@ -48,7 +55,6 @@ class UserResolver : public DNS::Request
UserResolver(DNS::Manager* mgr, Module* me, LocalUser* user, const std::string& to_resolve, DNS::QueryType qt)
: DNS::Request(mgr, me, to_resolve, qt)
, uuid(user->uuid)
, fwd(qt == DNS::QUERY_A || qt == DNS::QUERY_AAAA)
{
}
@ -58,7 +64,7 @@ class UserResolver : public DNS::Request
*/
void OnLookupComplete(const DNS::Query* r) override
{
LocalUser* bound_user = (LocalUser*)ServerInstance->FindUUID(uuid);
LocalUser* bound_user = IS_LOCAL(ServerInstance->FindUUID(uuid));
if (!bound_user)
{
ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "Resolution finished for user '%s' who is gone", uuid.c_str());
@ -68,17 +74,17 @@ class UserResolver : public DNS::Request
const DNS::ResourceRecord* ans_record = r->FindAnswerOfType(this->question.type);
if (ans_record == NULL)
{
OnError(r);
HandleError(bound_user, "Could not resolve your hostname: No " + this->manager->GetTypeStr(this->question.type) + " records found");
return;
}
ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "DNS result for %s: '%s' -> '%s'", uuid.c_str(), ans_record->name.c_str(), ans_record->rdata.c_str());
ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "DNS %s result for %s: '%s' -> '%s'%s",
this->manager->GetTypeStr(question.type).c_str(), uuid.c_str(),
ans_record->name.c_str(), ans_record->rdata.c_str(),
r->cached ? " (cached)" : "");
if (!fwd)
if (this->question.type == DNS::QUERY_PTR)
{
// first half of resolution is done. We now need to verify that the host matches.
ph->set(bound_user, ans_record->rdata);
UserResolver* res_forward;
if (bound_user->client_sa.family() == AF_INET6)
{
@ -99,11 +105,10 @@ class UserResolver : public DNS::Request
delete res_forward;
ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "Error in resolver: " + e.GetReason());
bound_user->WriteNotice("*** There was an internal error resolving your host, using your IP address (" + bound_user->GetIPString() + ") instead.");
dl->set(bound_user, 0);
HandleError(bound_user, "There was an internal error resolving your host");
}
}
else
else if (this->question.type == DNS::QUERY_A || this->question.type == DNS::QUERY_AAAA)
{
/* Both lookups completed */
@ -126,37 +131,15 @@ class UserResolver : public DNS::Request
}
}
dl->set(bound_user, 0);
if (rev_match)
{
std::string* hostname = ph->get(bound_user);
if (hostname == NULL)
{
ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "ERROR: User has no hostname attached when doing a forward lookup");
bound_user->WriteNotice("*** There was an internal error resolving your host, using your IP address (" + bound_user->GetIPString() + ") instead.");
return;
}
else if (hostname->length() <= ServerInstance->Config->Limits.MaxHost)
{
/* Hostnames starting with : are not a good thing (tm) */
if ((*hostname)[0] == ':')
hostname->insert(0, "0");
bound_user->WriteNotice("*** Found your hostname (" + *hostname + (r->cached ? ") -- cached" : ")"));
bound_user->ChangeRealHost(hostname->substr(0, ServerInstance->Config->Limits.MaxHost), true);
}
else
{
bound_user->WriteNotice("*** Your hostname is longer than the maximum of " + ConvToStr(ServerInstance->Config->Limits.MaxHost) + " characters, using your IP address (" + bound_user->GetIPString() + ") instead.");
}
ph->unset(bound_user);
bound_user->WriteNotice("*** Found your hostname (" + this->question.name + (r->cached ? ") -- cached" : ")"));
bound_user->ChangeRealHost(this->question.name, true);
dl->unset(bound_user);
}
else
{
bound_user->WriteNotice("*** Your hostname does not match up with your IP address. Sorry, using your IP address (" + bound_user->GetIPString() + ") instead.");
HandleError(bound_user, "Your hostname does not match up with your IP address");
}
}
}
@ -166,29 +149,24 @@ class UserResolver : public DNS::Request
*/
void OnError(const DNS::Query* query) override
{
LocalUser* bound_user = (LocalUser*)ServerInstance->FindUUID(uuid);
LocalUser* bound_user = IS_LOCAL(ServerInstance->FindUUID(uuid));
if (bound_user)
{
bound_user->WriteNotice("*** Could not resolve your hostname: " + this->manager->GetErrorStr(query->error) + "; using your IP address (" + bound_user->GetIPString() + ") instead.");
dl->set(bound_user, 0);
}
HandleError(bound_user, "Could not resolve your hostname: " + this->manager->GetErrorStr(query->error));
}
};
class ModuleHostnameLookup : public Module
{
private:
IntExtItem dnsLookup;
StringExtItem ptrHosts;
dynamic_reference<DNS::Manager> DNS;
public:
ModuleHostnameLookup()
: dnsLookup(this, "dnsLookup", ExtensionItem::EXT_USER)
, ptrHosts(this, "ptrHosts", ExtensionItem::EXT_USER)
, DNS(this, "DNS")
{
dl = &dnsLookup;
ph = &ptrHosts;
}
void OnSetUserIP(LocalUser* user) override

View File

@ -93,8 +93,11 @@ void InspIRCd::Cleanup()
}
ports.clear();
// Disconnect all local users
// Tell modules that we're shutting down.
const std::string quitmsg = "Server shutting down";
FOREACH_MOD(OnShutdown, (quitmsg));
// Disconnect all local users
const UserManager::LocalList& list = Users.GetLocalUsers();
while (!list.empty())
ServerInstance->Users.QuitUser(list.front(), quitmsg);

View File

@ -141,6 +141,7 @@ void Module::OnServiceAdd(ServiceProvider&) { DetachEvent(I_OnServiceAdd); }
void Module::OnServiceDel(ServiceProvider&) { DetachEvent(I_OnServiceDel); }
ModResult Module::OnUserWrite(LocalUser*, ClientProtocol::Message&) { DetachEvent(I_OnUserWrite); return MOD_RES_PASSTHRU; }
ModResult Module::OnConnectionFail(LocalUser*, BufferedSocketError) { DetachEvent(I_OnConnectionFail); return MOD_RES_PASSTHRU; }
void Module::OnShutdown(const std::string& reason) { DetachEvent(I_OnShutdown); }
ServiceProvider::ServiceProvider(Module* Creator, const std::string& Name, ServiceType Type)
: creator(Creator), name(Name), service(Type)

View File

@ -247,6 +247,17 @@ class LDAPService : public LDAPProvider, public SocketThread
Connect();
}
int SetOption(int option, const void* value)
{
int ret = ldap_set_option(this->con, option, value);
if (ret != LDAP_OPT_SUCCESS)
{
ldap_unbind_ext(this->con, NULL, NULL);
this->con = NULL;
}
return ret;
}
void QueueRequest(LDAPRequest* r)
{
this->LockQueue();
@ -318,22 +329,14 @@ class LDAPService : public LDAPProvider, public SocketThread
throw LDAPException("Unable to connect to LDAP service " + this->name + ": " + ldap_err2string(i));
const int version = LDAP_VERSION3;
i = ldap_set_option(this->con, LDAP_OPT_PROTOCOL_VERSION, &version);
i = SetOption(LDAP_OPT_PROTOCOL_VERSION, &version);
if (i != LDAP_OPT_SUCCESS)
{
ldap_unbind_ext(this->con, NULL, NULL);
this->con = NULL;
throw LDAPException("Unable to set protocol version for " + this->name + ": " + ldap_err2string(i));
}
const struct timeval tv = { 0, 0 };
i = ldap_set_option(this->con, LDAP_OPT_NETWORK_TIMEOUT, &tv);
i = SetOption(LDAP_OPT_NETWORK_TIMEOUT, &tv);
if (i != LDAP_OPT_SUCCESS)
{
ldap_unbind_ext(this->con, NULL, NULL);
this->con = NULL;
throw LDAPException("Unable to set timeout for " + this->name + ": " + ldap_err2string(i));
}
}
void BindAsManager(LDAPInterface* i) override

View File

@ -277,8 +277,10 @@ class SQLConnection : public SQL::Provider
std::mutex lock;
// This constructor creates an SQLConnection object with the given credentials, but does not connect yet.
SQLConnection(Module* p, ConfigTag* tag) : SQL::Provider(p, "SQL/" + tag->getString("id")),
config(tag), connection(NULL)
SQLConnection(Module* p, ConfigTag* tag)
: SQL::Provider(p, tag->getString("id"))
, config(tag)
, connection(NULL)
{
}
@ -291,28 +293,43 @@ class SQLConnection : public SQL::Provider
// true upon success.
bool Connect()
{
unsigned int timeout = 1;
connection = mysql_init(connection);
mysql_options(connection,MYSQL_OPT_CONNECT_TIMEOUT,(char*)&timeout);
std::string host = config->getString("host");
std::string user = config->getString("user");
std::string pass = config->getString("pass");
std::string dbname = config->getString("name");
unsigned int port = config->getUInt("port", 3306);
bool rv = mysql_real_connect(connection, host.c_str(), user.c_str(), pass.c_str(), dbname.c_str(), port, NULL, 0);
if (!rv)
return rv;
// Enable character set settings
std::string charset = config->getString("charset");
if ((!charset.empty()) && (mysql_set_character_set(connection, charset.c_str())))
ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "WARNING: Could not set character set to \"%s\"", charset.c_str());
// Set the connection timeout.
unsigned int timeout = config->getDuration("timeout", 5, 1, 30);
mysql_options(connection, MYSQL_OPT_CONNECT_TIMEOUT, &timeout);
std::string initquery;
if (config->readString("initialquery", initquery))
// Attempt to connect to the database.
const std::string host = config->getString("host");
const std::string user = config->getString("user");
const std::string pass = config->getString("pass");
const std::string dbname = config->getString("name");
unsigned int port = config->getUInt("port", 3306, 1, 65535);
if (!mysql_real_connect(connection, host.c_str(), user.c_str(), pass.c_str(), dbname.c_str(), port, NULL, CLIENT_IGNORE_SIGPIPE))
{
mysql_query(connection,initquery.c_str());
ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Unable to connect to the %s MySQL server: %s",
GetId().c_str(), mysql_error(connection));
return false;
}
// Set the default character set.
const std::string charset = config->getString("charset");
if (!charset.empty() && mysql_set_character_set(connection, charset.c_str()))
{
ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Could not set character set for %s to \"%s\": %s",
GetId().c_str(), charset.c_str(), mysql_error(connection));
return false;
}
// Execute the initial SQL query.
const std::string initialquery = config->getString("initialquery");
if (!initialquery.empty() && mysql_real_query(connection, initialquery.data(), initialquery.length()))
{
ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Could not execute initial query \"%s\" for %s: %s",
initialquery.c_str(), name.c_str(), mysql_error(connection));
return false;
}
return true;
}

View File

@ -176,7 +176,11 @@ class SQLConn : public SQL::Provider, public EventHandler
QueueItem qinprog; /* If there is currently a query in progress */
SQLConn(Module* Creator, ConfigTag* tag)
: SQL::Provider(Creator, "SQL/" + tag->getString("id")), conf(tag), sql(NULL), status(CWRITE), qinprog(NULL, "")
: SQL::Provider(Creator, tag->getString("id"))
, conf(tag)
, sql(NULL)
, status(CWRITE)
, qinprog(NULL, "")
{
if (!DoConnect())
{

View File

@ -97,7 +97,9 @@ class SQLConn : public SQL::Provider
reference<ConfigTag> config;
public:
SQLConn(Module* Parent, ConfigTag* tag) : SQL::Provider(Parent, "SQL/" + tag->getString("id")), config(tag)
SQLConn(Module* Parent, ConfigTag* tag)
: SQL::Provider(Parent, tag->getString("id"))
, config(tag)
{
std::string host = tag->getString("hostname");
if (sqlite3_open_v2(host.c_str(), &conn, SQLITE_OPEN_READWRITE, 0) != SQLITE_OK)

View File

@ -1193,7 +1193,7 @@ class ModuleSSLGnuTLS : public Module
void OnModuleRehash(User* user, const std::string &param) override
{
if(param != "ssl")
if (!irc::equals(param, "ssl"))
return;
try

View File

@ -926,7 +926,7 @@ class ModuleSSLmbedTLS : public Module
void OnModuleRehash(User* user, const std::string &param) override
{
if (param != "ssl")
if (!irc::equals(param, "ssl"))
return;
try

View File

@ -980,7 +980,7 @@ class ModuleSSLOpenSSL : public Module
void OnModuleRehash(User* user, const std::string &param) override
{
if (param != "ssl")
if (!irc::equals(param, "ssl"))
return;
try

View File

@ -375,12 +375,14 @@ class ModuleCloaking : public Module
{
u->SetMode(cu, false);
if (!IS_LOCAL(u))
LocalUser* luser = IS_LOCAL(u);
if (!luser)
return;
Modes::ChangeList modechangelist;
modechangelist.push_remove(&cu);
ClientProtocol::Events::Mode modeevent(ServerInstance->FakeClient, NULL, u, modechangelist);
static_cast<LocalUser*>(u)->Send(modeevent);
luser->Send(modeevent);
}
cu.active = false;
}

View File

@ -19,8 +19,11 @@
#include "inspircd.h"
#include "xline.h"
#include "modules/webirc.h"
class ModuleConnectBan : public Module
class ModuleConnectBan
: public Module
, public WebIRC::EventListener
{
typedef std::map<irc::sockets::cidr_mask, unsigned int> ConnectMap;
ConnectMap connects;
@ -30,7 +33,33 @@ class ModuleConnectBan : public Module
unsigned int ipv6_cidr;
std::string banmessage;
unsigned char GetRange(LocalUser* user)
{
int family = user->client_sa.family();
switch (family)
{
case AF_INET:
return ipv4_cidr;
case AF_INET6:
return ipv6_cidr;
case AF_UNIX:
// Ranges for UNIX sockets are ignored entirely.
return 0;
}
// If we have reached this point then we have encountered a bug.
ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "BUG: ModuleConnectBan::GetRange(): socket type %d is unknown!", family);
return 0;
}
public:
ModuleConnectBan()
: WebIRC::EventListener(this)
{
}
Version GetVersion() override
{
return Version("Throttles the connections of IP ranges who try to connect flood", VF_VENDOR);
@ -47,24 +76,26 @@ class ModuleConnectBan : public Module
banmessage = tag->getString("banmessage", "Your IP range has been attempting to connect too many times in too short a duration. Wait a while, and you will be able to connect.");
}
void OnWebIRCAuth(LocalUser* user, const WebIRC::FlagMap* flags) override
{
if (user->exempt)
return;
// HACK: Lower the connection attempts for the gateway IP address. The user
// will be rechecked for connect spamming shortly after when their IP address
// is changed and OnSetUserIP is called.
irc::sockets::cidr_mask mask(user->client_sa, GetRange(user));
ConnectMap::iterator iter = connects.find(mask);
if (iter != connects.end() && iter->second)
iter->second--;
}
void OnSetUserIP(LocalUser* u) override
{
if (u->exempt)
return;
unsigned char range = 32;
switch (u->client_sa.family())
{
case AF_INET6:
range = ipv6_cidr;
break;
case AF_INET:
range = ipv4_cidr;
break;
}
irc::sockets::cidr_mask mask(u->client_sa, range);
irc::sockets::cidr_mask mask(u->client_sa, GetRange(u));
ConnectMap::iterator i = connects.find(mask);
if (i != connects.end())

View File

@ -54,7 +54,7 @@ public:
quitmsg = tag->getString("quitmsg");
/* seconds to wait when the server just booted */
boot_wait = tag->getDuration("bootwait", 10);
boot_wait = tag->getDuration("bootwait", 60*2);
first = ServerInstance->Time();
}

View File

@ -47,15 +47,21 @@ class DNSBLConfEntry : public refcountbase
*/
class DNSBLResolver : public DNS::Request
{
private:
irc::sockets::sockaddrs theirsa;
std::string theiruid;
StringExtItem& nameExt;
IntExtItem& countExt;
reference<DNSBLConfEntry> ConfEntry;
public:
DNSBLResolver(DNS::Manager *mgr, Module *me, StringExtItem& match, IntExtItem& ctr, const std::string &hostname, LocalUser* u, reference<DNSBLConfEntry> conf)
: DNS::Request(mgr, me, hostname, DNS::QUERY_A, true), theiruid(u->uuid), nameExt(match), countExt(ctr), ConfEntry(conf)
: DNS::Request(mgr, me, hostname, DNS::QUERY_A, true)
, theirsa(u->client_sa)
, theiruid(u->uuid)
, nameExt(match)
, countExt(ctr)
, ConfEntry(conf)
{
}
@ -63,8 +69,8 @@ class DNSBLResolver : public DNS::Request
void OnLookupComplete(const DNS::Query *r) override
{
/* Check the user still exists */
LocalUser* them = (LocalUser*)ServerInstance->FindUUID(theiruid);
if (!them)
LocalUser* them = IS_LOCAL(ServerInstance->FindUUID(theiruid));
if (!them || them->client_sa != theirsa)
return;
const DNS::ResourceRecord* const ans_record = r->FindAnswerOfType(DNS::QUERY_A);
@ -209,8 +215,8 @@ class DNSBLResolver : public DNS::Request
void OnError(const DNS::Query *q) override
{
LocalUser* them = (LocalUser*)ServerInstance->FindUUID(theiruid);
if (!them)
LocalUser* them = IS_LOCAL(ServerInstance->FindUUID(theiruid));
if (!them || them->client_sa != theirsa)
return;
int i = countExt.get(them);

View File

@ -130,6 +130,9 @@ class ModeHook : public ClientProtocol::EventHook
if (!chan)
return MOD_RES_PASSTHRU;
if (user->HasPrivPermission("channels/auspex"))
return MOD_RES_PASSTHRU;
Membership* const memb = chan->GetUser(user);
if (!memb)
return MOD_RES_PASSTHRU;

View File

@ -216,7 +216,7 @@ class SearchInterface : public LDAPInterface
void OnResult(const LDAPResult& r) override
{
LocalUser* user = static_cast<LocalUser*>(ServerInstance->FindUUID(uid));
LocalUser* user = IS_LOCAL(ServerInstance->FindUUID(uid));
dynamic_reference<LDAPProvider> LDAP(me, provider);
if (!LDAP || r.empty() || !user)
{

View File

@ -113,8 +113,9 @@ class DummyZ : public ModeHandler
// Handle /MODE #chan Z
void DisplayList(User* user, Channel* chan) override
{
if (IS_LOCAL(user))
::DisplayList(static_cast<LocalUser*>(user), chan);
LocalUser* luser = IS_LOCAL(user);
if (luser)
::DisplayList(luser, chan);
}
};

View File

@ -58,6 +58,14 @@ class ModuleNoCTCP : public Module
return MOD_RES_PASSTHRU;
Channel* c = target.Get<Channel>();
const Channel::MemberMap& members = c->GetUsers();
for (Channel::MemberMap::const_iterator member = members.begin(); member != members.end(); ++member)
{
User* u = member->first;
if (u->IsModeSet(ncu))
details.exemptions.insert(u);
}
ModResult res = CheckExemption::Call(exemptionprov, user, c, "noctcp");
if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
@ -67,14 +75,6 @@ class ModuleNoCTCP : public Module
user->WriteNumeric(ERR_CANNOTSENDTOCHAN, c->name, "Can't send CTCP to channel (+C is set)");
return MOD_RES_DENY;
}
const Channel::MemberMap& members = c->GetUsers();
for (Channel::MemberMap::const_iterator member = members.begin(); member != members.end(); ++member)
{
User* u = member->first;
if (u->IsModeSet(ncu))
details.exemptions.insert(u);
}
break;
}
case MessageTarget::TYPE_USER:

View File

@ -59,7 +59,7 @@ class ServerTracker
Update(server, true);
}
void OnServerSplit(const Server* server) override
void OnServerSplit(const Server* server, bool error) override
{
Update(server, false);
}

View File

@ -58,7 +58,7 @@ class CmdBuilder
: content(1, ':')
, tagsize(0)
{
content.append(src->GetID());
content.append(src->GetId());
push(cmd);
FireEvent(src, cmd, tags);
}

View File

@ -381,7 +381,7 @@ bool TreeSocket::PreProcessOldProtocolMessage(User*& who, std::string& cmd, Comm
return false;
}
params[0] = server->GetID();
params[0] = server->GetId();
}
}
else if ((cmd == "GLINE") || (cmd == "KLINE") || (cmd == "ELINE") || (cmd == "ZLINE") || (cmd == "QLINE"))
@ -564,7 +564,7 @@ bool TreeSocket::PreProcessOldProtocolMessage(User*& who, std::string& cmd, Comm
// Second parameter becomes the target uuid
params[0].swap(params[1]);
// Replace first param (now the PUSH payload, not needed) with the source sid
params[0] = numericsource->GetID();
params[0] = numericsource->GetId();
params.push_back(InspIRCd::Format("%03u", numeric_number));

View File

@ -689,7 +689,7 @@ void ModuleSpanningTree::OnUnloadModule(Module* mod)
{
TreeServer* server = i->second;
if (!server->IsRoot())
FOREACH_MOD_CUSTOM(GetLinkEventProvider(), ServerProtocol::LinkEventListener, OnServerSplit, (server));
FOREACH_MOD_CUSTOM(GetLinkEventProvider(), ServerProtocol::LinkEventListener, OnServerSplit, (server, false));
}
return;
}
@ -793,6 +793,13 @@ void ModuleSpanningTree::OnMode(User* source, User* u, Channel* c, const Modes::
}
}
void ModuleSpanningTree::OnShutdown(const std::string& reason)
{
const TreeServer::ChildServers& children = Utils->TreeRoot->GetChildren();
while (!children.empty())
children.front()->SQuit(reason, true);
}
CullResult ModuleSpanningTree::cull()
{
if (Utils)
@ -804,7 +811,7 @@ ModuleSpanningTree::~ModuleSpanningTree()
{
ServerInstance->PI = &ServerInstance->DefaultProtocolInterface;
Server* newsrv = new Server(ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc);
Server* newsrv = new Server(ServerInstance->Config->GetSID(), ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc);
SetLocalUsersServer(newsrv);
delete Utils;

View File

@ -212,6 +212,7 @@ class ModuleSpanningTree
void OnUnloadModule(Module* mod) override;
ModResult OnAcceptConnection(int newsock, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) override;
void OnMode(User* source, User* u, Channel* c, const Modes::ChangeList& modes, ModeParser::ModeProcessFlag processflags) override;
void OnShutdown(const std::string& reason) override;
CullResult cull() override;
~ModuleSpanningTree();
Version GetVersion() override;

View File

@ -51,7 +51,7 @@ CommandNum::Builder::Builder(SpanningTree::RemoteUser* target, const Numeric::Nu
: CmdBuilder("NUM")
{
TreeServer* const server = (numeric.GetServer() ? (static_cast<TreeServer*>(numeric.GetServer())) : Utils->TreeRoot);
push(server->GetID()).push(target->uuid).push(InspIRCd::Format("%03u", numeric.GetNumeric()));
push(server->GetId()).push(target->uuid).push(InspIRCd::Format("%03u", numeric.GetNumeric()));
const CommandBase::Params& params = numeric.GetParams();
if (!params.empty())
{

View File

@ -76,7 +76,7 @@ static std::vector<std::string> GetMap(User* user, TreeServer* current, unsigned
std::string buffer = current->GetName();
if (user->IsOper())
{
buffer += " (" + current->GetID();
buffer += " (" + current->GetId();
const std::string& cur_vers = current->GetRawVersion();
if (!cur_vers.empty())

View File

@ -36,7 +36,7 @@ PingTimer::State PingTimer::TickInternal()
if (state == PS_SENDPING)
{
// Last ping was answered, send next ping
server->GetSocket()->WriteLine(CmdBuilder("PING").push(server->GetID()));
server->GetSocket()->WriteLine(CmdBuilder("PING").push(server->GetId()));
LastPingMsec = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000);
// Warn next unless warnings are disabled. If they are, jump straight to timeout.
if (Utils->PingWarnTime)

View File

@ -64,7 +64,7 @@ void SpanningTreeUtilities::RouteCommand(TreeServer* origin, CommandBase* thiscm
if (encap)
{
params.push(sdest->GetID());
params.push(sdest->GetId());
params.push(command);
}
}

View File

@ -65,7 +65,7 @@ bool SpanningTreeProtocolInterface::SendEncapsulatedData(const std::string& targ
return false;
// Use the SID of the target in the message instead of the server name
encap.push(server->GetID()).push(cmd).insert(params).Unicast(server->ServerUser);
encap.push(server->GetId()).push(cmd).insert(params).Unicast(server->ServerUser);
}
return true;

View File

@ -188,8 +188,8 @@ bool TreeSocket::CheckDuplicate(const std::string& sname, const std::string& sid
if (CheckDupe)
{
this->SendError("Server ID "+CheckDupe->GetID()+" already exists on server "+CheckDupe->GetName()+"! You may want to specify the server ID for the server manually with <server:id> so they do not conflict.");
ServerInstance->SNO.WriteToSnoMask('l', "Server connection from \002"+sname+"\002 denied, server ID '"+CheckDupe->GetID()+
this->SendError("Server ID "+CheckDupe->GetId()+" already exists on server "+CheckDupe->GetName()+"! You may want to specify the server ID for the server manually with <server:id> so they do not conflict.");
ServerInstance->SNO.WriteToSnoMask('l', "Server connection from \002"+sname+"\002 denied, server ID '"+CheckDupe->GetId()+
"' already exists on server "+CheckDupe->GetName());
return false;
}
@ -228,7 +228,7 @@ CommandServer::Builder::Builder(TreeServer* server)
: CmdBuilder(server->GetParent(), "SERVER")
{
push(server->GetName());
push(server->GetID());
push(server->GetId());
if (server->IsBursting())
push_property("burst", ConvToStr(server->StartBurst));
push_property("hidden", ConvToStr(server->Hidden));

View File

@ -32,16 +32,22 @@
* no socket associated with it. Its version string is our own local version.
*/
TreeServer::TreeServer()
: Server(ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc)
: Server(ServerInstance->Config->GetSID(), ServerInstance->Config->ServerName, ServerInstance->Config->ServerDesc)
, Parent(NULL), Route(NULL)
, VersionString(ServerInstance->GetVersionString())
, fullversion(ServerInstance->GetVersionString(true))
, rawversion(INSPIRCD_VERSION)
, Socket(NULL), sid(ServerInstance->Config->GetSID()), behind_bursting(0), isdead(false)
, Socket(NULL)
, behind_bursting(0)
, isdead(false)
, pingtimer(this)
, ServerUser(ServerInstance->FakeClient)
, age(ServerInstance->Time()), UserCount(ServerInstance->Users.LocalUserCount())
, OperCount(0), rtt(0), StartBurst(0), Hidden(false)
, age(ServerInstance->Time())
, UserCount(ServerInstance->Users.LocalUserCount())
, OperCount(0)
, rtt(0)
, StartBurst(0)
, Hidden(false)
{
AddHashEntry();
}
@ -50,12 +56,20 @@ TreeServer::TreeServer()
* This constructor initializes the server's Route and Parent, and sets up
* the ping timer for the server.
*/
TreeServer::TreeServer(const std::string& Name, const std::string& Desc, const std::string& id, TreeServer* Above, TreeSocket* Sock, bool Hide)
: Server(Name, Desc)
, Parent(Above), Socket(Sock), sid(id), behind_bursting(Parent->behind_bursting), isdead(false)
TreeServer::TreeServer(const std::string& Name, const std::string& Desc, const std::string& Sid, TreeServer* Above, TreeSocket* Sock, bool Hide)
: Server(Sid, Name, Desc)
, Parent(Above)
, Socket(Sock)
, behind_bursting(Parent->behind_bursting)
, isdead(false)
, pingtimer(this)
, ServerUser(new FakeUser(id, this))
, age(ServerInstance->Time()), UserCount(0), OperCount(0), rtt(0), StartBurst(0), Hidden(Hide)
, age(ServerInstance->Time())
, UserCount(0)
, OperCount(0)
, rtt(0)
, StartBurst(0)
, Hidden(Hide)
{
ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "New server %s behind_bursting %u", GetName().c_str(), behind_bursting);
CheckULine();
@ -128,7 +142,7 @@ void TreeServer::BeginBurst(uint64_t startms)
if ((!startms) || (startms > now))
startms = now;
this->StartBurst = startms;
ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "Server %s started bursting at time %s behind_bursting %u", sid.c_str(), ConvToStr(startms).c_str(), behind_bursting);
ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "Server %s started bursting at time %s behind_bursting %u", GetId().c_str(), ConvToStr(startms).c_str(), behind_bursting);
}
void TreeServer::FinishBurstInternal()
@ -153,12 +167,13 @@ void TreeServer::FinishBurst()
unsigned long bursttime = ts - this->StartBurst;
ServerInstance->SNO.WriteToSnoMask(Parent == Utils->TreeRoot ? 'l' : 'L', "Received end of netburst from \002%s\002 (burst time: %lu %s)",
GetName().c_str(), (bursttime > 10000 ? bursttime / 1000 : bursttime), (bursttime > 10000 ? "secs" : "msecs"));
FOREACH_MOD_CUSTOM(Utils->Creator->GetLinkEventProvider(), ServerProtocol::LinkEventListener, OnServerBurst, (this));
StartBurst = 0;
FinishBurstInternal();
}
void TreeServer::SQuitChild(TreeServer* server, const std::string& reason)
void TreeServer::SQuitChild(TreeServer* server, const std::string& reason, bool error)
{
stdalgo::erase(Children, server);
@ -166,7 +181,7 @@ void TreeServer::SQuitChild(TreeServer* server, const std::string& reason)
{
// Server split from us, generate a SQUIT message and broadcast it
ServerInstance->SNO.WriteGlobalSno('l', "Server \002" + server->GetName() + "\002 split: " + reason);
CmdBuilder("SQUIT").push(server->GetID()).push_last(reason).Broadcast();
CmdBuilder("SQUIT").push(server->GetId()).push_last(reason).Broadcast();
}
else
{
@ -174,7 +189,7 @@ void TreeServer::SQuitChild(TreeServer* server, const std::string& reason)
}
unsigned int num_lost_servers = 0;
server->SQuitInternal(num_lost_servers);
server->SQuitInternal(num_lost_servers, error);
const std::string quitreason = GetName() + " " + server->GetName();
unsigned int num_lost_users = QuitUsers(quitreason);
@ -190,14 +205,14 @@ void TreeServer::SQuitChild(TreeServer* server, const std::string& reason)
ServerInstance->GlobalCulls.AddItem(server);
}
void TreeServer::SQuitInternal(unsigned int& num_lost_servers)
void TreeServer::SQuitInternal(unsigned int& num_lost_servers, bool error)
{
ServerInstance->Logs.Log(MODNAME, LOG_DEBUG, "Server %s lost in split", GetName().c_str());
for (ChildServers::const_iterator i = Children.begin(); i != Children.end(); ++i)
{
TreeServer* server = *i;
server->SQuitInternal(num_lost_servers);
server->SQuitInternal(num_lost_servers, error);
}
// Mark server as dead
@ -206,7 +221,7 @@ void TreeServer::SQuitInternal(unsigned int& num_lost_servers)
RemoveHash();
if (!Utils->Creator->dying)
FOREACH_MOD_CUSTOM(Utils->Creator->GetLinkEventProvider(), ServerProtocol::LinkEventListener, OnServerSplit, (this));
FOREACH_MOD_CUSTOM(Utils->Creator->GetLinkEventProvider(), ServerProtocol::LinkEventListener, OnServerSplit, (this, error));
}
unsigned int TreeServer::QuitUsers(const std::string& reason)
@ -258,7 +273,7 @@ void TreeServer::CheckULine()
void TreeServer::AddHashEntry()
{
Utils->serverlist[GetName()] = this;
Utils->sidlist[sid] = this;
Utils->sidlist[GetId()] = this;
}
CullResult TreeServer::cull()
@ -288,6 +303,6 @@ TreeServer::~TreeServer()
void TreeServer::RemoveHash()
{
Utils->sidlist.erase(sid);
Utils->sidlist.erase(GetId());
Utils->serverlist.erase(GetName());
}

View File

@ -51,7 +51,6 @@ class TreeServer : public Server
std::string rawversion;
TreeSocket* Socket; /* Socket used to communicate with this server */
std::string sid; /* Server ID */
/** Counter counting how many servers are bursting in front of this server, including
* this server. Set to parents' value on construction then it is increased if the
@ -75,7 +74,7 @@ class TreeServer : public Server
/** Used by SQuit logic to recursively remove servers
*/
void SQuitInternal(unsigned int& num_lost_servers);
void SQuitInternal(unsigned int& num_lost_servers, bool error);
/** Remove the reference to this server from the hash maps
*/
@ -104,15 +103,17 @@ class TreeServer : public Server
/** SQuit a server connected to this server, removing the given server and all servers behind it
* @param server Server to squit, must be directly below this server
* @param reason Reason for quitting the server, sent to opers and other servers
* @param error Whether the server is being squit because of an error.
*/
void SQuitChild(TreeServer* server, const std::string& reason);
void SQuitChild(TreeServer* server, const std::string& reason, bool error = false);
/** SQuit this server, removing this server and all servers behind it
* @param reason Reason for quitting the server, sent to opers and other servers
* @param error Whether the server is being squit because of an error.
*/
void SQuit(const std::string& reason)
void SQuit(const std::string& reason, bool error = false)
{
GetParent()->SQuitChild(this, reason);
GetParent()->SQuitChild(this, reason, error);
}
static unsigned int QuitUsers(const std::string& reason);
@ -194,10 +195,6 @@ class TreeServer : public Server
*/
const ChildServers& GetChildren() const { return Children; }
/** Get server ID
*/
const std::string& GetID() const { return sid; }
/** Marks a server as having finished bursting and performs appropriate actions.
*/
void FinishBurst();

View File

@ -415,7 +415,7 @@ void TreeSocket::Close()
// If the connection is fully up (state CONNECTED)
// then propogate a netsplit to all peers.
if (MyRoot)
MyRoot->SQuit(getError());
MyRoot->SQuit(getError(), true);
ServerInstance->SNO.WriteGlobalSno('l', "Connection to '\002%s\002' failed.", linkID.c_str());

View File

@ -38,7 +38,7 @@ CmdResult CommandUID::HandleServer(TreeServer* remoteserver, CommandBase::Params
const std::string& modestr = params[8];
// Check if the length of the uuid is correct and confirm the sid portion of the uuid matches the sid of the server introducing the user
if (params[0].length() != UIDGenerator::UUID_LENGTH || params[0].compare(0, 3, remoteserver->GetID()))
if (params[0].length() != UIDGenerator::UUID_LENGTH || params[0].compare(0, 3, remoteserver->GetId()))
throw ProtocolException("Bogus UUID");
// Sanity check on mode string: must begin with '+'
if (modestr[0] != '+')

View File

@ -49,7 +49,7 @@ class AuthQuery : public SQL::Query
void OnResult(SQL::Result& res) override
{
LocalUser* user = static_cast<LocalUser*>(ServerInstance->FindUUID(uid));
LocalUser* user = IS_LOCAL(ServerInstance->FindUUID(uid));
if (!user)
return;

View File

@ -23,12 +23,12 @@
#include "inspircd.h"
#include "listmode.h"
/** Holds a timed ban
*/
// Holds a timed ban
class TimedBan
{
public:
std::string mask;
std::string setter;
time_t expire;
Channel* chan;
};
@ -36,8 +36,7 @@ class TimedBan
typedef std::vector<TimedBan> timedbans;
timedbans TimedBanList;
/** Handle /TBAN
*/
// Handle /TBAN
class CommandTban : public Command
{
ChanModeReference banmode;
@ -47,6 +46,7 @@ class CommandTban : public Command
ListModeBase* banlm = static_cast<ListModeBase*>(*banmode);
if (!banlm)
return false;
const ListModeBase::ModeList* bans = banlm->GetList(chan);
if (bans)
{
@ -62,7 +62,8 @@ class CommandTban : public Command
}
public:
CommandTban(Module* Creator) : Command(Creator,"TBAN", 3)
CommandTban(Module* Creator)
: Command(Creator,"TBAN", 3)
, banmode(Creator, "ban")
{
syntax = "<channel> <duration> <banmask>";
@ -76,6 +77,7 @@ class CommandTban : public Command
user->WriteNumeric(Numerics::NoSuchChannel(parameters[0]));
return CMD_FAILURE;
}
unsigned int cm = channel->GetPrefixValue(user);
if (cm < HALFOP_VALUE)
{
@ -91,6 +93,7 @@ class CommandTban : public Command
return CMD_FAILURE;
}
unsigned long expire = duration + ServerInstance->Time();
std::string mask = parameters[2];
bool isextban = ((mask.size() > 2) && (mask[1] == ':'));
if (!isextban && !InspIRCd::IsValidMask(mask))
@ -114,18 +117,20 @@ class CommandTban : public Command
}
T.mask = mask;
T.setter = user->nick;
T.expire = expire + (IS_REMOTE(user) ? 5 : 0);
T.chan = channel;
TimedBanList.push_back(T);
const std::string addban = user->nick + " added a timed ban on " + mask + " lasting for " + InspIRCd::DurationString(duration) + ".";
const std::string message = InspIRCd::Format("Timed ban %s added by %s on %s lasting for %s.",
mask.c_str(), user->nick.c_str(), channel->name.c_str(), InspIRCd::DurationString(duration).c_str());
// If halfop is loaded, send notice to halfops and above, otherwise send to ops and above
PrefixMode* mh = ServerInstance->Modes.FindPrefixMode('h');
char pfxchar = (mh && mh->name == "halfop") ? mh->GetPrefix() : '@';
ClientProtocol::Messages::Privmsg notice(ServerInstance->FakeClient, channel, addban, MSG_NOTICE);
ClientProtocol::Messages::Privmsg notice(ServerInstance->FakeClient, channel, message, MSG_NOTICE);
channel->Write(ServerInstance->GetRFCEvents().privmsg, notice, pfxchar);
ServerInstance->PI->SendChannelNotice(channel, pfxchar, addban);
ServerInstance->PI->SendChannelNotice(channel, pfxchar, message);
return CMD_SUCCESS;
}
@ -207,22 +212,22 @@ class ModuleTimedBans : public Module
for (timedbans::iterator i = expired.begin(); i != expired.end(); i++)
{
std::string mask = i->mask;
const std::string mask = i->mask;
Channel* cr = i->chan;
{
const std::string expiry = "*** Timed ban on " + cr->name + " expired.";
// If halfop is loaded, send notice to halfops and above, otherwise send to ops and above
PrefixMode* mh = ServerInstance->Modes.FindPrefixMode('h');
char pfxchar = (mh && mh->name == "halfop") ? mh->GetPrefix() : '@';
ClientProtocol::Messages::Privmsg notice(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->FakeClient, cr, expiry, MSG_NOTICE);
cr->Write(ServerInstance->GetRFCEvents().privmsg, notice, pfxchar);
ServerInstance->PI->SendChannelNotice(cr, pfxchar, expiry);
const std::string message = InspIRCd::Format("Timed ban %s set by %s on %s has expired.",
mask.c_str(), i->setter.c_str(), cr->name.c_str());
// If halfop is loaded, send notice to halfops and above, otherwise send to ops and above
PrefixMode* mh = ServerInstance->Modes.FindPrefixMode('h');
char pfxchar = (mh && mh->name == "halfop") ? mh->GetPrefix() : '@';
Modes::ChangeList setban;
setban.push_remove(ServerInstance->Modes.FindMode('b', MODETYPE_CHANNEL), mask);
ServerInstance->Modes.Process(ServerInstance->FakeClient, cr, NULL, setban);
}
ClientProtocol::Messages::Privmsg notice(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->FakeClient, cr, message, MSG_NOTICE);
cr->Write(ServerInstance->GetRFCEvents().privmsg, notice, pfxchar);
ServerInstance->PI->SendChannelNotice(cr, pfxchar, message);
Modes::ChangeList setban;
setban.push_remove(ServerInstance->Modes.FindMode('b', MODETYPE_CHANNEL), mask);
ServerInstance->Modes.Process(ServerInstance->FakeClient, cr, NULL, setban);
}
}

282
src/serializable.cpp Normal file
View File

@ -0,0 +1,282 @@
/*
* InspIRCd -- Internet Relay Chat Daemon
*
* Copyright (C) 2019 Peter Powell <petpow@saberuk.com>
*
* 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
* License as published by the Free Software Foundation, version 2.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "inspircd.h"
Serializable::Data& Serializable::Data::Load(const std::string& key, std::string& out)
{
EntryMap::iterator iter = this->entries.find(key);
if (iter == this->entries.end())
{
ServerInstance->Logs.Log("SERIALIZE", LOG_DEBUG, "Unable to load missing kv %s!", key.c_str());
}
else
{
out = iter->second;
ServerInstance->Logs.Log("SERIALIZE", LOG_DEBUG, "Loaded kv %s: %s", key.c_str(), out.c_str());
}
return *this;
}
Serializable::Data& Serializable::Data::Load(const std::string& key, Serializable::Data& out)
{
ChildMap::iterator iter = this->children.find(key);
if (iter == this->children.end())
{
ServerInstance->Logs.Log("SERIALIZE", LOG_DEBUG, "Unable to load missing data %s!", key.c_str());
}
else
{
out = iter->second;
ServerInstance->Logs.Log("SERIALIZE", LOG_DEBUG, "Loaded data: %s", key.c_str());
}
return *this;
}
Serializable::Data& Serializable::Data::Store(const std::string& key, const std::string& value)
{
ServerInstance->Logs.Log("SERIALIZE", LOG_DEBUG, "Stored kv %s: %s", key.c_str(), value.c_str());
this->entries[key] = value;
return *this;
}
Serializable::Data& Serializable::Data::Store(const std::string& key, const Serializable::Data& value)
{
ServerInstance->Logs.Log("SERIALIZE", LOG_DEBUG, "Stored data: %s", key.c_str());
this->children[key] = value;
return *this;
}
bool Extensible::Deserialize(Serializable::Data& data)
{
// If the extensible has been culled then it shouldn't be deserialized.
if (culled)
return false;
const Serializable::Data::EntryMap& entries = data.GetEntries();
for (Serializable::Data::EntryMap::const_iterator iter = entries.begin(); iter != entries.end(); ++iter)
{
const std::string& name = iter->first;
ExtensionItem* item = ServerInstance->Extensions.GetItem(name);
if (item)
{
item->FromInternal(this, iter->second);
continue;
}
ServerInstance->Logs.Log("SERIALIZE", LOG_DEBUG, "Tried to deserialize the %s extension item but it doesn't exist",
name.c_str());
}
return true;
}
bool Extensible::Serialize(Serializable::Data& data)
{
// If the extensible has been culled then it shouldn't be serialized.
if (culled)
{
ServerInstance->Logs.Log("SERIALIZE", LOG_DEBUG, "Tried to serialize an extensible which has been culled");
return false;
}
for (Extensible::ExtensibleStore::const_iterator iter = extensions.begin(); iter != extensions.end(); ++iter)
{
ExtensionItem* item = iter->first;
const std::string value = item->ToInternal(this, iter->second);
if (!value.empty())
data.Store(item->name, value);
}
return true;
}
bool User::Deserialize(Serializable::Data& data)
{
// If the user is quitting they shouldn't be deserialized.
if (quitting)
{
ServerInstance->Logs.Log("SERIALIZE", LOG_DEBUG, "Tried to deserialize %s who is in the process of quitting",
uuid.c_str());
return false;
}
// Check we're actually deserialising data for this user.
std::string client_uuid;
data.Load("uuid", client_uuid);
if (!client_uuid.empty() && client_uuid != uuid)
{
ServerInstance->Logs.Log("SERIALIZE", LOG_DEBUG, "Tried to deserialize %s into %s",
client_uuid.c_str(), uuid.c_str());
return false;
}
// Deserialize the extensions first.
Serializable::Data exts;
data.Load("extensions", exts);
if (!Extensible::Deserialize(exts))
return false;
long client_port;
std::string client_addr;
std::string user_modes;
std::string user_oper;
std::string user_snomasks;
// Apply the members which can be applied directly.
data.Load("age", age)
.Load("awaymsg", awaymsg)
.Load("awaytime", awaytime)
.Load("client_sa.addr", client_addr)
.Load("client_sa.port", client_port)
.Load("displayhost", displayhost)
.Load("ident", ident)
.Load("modes", user_modes)
.Load("nick", nick)
.Load("oper", user_oper)
.Load("realhost", realhost)
.Load("realname", realname)
.Load("signon", signon)
.Load("snomasks", user_snomasks);
// Apply the rest of the members.
modes = std::bitset<ModeParser::MODEID_MAX>(user_modes);
snomasks = std::bitset<64>(user_snomasks);
ServerConfig::OperIndex::const_iterator iter = ServerInstance->Config->OperTypes.find(user_oper);
if (iter != ServerInstance->Config->OperTypes.end())
oper = iter->second;
else
oper = new OperInfo(user_oper);
irc::sockets::sockaddrs sa;
if (irc::sockets::aptosa(client_addr, client_port, sa) || irc::sockets::untosa(client_addr, sa))
client_sa = sa;
InvalidateCache();
return true;
}
bool User::Serialize(Serializable::Data& data)
{
// If the user is quitting they shouldn't be serialized.
if (quitting)
{
ServerInstance->Logs.Log("SERIALIZE", LOG_DEBUG, "Tried to serialize %s who is in the process of quitting",
uuid.c_str());
return false;
}
// If the user is unregistered they shouldn't be serialised.
if (registered != REG_ALL)
return false;
// Serialize the extensions first.
Serializable::Data exts;
if (!Extensible::Serialize(exts))
return false;
data.Store("extensions", exts);
// The following member variables not checked above are not serialised:
// * cached_fullhost (serialising cache variables is unnecessary)
// * cached_fullrealhost (serialising cache variables is unnecessary)
// * cached_hostip (serialising cache variables is unnecessary)
// * cached_makehost (serialising cache variables is unnecessary)
// * cachedip (serialising cache variables is unnecessary)
// * server (specific to the origin server)
// * usertype (can't be networked reliably)
data.Store("age", age)
.Store("awaymsg", awaymsg)
.Store("awaytime", awaytime)
.Store("client_sa.addr", client_sa.addr())
.Store("client_sa.port", client_sa.port())
.Store("displayhost", displayhost)
.Store("ident", ident)
.Store("modes", modes.to_string())
.Store("nick", nick)
.Store("oper", oper ? oper->name : "")
.Store("realhost", realhost)
.Store("realname", realname)
.Store("signon", signon)
.Store("snomasks", snomasks.to_string())
.Store("uuid", uuid);
return true;
}
bool LocalUser::Deserialize(Serializable::Data& data)
{
// Deserialize the base class first.
if (!User::Deserialize(data))
return false;
bool user_exempt;
bool user_lastping;
long server_port;
std::string server_addr;
// Apply the members which can be applied directly.
data.Load("bytes_in", bytes_in)
.Load("bytes_out", bytes_out)
.Load("cmds_in", cmds_in)
.Load("cmds_out", cmds_out)
.Load("CommandFloodPenalty", CommandFloodPenalty)
.Load("exempt", user_exempt)
.Load("idle_lastmsg", idle_lastmsg)
.Load("lastping", user_lastping)
.Load("nextping", nextping)
.Load("password", password)
.Load("server_sa.addr", server_addr)
.Load("server_sa.port", server_port);
// Apply the rest of the members.
irc::sockets::sockaddrs sa;
if (irc::sockets::aptosa(server_addr, server_port, sa) || irc::sockets::untosa(server_addr, sa))
server_sa = sa;
// These are bitfields so we need to ensure they only get the appropriate bits.
exempt = user_exempt ? 1 : 0;
lastping = user_lastping ? 1 : 0;
return true;
}
bool LocalUser::Serialize(Serializable::Data& data)
{
// Serialize the base class first.
if (!User::Serialize(data))
return false;
// The following member variables not checked above are not serialised:
// * already_sent (can't be networked reliably)
// * eh (shouldn't be networked)
// * MyClass (might not be the same on a different server)
// * serializer (might not be the same on a different connection)
data.Store("bytes_in", bytes_in)
.Store("bytes_out", bytes_out)
.Store("cmds_in", cmds_in)
.Store("cmds_out", cmds_out)
.Store("CommandFloodPenalty", CommandFloodPenalty)
.Store("exempt", exempt)
.Store("idle_lastmsg", idle_lastmsg)
.Store("lastping", lastping)
.Store("nextping", nextping)
.Store("password", password)
.Store("server_sa.addr", server_sa.addr())
.Store("server_sa.port", server_sa.port());
return true;
}

View File

@ -200,7 +200,6 @@ void ISupportManager::Build()
tokens["STATUSMSG"] = ServerInstance->Modes.BuildPrefixes(false);
tokens["TOPICLEN"] = ConvToStr(ServerInstance->Config->Limits.MaxTopic);
tokens["USERLEN"] = ConvToStr(ServerInstance->Config->Limits.IdentMax);
tokens["VBANLIST"];
// Modules can add new tokens and also edit or remove existing tokens
FOREACH_MOD(On005Numeric, (tokens));

View File

@ -40,10 +40,10 @@ namespace
*/
std::vector<struct kevent> changelist(8);
#ifdef __NetBSD__
#if defined __NetBSD__ && __NetBSD_Version__ <= 999001400
inline intptr_t udata_cast(EventHandler* eh)
{
// On NetBSD the last parameter of EV_SET is intptr_t.
// On NetBSD <10 the last parameter of EV_SET is intptr_t.
return reinterpret_cast<intptr_t>(eh);
}
#else

View File

@ -112,6 +112,15 @@ LocalUser::LocalUser(int myfd, irc::sockets::sockaddrs* client, irc::sockets::so
ChangeRealHost(GetIPString(), true);
}
LocalUser::LocalUser(int myfd, const std::string& uid, Serializable::Data& data)
: User(uid, ServerInstance->FakeClient->server, USERTYPE_LOCAL)
, eh(this)
, already_sent(0)
{
eh.SetFd(myfd);
Deserialize(data);
}
User::~User()
{
}
@ -749,17 +758,16 @@ void LocalUser::SetClientIP(const irc::sockets::sockaddrs& sa)
return;
ServerInstance->Users.RemoveCloneCounts(this);
User::SetClientIP(sa);
FOREACH_MOD(OnSetUserIP, (this));
ServerInstance->Users.AddClone(this);
// Recheck the connect class.
this->MyClass = NULL;
this->SetClass();
this->CheckClass();
if (!quitting)
FOREACH_MOD(OnSetUserIP, (this));
}
void LocalUser::Write(const ClientProtocol::SerializedMessage& text)
@ -1189,10 +1197,24 @@ const std::string& FakeUser::GetFullRealHost()
}
ConnectClass::ConnectClass(ConfigTag* tag, char t, const std::string& mask)
: config(tag), type(t), fakelag(true), name("unnamed"), registration_timeout(0), host(mask),
pingtime(0), softsendqmax(0), hardsendqmax(0), recvqmax(0),
penaltythreshold(0), commandrate(0), maxlocal(0), maxglobal(0), maxconnwarn(true), maxchans(20),
limit(0), resolvehostnames(true)
: config(tag)
, type(t)
, fakelag(true)
, name("unnamed")
, registration_timeout(0)
, host(mask)
, pingtime(0)
, softsendqmax(0)
, hardsendqmax(0)
, recvqmax(0)
, penaltythreshold(0)
, commandrate(0)
, maxlocal(0)
, maxglobal(0)
, maxconnwarn(true)
, maxchans(20)
, limit(0)
, resolvehostnames(true)
{
}