/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2012-2016, 2018 Attila Molnar * Copyright (C) 2012-2013, 2017-2025 Sadie Powell * Copyright (C) 2012 Robby * Copyright (C) 2012 ChrisTX * Copyright (C) 2009-2010 Daniel De Graaf * Copyright (C) 2007-2009 Dennis Friis * Copyright (C) 2007-2008 Robin Burchell * Copyright (C) 2007 Oliver Lupton * Copyright (C) 2005-2008 Craig Edwards * * 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 . */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef _WIN32 # include #endif #include "utility/aligned_storage.h" #include "utility/iterator_range.h" #include "intrusive_list.h" #include "flat_map.h" #include "compat.h" #include "typedefs.h" #include "convto.h" #include "stdalgo.h" #include "exception.h" CoreExport extern InspIRCd* ServerInstance; #include "config.h" #include "dynref.h" #include "cull.h" #include "extensible.h" #include "ctables.h" #include "numeric.h" #include "uid.h" #include "server.h" #include "token_list.h" #include "users.h" #include "channels.h" #include "timer.h" #include "hashcomp.h" #include "channelmanager.h" #include "usermanager.h" #include "socket.h" #include "command_parse.h" #include "mode.h" #include "socketengine.h" #include "snomasks.h" #include "message.h" #include "modules.h" #include "moduledefs.h" #include "clientprotocol.h" #include "thread.h" #include "configreader.h" #include "protocol.h" #include "bancache.h" #include "logging.h" /** This class contains various STATS counters * It is used by the InspIRCd class, which internally * has an instance of it. */ class ServerStats final { public: /** Number of accepted connections. */ size_t Accept = 0; /** Number of rejected connections. */ size_t Refused = 0; /** Number of unknown commands seen. */ size_t Unknown = 0; /** Number of nickname collisions handled. */ size_t Collisions = 0; /** Number of fully connected users seen. */ size_t Connects = 0; /** Total bytes of data transmitted. */ size_t Sent = 0; /** Total bytes of data received. */ size_t Recv = 0; #ifdef _WIN32 /** CPU performance frequency on boot. */ LARGE_INTEGER BootCPU; /** CPU performance frequency at the last sample. */ LARGE_INTEGER LastCPU; /** Time the last sample was read. */ FILETIME LastSampled; #else /** CPU usage at the last sample. */ timeval LastCPU; /** Time the last sample was read. */ timespec LastSampled; #endif }; /** The main class of the irc server. * This class contains instances of all the other classes in this software. * Amongst other things, it contains a ModeParser, a DNS object, a CommandParser * object, and a list of active Module objects, and facilities for Module * objects to interact with the core system it implements. */ class CoreExport InspIRCd final { private: /** The last signal that was received from the operating system. */ static sig_atomic_t lastsignal; /** A 64k buffer used to read socket data into. */ char readbuffer[65535]; /** The client protocol events provided by the core. */ ClientProtocol::RFCEvents rfcevents; /** The current time, updated once per main loop iteration. */ struct timespec ts; /** Prepares the server for restart or shutdown. */ void Cleanup(); /** Handles an stored signal in the main loop. * @param signal The signal received from the operating system. */ void HandleSignal(sig_atomic_t signal); /** Attempt to write the process id to a file. */ void WritePID(); public: /** Actions that must happen outside of the current call stack. */ ActionList AtomicActions; /** Caches server bans to speeds up checking of restrictions on connect. */ BanCacheManager BanCache; /** Manager for state relating to channels. */ ChannelManager Channels; /** Default implementation of the protocol interface which does nothing. */ ProtocolInterface DefaultProtocolInterface; /* Manager for the extension system. */ ExtensionManager Extensions; /** Objects that should be culled outside of the current call stack. */ CullList GlobalCulls; /** Manager for the logging system. */ Log::Manager Logs; /* Manager for the mode handlers. */ ModeParser Modes; /** Manager for the module loading system. */ ModuleManager Modules; /** Manager for the command handlers. */ CommandParser Parser; /** Manages sending snomasks to server operators. */ SnomaskManager SNO; /** Holds miscellaneous stats counters. */ ServerStats Stats; /** Manages scheduling and triggering of timer events. */ TimerManager Timers; /* Generator for unique user identifiers. */ UIDGenerator UIDGen; /** Manager for state relating to users. */ UserManager Users; /** The server configuration. */ ServerConfig* Config = nullptr; /* If non-nullptr then the thread that is reading the server configuration on rehash. */ ConfigReaderThread* ConfigThread = nullptr; /** A fake user that represents the local server. */ FakeUser* FakeClient = nullptr; /** The protocol interface used for interacting with remote servers by the linking module. */ ProtocolInterface* PI = &DefaultProtocolInterface; /** Manager for X-lines. */ XLineManager* XLines = nullptr; /** The current server configuration file from --config or configure. */ std::string ConfigFileName; /** Fills a buffer with random bytes. */ std::function GenRandom = &DefaultGenRandom; /** Determines whether a nickname is valid. */ std::function IsNick = &DefaultIsNick; /** Determines whether a username is valid. */ std::function IsUser = &DefaultIsUser; /** List of the open listeners. */ std::vector ports; /** The time at which the server was started. */ time_t startup_time; /** Initialises a new server instance and stores it in ServerInstance * @param argc The argument count from main(). * @param argv The argument list from main(). */ InspIRCd(int argc, char** argv); /** Binds to a specific port from a config tag. * @param tag the tag that contains bind information. * @param sa The endpoint to listen on. * @param oldports Previously listening ports that may be on the same endpoint. * @param protocol The protocol to bind with or 0 to determine from the endpoint. * @return True if the port was bound successfully; otherwise, false. */ bool BindPort(const std::shared_ptr& tag, const irc::sockets::sockaddrs& sa, std::vector& oldports, sa_family_t protocol); /** Binds all ports specified in the configuration file. * @param failedports The location to store details about the ports that failed to bind. * @return The number of ports bound without error. */ size_t BindPorts(FailedPortList& failedports); /** Compares a password to a hashed password. * @param password The hashed password. * @param passwordhash If non-empty then the algorithm the password is hashed with. * @param value The value to check to see if the password is valid. * @return True if the password is correct, otherwise, false. */ static bool CheckPassword(const std::string& password, const std::string& passwordhash, const std::string& value); /** Generates a random integer. * @param max The maximum value for the integer. * @return A random integer between 0 and \p max. */ unsigned long GenRandomInt(unsigned long max) const; /** Generates a human readable random string. * @param length The length in bytes. * @return A random string of \p length bytes. */ std::string GenRandomStr(size_t length) const; /** Generates a random string. * @param length The length in bytes. * @param printable Whether to only return printable characters. * @return A random string of \p length bytes. */ [[deprecated("Use GenRandomStr(length) or GenRandom(buf, len) instead")]] std::string GenRandomStr(size_t length, bool printable) const; /** Retrieves a 64k buffer used to read socket data into. */ inline auto* GetReadBuffer() { return readbuffer; } /** Retrieves the client protocol events provided by the core. */ inline auto& GetRFCEvents() { return rfcevents; } /** Fills the output buffer with the specified number of random characters. * This is the default function for InspIRCd::GenRandom. * @param output The output buffer to store random characters in. * @param max The maximum number of random characters to put in the buffer. */ static void DefaultGenRandom(char* output, size_t max); /** Determines whether a nickname is valid according to the RFC 1459 rules. * This is the default function for InspIRCd::IsNick. * @param nick The nickname to validate. * @return True if the nickname is valid according to RFC 1459 rules; otherwise, false. */ static bool DefaultIsNick(const std::string_view& nick); /** Determines whether a username is valid according to the RFC 1459 rules. * This is the default function for InspIRCd::IsUser. * @param user The username to validate. * @return True if the username is valid according to RFC 1459 rules; otherwise, false. */ static bool DefaultIsUser(const std::string_view& user); /** Causes the server to exit after unloading modules and closing all open file descriptors. * @param status The exit code to give to the operating system. */ [[noreturn]] void Exit(int status); /** Determines whether a fully qualified hostname is valid according to RFC 5891 rules. * @param host The hostname to validate. * @return True if the hostname is valid; otherwise, false. */ inline static auto IsFQDN(const std::string_view& host) { return IsHost(host, false); } /** Determines whether a hostname is valid according to RFC 5891 rules. * @param host The hostname to validate. * @param allowsimple Whether to allow simple hostnames (e.g. localhost). * @return True if the hostname is valid; otherwise, false. */ static bool IsHost(const std::string_view& host, bool allowsimple); /** Determines whether the specified string is a server identifier. * @param sid The string to check. * @return True if the specified string is a server identifier; otherwise, false. */ static bool IsSID(const std::string_view& sid); /** Determines whether the specified string is a valid nick!user\@host mask. * @param mask The string to check. * @return True if the specified string is a valid nick!user\@host mask; otherwise, false. */ static bool IsValidMask(const std::string& mask); /** Matches two strings using glob pattern matching, optionally with a case map to use instead * of the server case map. * @param str The literal string to match against * @param pattern The glob pattern to match against. * @param map The character map to use when matching. * @return True if the string matches the mask; otherwise, false. */ static bool Match(const std::string& str, const std::string& pattern, const unsigned char* map = nullptr); /** Matches two strings using glob pattern matching, optionally with a case map to use instead * of the server case map. * @param str The literal string to match against * @param pattern The glob pattern to match against. * @param map The character map to use when matching. * @return True if the string matches the pattern; otherwise, false. */ static bool Match(const char* str, const char* pattern, const unsigned char* map = nullptr); /** Matches two strings using glob pattern and CIDR range matching, optionally with a case map * to use instead of the server case map. * @param str The literal string to match against * @param pattern The glob pattern to match against. * @param map The character map to use when matching. * @return True if the string matches the pattern; otherwise, false. */ static bool MatchCIDR(const std::string& str, const std::string& pattern, const unsigned char* map = nullptr); /** Matches two strings using glob pattern and CIDR range matching, optionally with a case map * to use instead of the server case map. * @param str The literal string to match against * @param pattern The glob pattern to match against. * @param map The character map to use when matching. * @return True if the string matches the pattern; otherwise, false. */ static bool MatchCIDR(const char* str, const char* pattern, const unsigned char* map = nullptr); /** Matches a hostname and address against a space delimited list of hostmasks. * @param masks The space delimited masks to match against. * @param hostname The hostname to try and match. * @param address The IP address or UNIX socket path to try and match. * @return True if a mask matches the hostname or address; otherwise, false. */ static bool MatchMask(const std::string& masks, const std::string& hostname, const std::string& address); /** Reloads the server configuration. * @param uuid If non-empty then the uuid of the user who started the rehash. */ void Rehash(const std::string& uuid = ""); /** Starts the execution of the server main loop. */ [[noreturn]] void Run(); /** Replaces color escapes in the specified lines with IRC colors. * @param lines A vector of lines to replace color escapes in. */ [[deprecated("Use ProcessColors(std::string) instead")]] static void ProcessColors(std::vector& lines); /** Replaces color escapes in the specified string with IRC colors. * @param lines The string replace color escapes in. */ static void ProcessColors(std::string& str); /** Stores an incoming signal when received from the operating system. * @param signal The signal received from the operating system. */ static void SetSignal(int signal); /* Removes IRC colors from the specified string. * @param str The string to strip colors from. */ static void StripColor(std::string& str); /** Retrieves the time, updated once per main loop iteration, as the number of seconds since * the UNIX epoch. This is faster than calling time functions manually. */ inline auto Time() const { return ts.tv_sec; } /** Retrieves the time, updated once per main loop iteration, as the number of fractional * seconds since the UNIX epoch. This is faster than calling time functions manually. */ inline auto Time_ns() const { return ts.tv_nsec; } /** Compares two strings in a timing-safe way. If the lengths of the strings differ the * function returns false immediately (leaking information about the length). Otherwise, it * compares each character and only returns after all characters have been compared. * @param str1 The first string to compare. * @param str2 The second string to compare. * @return True if the strings are equivalent; otherwise, false. */ static bool TimingSafeCompare(const std::string& str1, const std::string& str2); /** Updates the current cached time. Don't call this unless you have reason to do so. */ void UpdateTime(); }; inline void Cullable::Deleter::operator()(Cullable* item) const { if (item) ServerInstance->GlobalCulls.AddItem(item); } inline void Channel::Write(ClientProtocol::EventProvider& protoevprov, ClientProtocol::Message& msg, char status, const CUList& except_list) const { ClientProtocol::Event event(protoevprov, msg); Write(event, status, except_list); } inline void LocalUser::Send(ClientProtocol::EventProvider& protoevprov, ClientProtocol::Message& msg) { ClientProtocol::Event event(protoevprov, msg); Send(event); }