Merge branch 'insp4' into master.

This commit is contained in:
Sadie Powell 2024-11-01 14:35:23 +00:00
commit 8a3aba4044
59 changed files with 441 additions and 183 deletions

View File

@ -12,7 +12,7 @@ The GitHub issue tracker is for bug reports ONLY. General support can be found a
Discussions: https://github.com/inspircd/inspircd/discussions
Docs: https://docs.inspircd.org
IRC: irc.chatspike.net #inspircd
IRC: ircs://irc.teranova.net/inspircd
Example configs (v3): https://github.com/inspircd/inspircd/tree/insp3/docs/conf
Example configs (v4): https://github.com/inspircd/inspircd/tree/insp4/docs/conf
-->

View File

@ -10,7 +10,7 @@ The GitHub issue tracker is for feature requests ONLY. General support can be fo
Discussions: https://github.com/inspircd/inspircd/discussions
Docs: https://docs.inspircd.org
IRC: irc.chatspike.net #inspircd
IRC: ircs://irc.teranova.net/inspircd
Example configs (v3): https://github.com/inspircd/inspircd/tree/insp3/docs/conf
Example configs (v4): https://github.com/inspircd/inspircd/tree/insp4/docs/conf
-->

2
.github/SECURITY.md vendored
View File

@ -18,6 +18,6 @@ Version | Supported
## Reporting a Vulnerability
Please do not report security vulnerabilities on GitHub. Instead, get the attention of a developer in our development IRC channel at irc.chatspike.net #inspircd.dev and PM them the details.
Please do not report security vulnerabilities on GitHub. Instead, get the attention of a developer in our development IRC channel at ircs://irc.teranova.net/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

@ -4,4 +4,3 @@ updates:
directory: /
schedule:
interval: monthly
target-branch: insp3

View File

@ -22,7 +22,7 @@ jobs:
- name: Setup Conan
uses: turtlebrowser/get-conan@v1.2
with:
version: 1.63.0
version: 1.65.0
- name: Install libraries
working-directory: ${{ github.workspace }}/win/build

View File

@ -31,7 +31,7 @@ jobs:
- uses: sobolevn/misspell-fixer-action@master
with:
options: '-rvnfuRVD .'
- uses: peter-evans/create-pull-request@v6
- uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ env.REF_BRANCH }}+fix-spellings-${{ env.DATE }}

View File

@ -48,6 +48,6 @@ InspIRCd is licensed under [version 2 of the GNU General Public License](https:/
* [Documentation](https://docs.inspircd.org)
* [GitHub](https://github.com/inspircd)
* [Social Media](https://docs.inspircd.org/social)
* Support IRC channel — \#inspircd on irc.chatspike.net
* Development IRC channel — \#inspircd.dev on irc.chatspike.net
* InspIRCd test network — testnet.inspircd.org
* Support IRC channel — \#inspircd on irc.teranova.net (TLS only)
* Development IRC channel — \#inspircd.dev on irc.teranova.net (TLS only)
* InspIRCd test network — testnet.inspircd.org (TLS only)

View File

@ -1,16 +1,8 @@
NOTE: InspIRCd is licensed under GPL version 2 only.
"Upgrading" to a later version of the GENERAL PUBLIC
LICENSE is not permitted. For further information on
this, please contact us at irc.chatspike.net on #inspircd.
----------------------------------------------------------------------
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@ -312,8 +304,7 @@ the "copyright" line and a pointer to where the full notice is found.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
with this program; if not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
@ -337,8 +328,8 @@ necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
<signature of Moe Ghoul>, 1 April 1989
Moe Ghoul, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may

View File

@ -651,23 +651,27 @@
# banned from the server.
xlinemessage="You're banned! Email irc@&networkDomain; with the ERROR line below for help."
# xlinequit: The quit message to show to opers and affected users when
# a user is [KGZ]-lined. The variables you can use in this are:
#
# %created% - The date/time at which the X-line was created.
# %duration% - The duration of the X-line.
# %expiry% - The date/time at which the X-line expires.
# %fulltype% - The type of X-line which was matched, suffixed with
# "-lined" if its name is one or two characters.
# %reason% - The reason the X-line was added.
# %remaining% - The duration remaining on the X-line.
# %setter% - The name of the X-line setter.
# %type% - The type of X-line which was matched.
xlinequit="%fulltype%: %reason%"
# xlinequit: The quit message to show to opers and affected users when
# a user is [KGZ]-lined. The variables you can use in this are:
#
# %created% - The date/time at which the X-line was created.
# %duration% - The duration of the X-line.
# %expiry% - The date/time at which the X-line expires.
# %fulltype% - The type of X-line which was matched, suffixed with
# "-lined" if its name is one or two characters.
# %reason% - The reason the X-line was added.
# %remaining% - The duration remaining on the X-line.
# %setter% - The name of the X-line setter.
# %type% - The type of X-line which was matched.
xlinequit="%fulltype%: %reason%"
# modesinlist: If enabled then the current channel modes will be shown
# in the /LIST response. Defaults to yes.
modesinlist="no"
# modesinlist: Whether to show the current channel modes in the /LIST
# output. Can be set to any one of:
# - yes Show the current channel modes to all users.
# - opers Show the current channel modes to server operators with the
# channels/auspex privilege. This is the default.
# - no Do not show the current channel modes in /LIST.
modesinlist="opers"
# extbanformat: The method to use for normalising extbans. Can be set
# to one of:

View File

@ -118,10 +118,10 @@
# An example of using the format value to create an alias with two
# different behaviours depending on the format of the parameters.
#
#<alias text="ID" format="#*" replace="SQUERY ChanServ :IDENTIFY $2 $3"
#<alias text="ID" format="#*" replace="PRIVMSG ChanServ :IDENTIFY $2 $3"
# requires="ChanServ" service="yes">
#
#<alias text="ID" replace="SQUERY NickServ :IDENTIFY $2"
#<alias text="ID" replace="PRIVMSG NickServ :IDENTIFY $2"
# requires="NickServ" service="yes">
#
# You may also add aliases to trigger based on something said in a
@ -130,7 +130,7 @@
# command must be preceded by the fantasy prefix when used.
#
#<alias text="CS" usercommand="no" channelcommand="yes"
# replace="SQUERY ChanServ :$1 $chan $2-" requires="ChanServ" service="yes">
# replace="PRIVMSG ChanServ :$1 $chan $2-" requires="ChanServ" service="yes">
#
# This would be used as "!cs <command> <options>", with the channel
# being automatically inserted after the command in the message to
@ -927,6 +927,9 @@
# stdregex - stdlib regexps, provided via regex_stdlib, see comment #
# at the <module> tag for info on availability. #
# #
# If enableflags is set, you can specify flags that modify matching #
# of the regular expression. #
# #
# If notifyuser is set to no, the user will not be notified when #
# their message is blocked. #
# #
@ -935,7 +938,10 @@
# warning will be sent to opers instead. This stops spambots which #
# send their spam message to themselves first to check if it is being #
# filtered by the server. #
#<filteropts engine="stdregex" notifyuser="yes" warnonselfmsg="no">
#<filteropts engine="stdregex"
# enableflags="yes"
# notifyuser="yes"
# warnonselfmsg="no">
# #
# Your choice of regex engine must match on all servers network-wide. #
# #

View File

@ -24,7 +24,7 @@
+---- To change this see \bmotd.example.txt\x ----+
| |
| * \bWeb:\x https://www.inspircd.org |
| * \bIRC:\x irc.chatspike.net #inspircd |
| * \bIRC:\x ircs://irc.teranova.net/inspircd |
| * \bDocs:\x https://docs.inspircd.org |
| * \bIssues:\x https://git.io/JIuYi |
| * \bDiscussions:\x https://git.io/JIuYv |

View File

@ -24,7 +24,7 @@
+-- To change this see \bopermotd.example.txt\x --+
| |
| * \bWeb:\x https://www.inspircd.org |
| * \bIRC:\x irc.chatspike.net #inspircd |
| * \bIRC:\x ircs://irc.teranova.net/inspircd |
| * \bDocs:\x https://docs.inspircd.org |
| * \bIssues:\x https://git.io/JIuYi |
| * \bDiscussions:\x https://git.io/JIuYv |

View File

@ -8,4 +8,80 @@
records="3,5,6,7,8,9,10,11,13,14,15,16,17,19"
action="zline"
duration="7d"
reason="You are listed in DroneBL. Please visit https://dronebl.org/lookup.do?ip=%ip%&amp;network=%network.url% for more information.">
reason="You are listed in DroneBL: %reason%. Please visit https://dronebl.org/lookup.do?ip=%ip%&amp;network=%network.url% for more information.">
<dnsblreply name="DroneBL"
reply="1"
description="Testing">
<dnsblreply name="DroneBL"
reply="2"
description="Sample data used for heuristical analysis">
<dnsblreply name="DroneBL"
reply="3"
description="IRC spam drone (litmus/sdbot/fyle)">
<dnsblreply name="DroneBL"
reply="5"
description="Bottler">
<dnsblreply name="DroneBL"
reply="6"
description="Unknown worm or spambot">
<dnsblreply name="DroneBL"
reply="7"
description="DDoS drone">
<dnsblreply name="DroneBL"
reply="8"
description="Open SOCKS proxy">
<dnsblreply name="DroneBL"
reply="9"
description="Open HTTP proxy">
<dnsblreply name="DroneBL"
reply="10"
description="Proxychain">
<dnsblreply name="DroneBL"
reply="11"
description="Webpage proxy">
<dnsblreply name="DroneBL"
reply="12"
description="Open DNS resolver">
<dnsblreply name="DroneBL"
reply="13"
description="Automated dictionary attack">
<dnsblreply name="DroneBL"
reply="14"
description="Open WINGATE proxy">
<dnsblreply name="DroneBL"
reply="15"
description="Compromised router / gateway">
<dnsblreply name="DroneBL"
reply="16"
description="Autorooting worm">
<dnsblreply name="DroneBL"
reply="17"
description="Automatically determined botnet IP">
<dnsblreply name="DroneBL"
reply="18"
description="Possibly compromised DNS/MX type hostname detected on IRC">
<dnsblreply name="DroneBL"
reply="19"
description="Abused VPN service">
<dnsblreply name="DroneBL"
reply="255"
description="Uncategorized threat">

View File

@ -8,4 +8,24 @@
records="1,2,3,4,5"
action="zline"
duration="7d"
reason="You are listed in the EFnet RBL. Please visit https://rbl.efnetrbl.org/?i=%ip% for more information.">
reason="You are listed in the EFnet RBL: %reason%. Please visit https://rbl.efnetrbl.org/?i=%ip% for more information.">
<dnsblreply name="EFnet RBL"
reply="1"
description="Open proxy">
<dnsblreply name="EFnet RBL"
reply="2"
description="Spamtrap score of 666">
<dnsblreply name="EFnet RBL"
reply="3"
description="Spamtrap score of 50+">
<dnsblreply name="EFnet RBL"
reply="4"
description="Tor exit node">
<dnsblreply name="EFnet RBL"
reply="5"
description="Drones or flooding">

View File

@ -10,3 +10,7 @@
action="zline"
duration="7d"
reason="Tor exit nodes are not allowed on this network. See https://metrics.torproject.org/rs.html#search/%ip% for more information.">
<dnsblreply name="torexit.dan.me.uk"
reply="100"
description="Tor exit node">

View File

@ -6,27 +6,27 @@
<include file="&dir.example;/services/generic.example.conf">
# Long hand aliases for services pseudoclients.
<alias text="ALIS" replace="SQUERY $requirement :$2-" requires="ALIS" service="yes">
<alias text="CHANFIX" replace="SQUERY $requirement :$2-" requires="ChanFix" service="yes">
<alias text="GAMESERV" replace="SQUERY $requirement :$2-" requires="GameServ" service="yes">
<alias text="GROUPSERV" replace="SQUERY $requirement :$2-" requires="GroupServ" service="yes">
<alias text="HELPSERV" replace="SQUERY $requirement :$2-" requires="HelpServ" service="yes">
<alias text="INFOSERV" replace="SQUERY $requirement :$2-" requires="InfoServ" service="yes">
<alias text="PROXYSCAN" replace="SQUERY $requirement :$2-" requires="Proxyscan" service="yes" operonly="yes">
<alias text="RPGSERV" replace="SQUERY $requirement :$2-" requires="RPGServ" service="yes">
<alias text="ALIS" replace="PRIVMSG $requirement :$2-" requires="ALIS" service="yes">
<alias text="CHANFIX" replace="PRIVMSG $requirement :$2-" requires="ChanFix" service="yes">
<alias text="GAMESERV" replace="PRIVMSG $requirement :$2-" requires="GameServ" service="yes">
<alias text="GROUPSERV" replace="PRIVMSG $requirement :$2-" requires="GroupServ" service="yes">
<alias text="HELPSERV" replace="PRIVMSG $requirement :$2-" requires="HelpServ" service="yes">
<alias text="INFOSERV" replace="PRIVMSG $requirement :$2-" requires="InfoServ" service="yes">
<alias text="PROXYSCAN" replace="PRIVMSG $requirement :$2-" requires="Proxyscan" service="yes" operonly="yes">
<alias text="RPGSERV" replace="PRIVMSG $requirement :$2-" requires="RPGServ" service="yes">
# Short hand aliases for services pseudoclients.
<alias text="CF" replace="SQUERY $requirement :$2-" requires="ChanFix" service="yes">
<alias text="GS" replace="SQUERY $requirement :$2-" requires="GroupServ" service="yes">
<alias text="IS" replace="SQUERY $requirement :$2-" requires="InfoServ" service="yes">
<alias text="LS" replace="SQUERY $requirement :$2-" requires="ALIS" service="yes">
<alias text="PS" replace="SQUERY $requirement :$2-" requires="Proxyscan" service="yes" operonly="yes">
<alias text="RS" replace="SQUERY $requirement :$2-" requires="RPGServ" service="yes">
<alias text="CF" replace="PRIVMSG $requirement :$2-" requires="ChanFix" service="yes">
<alias text="GS" replace="PRIVMSG $requirement :$2-" requires="GroupServ" service="yes">
<alias text="IS" replace="PRIVMSG $requirement :$2-" requires="InfoServ" service="yes">
<alias text="LS" replace="PRIVMSG $requirement :$2-" requires="ALIS" service="yes">
<alias text="PS" replace="PRIVMSG $requirement :$2-" requires="Proxyscan" service="yes" operonly="yes">
<alias text="RS" replace="PRIVMSG $requirement :$2-" requires="RPGServ" service="yes">
# These short hand aliases conflict with other pseudoclients. You can enable
# them but you will need to comment out the uncommented ones above first,
#<alias text="GS" replace="SQUERY $requirement :$2-" requires="GameServ" service="yes">
#<alias text="HS" replace="SQUERY $requirement :$2-" requires="HelpServ" service="yes">
#<alias text="GS" replace="PRIVMSG $requirement :$2-" requires="GameServ" service="yes">
#<alias text="HS" replace="PRIVMSG $requirement :$2-" requires="HelpServ" service="yes">
# Prevent clients from using the nicknames of services pseudoclients.
<badnick nick="ALIS" reason="Reserved for a network service">

View File

@ -4,34 +4,34 @@
<module name="alias">
# Long hand aliases for services pseudoclients.
<alias text="BOTSERV" replace="SQUERY $requirement :$2-" requires="BotServ" service="yes">
<alias text="CHANSERV" replace="SQUERY $requirement :$2-" requires="ChanServ" service="yes">
<alias text="GLOBAL" replace="SQUERY $requirement :$2-" requires="Global" service="yes" operonly="yes">
<alias text="HOSTSERV" replace="SQUERY $requirement :$2-" requires="HostServ" service="yes">
<alias text="MEMOSERV" replace="SQUERY $requirement :$2-" requires="MemoServ" service="yes">
<alias text="NICKSERV" replace="SQUERY $requirement :$2-" requires="NickServ" service="yes">
<alias text="OPERSERV" replace="SQUERY $requirement :$2-" requires="OperServ" service="yes" operonly="yes">
<alias text="STATSERV" replace="SQUERY $requirement :$2-" requires="StatServ" service="yes">
<alias text="BOTSERV" replace="PRIVMSG $requirement :$2-" requires="BotServ" service="yes">
<alias text="CHANSERV" replace="PRIVMSG $requirement :$2-" requires="ChanServ" service="yes">
<alias text="GLOBAL" replace="PRIVMSG $requirement :$2-" requires="Global" service="yes" operonly="yes">
<alias text="HOSTSERV" replace="PRIVMSG $requirement :$2-" requires="HostServ" service="yes">
<alias text="MEMOSERV" replace="PRIVMSG $requirement :$2-" requires="MemoServ" service="yes">
<alias text="NICKSERV" replace="PRIVMSG $requirement :$2-" requires="NickServ" service="yes">
<alias text="OPERSERV" replace="PRIVMSG $requirement :$2-" requires="OperServ" service="yes" operonly="yes">
<alias text="STATSERV" replace="PRIVMSG $requirement :$2-" requires="StatServ" service="yes">
# Short hand aliases for services pseudoclients.
<alias text="BS" replace="SQUERY $requirement :$2-" requires="BotServ" service="yes">
<alias text="CS" replace="SQUERY $requirement :$2-" requires="ChanServ" service="yes">
<alias text="GL" replace="SQUERY $requirement :$2-" requires="Global" service="yes" operonly="yes">
<alias text="HS" replace="SQUERY $requirement :$2-" requires="HostServ" service="yes">
<alias text="MS" replace="SQUERY $requirement :$2-" requires="MemoServ" service="yes">
<alias text="NS" replace="SQUERY $requirement :$2-" requires="NickServ" service="yes">
<alias text="OS" replace="SQUERY $requirement :$2-" requires="OperServ" service="yes" operonly="yes">
<alias text="SS" replace="SQUERY $requirement :$2-" requires="StatServ" service="yes">
<alias text="BS" replace="PRIVMSG $requirement :$2-" requires="BotServ" service="yes">
<alias text="CS" replace="PRIVMSG $requirement :$2-" requires="ChanServ" service="yes">
<alias text="GL" replace="PRIVMSG $requirement :$2-" requires="Global" service="yes" operonly="yes">
<alias text="HS" replace="PRIVMSG $requirement :$2-" requires="HostServ" service="yes">
<alias text="MS" replace="PRIVMSG $requirement :$2-" requires="MemoServ" service="yes">
<alias text="NS" replace="PRIVMSG $requirement :$2-" requires="NickServ" service="yes">
<alias text="OS" replace="PRIVMSG $requirement :$2-" requires="OperServ" service="yes" operonly="yes">
<alias text="SS" replace="PRIVMSG $requirement :$2-" requires="StatServ" service="yes">
# /ID [account] <password>
# Identifies to a services account.
<alias text="ID" format="*" replace="SQUERY $requirement :IDENTIFY $2-" requires="NickServ" service="yes">
<alias text="IDENTIFY" format="*" replace="SQUERY $requirement :IDENTIFY $2-" requires="NickServ" service="yes">
<alias text="LOGIN" format="*" replace="SQUERY $requirement :IDENTIFY $2-" requires="NickServ" service="yes">
<alias text="ID" format="*" replace="PRIVMSG $requirement :IDENTIFY $2-" requires="NickServ" service="yes">
<alias text="IDENTIFY" format="*" replace="PRIVMSG $requirement :IDENTIFY $2-" requires="NickServ" service="yes">
<alias text="LOGIN" format="*" replace="PRIVMSG $requirement :IDENTIFY $2-" requires="NickServ" service="yes">
# /LOGOUT
# Logs out of a services account.
<alias text="LOGOUT" format="*" replace="SQUERY $requirement :LOGOUT" requires="NickServ" service="yes">
<alias text="LOGOUT" format="*" replace="PRIVMSG $requirement :LOGOUT" requires="NickServ" service="yes">
# Prevent clients from using the nicknames of services pseudoclients.
<badnick nick="BotServ" reason="Reserved for a network service">

View File

@ -39,10 +39,12 @@
# include <format>
# define FMT std
# define FMT_PTR(PTR) static_cast<void*>(PTR)
template<typename T> concept fmt_formattable = std::default_initializable<std::formatter<std::remove_cvref_t<T>>>;
#else
# include <fmt/format.h>
# define FMT fmt
# define FMT_PTR(PTR) fmt::ptr(PTR)
template<typename T> concept fmt_formattable = fmt::formattable<T>;
#endif
/**

View File

@ -129,7 +129,7 @@ public:
/** Get the value of an option, using def if it does not exist */
bool getBool(const std::string& key, bool def = false) const;
/** Get the value of an option, using def if it does not exist */
unsigned char getCharacter(const std::string& key, unsigned char def = '\0') const;
unsigned char getCharacter(const std::string& key, unsigned char def = '\0', bool emptynul = false) const;
/** Get the value in seconds of a duration that is in the user-friendly "1h2m3s" format,
* using a default value if it does not exist or is out of bounds.

View File

@ -71,17 +71,26 @@ inline std::string ConvToStr(const bool in)
/** Converts a type that to_string is implemented for to a string.
* @param in The value to convert.
*/
template<typename Stringable>
inline std::enable_if_t<std::is_arithmetic_v<Stringable>, std::string> ConvToStr(const Stringable& in)
template<typename Stringable> requires(std::integral<Stringable> || std::floating_point<Stringable>)
inline std::string ConvToStr(const Stringable& in)
{
return std::to_string(in);
}
/** Converts a type that fmtlib can format to a string.
* @param in The value to convert.
*/
template<typename Formattable> requires(!std::integral<Formattable> && !std::floating_point<Formattable> && fmt_formattable<Formattable>)
inline std::string ConvToStr(const Formattable& in)
{
return FMT::format("{}", in);
}
/** Converts any type to a string.
* @param in The value to convert.
*/
template <class T>
inline std::enable_if_t<!std::is_arithmetic_v<T>, std::string> ConvToStr(const T& in)
template <class T> requires(!std::integral<T> && !std::floating_point<T> && !fmt_formattable<T>)
inline std::string ConvToStr(const T& in)
{
std::stringstream tmp;
if (!(tmp << in))

View File

@ -204,7 +204,7 @@ protected:
*/
Base(Module* mod, const std::string& xbname, ExtBan::Letter xbletter)
: ServiceProvider(mod, xbname, SERVICE_CUSTOM)
, letter(ServerInstance->Config->ConfValue("extbans")->getCharacter(xbname, xbletter))
, letter(ServerInstance->Config->ConfValue("extbans")->getCharacter(xbname, xbletter, true))
, manager(mod, "extbanmanager")
{
}

View File

@ -39,8 +39,11 @@ enum
ERR_UNKNOWNCOMMAND = 421,
ERR_NONICKNAMEGIVEN = 431,
ERR_ERRONEUSNICKNAME = 432,
ERR_NICKNAMEINUSE = 433,
ERR_USERNOTINCHANNEL = 441,
ERR_NOTONCHANNEL = 442,
ERR_NOTREGISTERED = 451,
ERR_NEEDMOREPARAMS = 461,
ERR_YOUREBANNEDCREEP = 465,
ERR_UNKNOWNMODE = 472,
ERR_BANNEDFROMCHAN = 474,
@ -58,11 +61,17 @@ enum
// From irc2?
RPL_SAVENICK = 43,
// From ircu.
RPL_YOURDISPLAYEDHOST = 396,
// From UnrealIRCd.
ERR_CANTCHANGENICK = 447,
// InspIRCd-specific.
ERR_UNKNOWNSNOMASK = 501,
RPL_SYNTAX = 650,
ERR_LISTMODEALREADYSET = 697,
ERR_LISTMODENOTSET = 698,
ERR_CANTUNLOADMODULE = 972,
RPL_UNLOADEDMODULE = 973,
ERR_CANTLOADMODULE = 974,

View File

@ -63,11 +63,22 @@ namespace Time
{
/** Converts a UNIX timestamp to a time string.
*
* e.g.
* @param ts The timestamp to convert to a string.
* @param format A snprintf format string to output the timestamp in.
* @param utc If the timestamp is a UTC timestamp then true or false if the
* timestamp is a local timestamp.
*/
CoreExport std::string ToString(time_t ts, const char* format = nullptr, bool utc = false);
/** Converts a duration from now to a time string.
*
* @param duration The duration from now to convert to a string.
* @param format A snprintf format string to output the timestamp in.
* @param utc If the timestamp is a UTC timestamp then true or false if the
* timestamp is a local timestamp.
*/
inline std::string FromNow(unsigned long duration, const char* format = nullptr, bool utc = false)
{
return ToString(ServerInstance->Time() + duration, format, utc);
}
}

View File

@ -140,6 +140,9 @@ public:
*/
void RehashCloneCounts();
/** Rebuilds the list of services servers. Required when \<services> settings change. */
void RehashServices();
/** Return the number of local and global clones of this user
* @param user The user to get the clone counts for
* @return The clone counts of this user. The returned reference is volatile - you
@ -171,7 +174,7 @@ public:
/** Return a count of fully connected connections on the network.
* @return The number of fully connected users on the network.
*/
size_t GlobalUserCount() const { return this->clientlist.size() - this->UnknownUserCount() - this->ServiceCount(); }
size_t GlobalUserCount() const { return this->clientlist.size() - this->UnknownUserCount(); }
/** Get a hash map containing all users, keyed by their nickname
* @return A hash map mapping nicknames to User pointers

View File

@ -179,7 +179,7 @@ non-interactive configuration is started and any omitted values are defaulted.
<|BOLD INSPIRCD_VERBOSE=<0|1>|> Shows additional information for debugging.
If you have any problems with configuring InspIRCd then visit our IRC channel
at irc.chatspike.net #InspIRCd or create a support discussion at
at ircs://irc.teranova.net/inspircd or create a support discussion at
https://github.com/inspircd/inspircd/discussions.
Packagers: see https://docs.inspircd.org/packaging/ for packaging advice.

View File

@ -161,8 +161,8 @@ sub __error {
push @message, '';
push @message, 'If you would like help with fixing this problem then visit our IRC';
push @message, 'channel at irc.chatspike.net #InspIRCd or create a support discussion';
push @message, 'at https://github.com/inspircd/inspircd/discussions.';
push @message, 'channel at ircs://irc.teranova.net/inspircd or create a support';
push @message, 'discussion at https://github.com/inspircd/inspircd/discussions.';
push @message, '';
print_error @message;

View File

@ -4,8 +4,8 @@ In order to get your server running you need to create config files. Examples
can be found at `@EXAMPLE_DIR@`.
If you need any help with this then you can visit our support channel at
irc.chatspike.net #inspircd, open a support discussion at https://git.io/JIuYv,
or refer to the the docs site:
ircs://irc.teranova.net/inspircd, open a support discussion at
https://git.io/JIuYv, or refer to the the docs site:
https://docs.inspircd.org/@VERSION_MAJOR@/configuration
https://docs.inspircd.org/@VERSION_MAJOR@/modules

View File

@ -41,6 +41,6 @@ The TCP port to connect to.
Disables checking whether the server certificate is signed by a Certificate Authority.
.SH "SUPPORT"
IRC support for InspIRCd can be found at ircs://irc.chatspike.net/inspircd.
IRC support for InspIRCd can be found at ircs://irc.teranova.net/inspircd.
Bug reports and feature requests can be filed at https://github.com/inspircd/inspircd/issues.

View File

@ -61,6 +61,6 @@ Allow the server to start as root (not recommended).
Displays the InspIRCd version and exits.
.SH "SUPPORT"
IRC support for InspIRCd can be found at ircs://irc.chatspike.net/inspircd.
IRC support for InspIRCd can be found at ircs://irc.teranova.net/inspircd.
Bug reports and feature requests can be filed at https://github.com/inspircd/inspircd/issues.

View File

@ -141,7 +141,17 @@ public:
bool IsMatch(User* user, Channel* channel, const std::string& text) override
{
const std::string* account = accountapi.GetAccountName(user);
const auto* nicks = accountapi.GetAccountNicks(user);
if (nicks)
{
for (const auto& nick : *nicks)
{
if (InspIRCd::Match(nick, text))
return true;
}
}
const auto* account = accountapi.GetAccountName(user);
return account && InspIRCd::Match(*account, text);
}
};

View File

@ -144,7 +144,7 @@ public:
{
ServerInstance->SNO.WriteToSnoMask('x', "{} added a timed CBan on {}, expires in {} (on {}): {}",
user->nick, parameters[0], Duration::ToString(duration),
Time::ToString(ServerInstance->Time() + duration), reason);
Time::FromNow(duration), reason);
}
}
else

View File

@ -75,7 +75,7 @@ public:
auto* c = ServerInstance->Channels.Find(channel);
if (c)
{
ClientProtocol::Messages::Privmsg privmsg(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->Config->ServerName, c, snotice);
ClientProtocol::Messages::Privmsg privmsg(ClientProtocol::Messages::Privmsg::nocopy, ServerInstance->FakeClient, c, snotice);
c->Write(ServerInstance->GetRFCEvents().privmsg, privmsg);
ServerInstance->PI->SendMessage(c, 0, snotice);
}

View File

@ -100,7 +100,7 @@ public:
ipv4_cidr = tag->getNum<unsigned int>("ipv4cidr", ServerInstance->Config->IPv4Range, 1, 32);
ipv6_cidr = tag->getNum<unsigned int>("ipv6cidr", ServerInstance->Config->IPv6Range, 1, 128);
threshold = tag->getNum<unsigned long>("threshold", 10, 1);
threshold = tag->getNum<unsigned long>("threshold", 10, 2);
bootwait = tag->getDuration("bootwait", 60*2);
splitwait = tag->getDuration("splitwait", 60*2);
banduration = tag->getDuration("banduration", 6*60*60, 1);

View File

@ -22,15 +22,20 @@
void ExtBanManager::AddExtBan(ExtBan::Base* extban)
{
auto lit = byletter.emplace(extban->GetLetter(), extban);
if (!lit.second)
throw ModuleException(creator, FMT::format("ExtBan letter \"{}\" is already in use by the {} extban from {}",
extban->GetLetter(), lit.first->second->GetName(), lit.first->second->creator->ModuleFile));
if (extban->GetLetter())
{
auto lit = byletter.emplace(extban->GetLetter(), extban);
if (!lit.second)
throw ModuleException(creator, FMT::format("ExtBan letter \"{}\" is already in use by the {} extban from {}",
extban->GetLetter(), lit.first->second->GetName(), lit.first->second->creator->ModuleFile));
}
auto nit = byname.emplace(extban->GetName(), extban);
if (!nit.second)
{
byletter.erase(extban->GetLetter());
if (extban->GetLetter())
byletter.erase(extban->GetLetter());
throw ModuleException(creator, FMT::format("ExtBan name \"{}\" is already in use by the {} extban from {}",
extban->GetName(), nit.first->second->GetLetter(), nit.first->second->creator->ModuleFile));
}
@ -63,7 +68,10 @@ bool ExtBanManager::Canonicalize(std::string& text) const
break;
case ExtBan::Format::LETTER:
text.append(1, extban->GetLetter());
if (extban->GetLetter())
text.push_back(extban->GetLetter());
else
text.append(extban->GetName()); // ExtBan has no letter.
break;
default:
@ -153,9 +161,12 @@ ModResult ExtBanManager::GetStatus(ExtBan::ActingBase* extban, User* user, Chann
void ExtBanManager::DelExtBan(ExtBan::Base* extban)
{
auto lit = byletter.find(extban->GetLetter());
if (lit != byletter.end() && lit->second->creator.ptr() == extban->creator.ptr())
byletter.erase(lit);
if (extban->GetLetter())
{
auto lit = byletter.find(extban->GetLetter());
if (lit != byletter.end() && lit->second->creator.ptr() == extban->creator.ptr())
byletter.erase(lit);
}
auto nit = byname.find(extban->GetName());
if (nit != byname.end() && nit->second->creator.ptr() == extban->creator.ptr())

View File

@ -27,6 +27,14 @@
#include "inspircd.h"
#include "modules/isupport.h"
enum class ShowModes
: uint8_t
{
NOBODY,
OPERS,
ALL,
};
class CommandList final
: public Command
{
@ -48,7 +56,7 @@ private:
public:
// Whether to show modes in the LIST response.
bool showmodes;
ShowModes showmodes;
CommandList(Module* parent)
: Command(parent, "LIST")
@ -129,6 +137,7 @@ CmdResult CommandList::Handle(User* user, const Params& parameters)
}
const bool has_privs = user->HasPrivPermission("channels/auspex");
const bool show_modes = (showmodes == ShowModes::ALL) || (showmodes == ShowModes::OPERS && has_privs);
user->WriteNumeric(RPL_LISTSTART, "Channel", "Users Name");
@ -168,7 +177,7 @@ CmdResult CommandList::Handle(User* user, const Params& parameters)
// Channel is private (+p) and user is outside/not privileged
user->WriteNumeric(RPL_LIST, '*', users, "");
}
else if (showmodes)
else if (show_modes)
{
// Show the list response with the modes and topic.
user->WriteNumeric(RPL_LIST, chan->name, users, FMT::format("[+{}] {}", chan->ChanModes(n), chan->topic));
@ -203,7 +212,11 @@ public:
void ReadConfig(ConfigStatus& status) override
{
const auto& tag = ServerInstance->Config->ConfValue("options");
cmd.showmodes = tag->getBool("modesinlist");
cmd.showmodes = tag->getEnum("showmodes", ShowModes::OPERS, {
{ "no", ShowModes::NOBODY },
{ "opers", ShowModes::OPERS },
{ "yes", ShowModes::ALL },
});
}
void OnBuildISupport(ISupport::TokenMap& tokens) override

View File

@ -50,7 +50,7 @@ struct LusersCounters final
{
for (const auto& [_, u] : ServerInstance->Users.GetUsers())
{
if (!u->server->IsService() && u->IsModeSet(invisiblemode))
if (u->IsModeSet(invisiblemode))
invisible++;
}
}
@ -135,9 +135,6 @@ public:
if (!dest->IsFullyConnected())
return;
if (dest->server->IsService())
return;
if (change.adding)
invisible++;
else
@ -166,13 +163,13 @@ public:
void OnPostConnect(User* user) override
{
counters.UpdateMaxUsers();
if (!user->server->IsService() && user->IsModeSet(invisiblemode))
if (user->IsModeSet(invisiblemode))
counters.invisible++;
}
void OnUserQuit(User* user, const std::string& message, const std::string& oper_message) override
{
if (!user->server->IsService() && user->IsModeSet(invisiblemode))
if (user->IsModeSet(invisiblemode))
counters.invisible--;
}
};

View File

@ -83,7 +83,7 @@ CmdResult CommandEline::Handle(User* user, const Params& parameters)
{
ServerInstance->SNO.WriteToSnoMask('x', "{} added a timed E-line on {}, expires in {} (on {}): {}",
user->nick, target, Duration::ToString(duration),
Time::ToString(ServerInstance->Time() + duration), parameters[2]);
Time::FromNow(duration), parameters[2]);
}
}
else

View File

@ -90,7 +90,7 @@ CmdResult CommandGline::Handle(User* user, const Params& parameters)
{
ServerInstance->SNO.WriteToSnoMask('x', "{} added a timed G-line on {}, expires in {} (on {}): {}",
user->nick, target, Duration::ToString(duration),
Time::ToString(ServerInstance->Time() + duration), parameters[2]);
Time::FromNow(duration), parameters[2]);
}
ServerInstance->XLines->ApplyLines();

View File

@ -90,7 +90,7 @@ CmdResult CommandKline::Handle(User* user, const Params& parameters)
{
ServerInstance->SNO.WriteToSnoMask('x', "{} added a timed K-line on {}, expires in {} (on {}): {}",
user->nick, target, Duration::ToString(duration),
Time::ToString(ServerInstance->Time() + duration), parameters[2]);
Time::FromNow(duration), parameters[2]);
}
ServerInstance->XLines->ApplyLines();

View File

@ -72,7 +72,7 @@ CmdResult CommandQline::Handle(User* user, const Params& parameters)
{
ServerInstance->SNO.WriteToSnoMask('x', "{} added a timed Q-line on {}, expires in {} (on {}): {}",
user->nick, parameters[0], Duration::ToString(duration),
Time::ToString(ServerInstance->Time() + duration), parameters[2]);
Time::FromNow(duration), parameters[2]);
}
ServerInstance->XLines->ApplyLines();
}

View File

@ -89,7 +89,7 @@ CmdResult CommandZline::Handle(User* user, const Params& parameters)
{
ServerInstance->SNO.WriteToSnoMask('x', "{} added a timed Z-line on {}, expires in {} (on {}): {}",
user->nick, ipaddr, Duration::ToString(duration),
Time::ToString(ServerInstance->Time() + duration), parameters[2]);
Time::FromNow(duration), parameters[2]);
}
ServerInstance->XLines->ApplyLines();
}

View File

@ -96,6 +96,9 @@ public:
// A range of DNSBL result types to match against.
CharState records;
// A map of DNSBL replies to their descriptions.
insp::flat_map<uint32_t, std::string> replies;
// The message to send to users who's IP address is in a DNSBL.
std::string reason;
@ -365,12 +368,16 @@ public:
if (match)
{
const auto it = config->replies.find(result);
const auto reasonstr = it == config->replies.end() ? FMT::format("Result {}", result) : it->second;
const std::string reason = Template::Replace(config->reason, {
{ "dnsbl", config->name },
{ "dnsbl.url", Percent::Encode(config->name) },
{ "ip", them->GetAddress() },
{ "network", ServerInstance->Config->Network },
{ "network.url", Percent::Encode(ServerInstance->Config->Network) },
{ "reason", reasonstr },
{ "result", ConvToStr(result) },
});
@ -421,9 +428,9 @@ public:
}
}
ServerInstance->SNO.WriteGlobalSno('d', "{} {} ({}) detected as being on the '{}' DNSBL with result {}{}",
ServerInstance->SNO.WriteGlobalSno('d', "{} {} ({}) detected as being on the '{}' DNSBL: {}{}",
them->IsFullyConnected() ? "User" : "Connecting user", them->GetRealMask(), them->GetAddress(),
config->name, result, them->exempt ? " -- exempt" : "");
config->name, reasonstr, them->exempt ? " -- exempt" : "");
}
else
config->stats_misses++;
@ -594,6 +601,30 @@ public:
auto entry = std::make_shared<DNSBLEntry>(this, tag);
newdnsbls.push_back(entry);
}
for (const auto& [_, tag] : ServerInstance->Config->ConfTags("dnsblreply"))
{
const auto dnsblname = tag->getString("name");
auto dnsbl = std::find_if(newdnsbls.begin(), newdnsbls.end(), [&dnsblname](const auto& d)
{
return insp::equalsci(d->name, dnsblname);
});
if (dnsbl == newdnsbls.end())
throw ModuleException(this, "<dnsblreply:name> must be set to the name of a DNSBL at " + tag->source.str());
const auto dnsbldesc = tag->getString("description");
if (dnsbldesc.empty())
throw ModuleException(this, "<dnsblreply:description> must not be empty at " + tag->source.str());
const auto dnsblreply = tag->getNum<uint32_t>("reply", std::numeric_limits<uint32_t>::max());
if (dnsblreply > 16'777'215)
{
throw ModuleException(this, FMT::format("<dnsblreply:reply> ({}) is not a valid DNSBL reply at {}",
dnsblreply, tag->source.str()));
}
(*dnsbl)->replies[dnsblreply] = dnsbldesc;
}
data.dnsbls.swap(newdnsbls);
}

View File

@ -85,7 +85,7 @@ public:
bool flag_strip_color;
bool flag_no_registered;
FilterResult(Regex::EngineReference& RegexEngine, const std::string& free, const std::string& rea, FilterAction act, unsigned long gt, const std::string& fla, bool cfg)
FilterResult(Regex::EngineReference& RegexEngine, const std::string& free, const std::string& rea, FilterAction act, unsigned long gt, const std::string& fla, bool cfg, bool ef)
: freeform(free)
, reason(rea)
, action(act)
@ -94,7 +94,7 @@ public:
{
if (!RegexEngine)
throw ModuleException(thismod, "Regex module implementing '"+RegexEngine.GetProvider()+"' is not loaded!");
regex = RegexEngine->Create(free);
regex = ef ? RegexEngine->CreateHuman(free) : RegexEngine->Create(free);
this->FillFlags(fla);
}
@ -202,6 +202,7 @@ private:
Account::API accountapi;
bool initing = true;
bool enableflags;
bool notifyuser;
bool warnonselfmsg;
bool dirty = false;
@ -233,6 +234,7 @@ public:
bool DeleteFilter(const std::string& freeform, std::string& reason);
std::pair<bool, std::string> AddFilter(const std::string& freeform, FilterAction type, const std::string& reason, unsigned long duration, const std::string& flags, bool config = false);
void ReadConfig(ConfigStatus& status) override;
void CompareLinkData(const LinkData& otherdata, LinkDataDiff& diffs) override;
void GetLinkData(LinkData& data) override;
static std::string EncodeFilter(const FilterResult& filter);
FilterResult DecodeFilter(const std::string& data);
@ -471,7 +473,7 @@ ModResult ModuleFilter::OnUserPreMessage(User* user, MessageTarget& msgtarget, M
auto* sh = new Shun(ServerInstance->Time(), f->duration, MODNAME "@" + ServerInstance->Config->ServerName, f->reason, user->GetAddress());
ServerInstance->SNO.WriteGlobalSno('f', "{} ({}) was shunned for {} (expires on {}) because their message to {} matched {} ({})",
user->nick, sh->Displayable(), Duration::ToString(f->duration),
Time::ToString(ServerInstance->Time() + f->duration),
Time::FromNow(f->duration),
msgtarget.GetName(), f->freeform, f->reason);
if (ServerInstance->XLines->AddLine(sh, nullptr))
{
@ -485,7 +487,7 @@ ModResult ModuleFilter::OnUserPreMessage(User* user, MessageTarget& msgtarget, M
auto* gl = new GLine(ServerInstance->Time(), f->duration, MODNAME "@" + ServerInstance->Config->ServerName, f->reason, "*", user->GetAddress());
ServerInstance->SNO.WriteGlobalSno('f', "{} ({}) was G-lined for {} (expires on {}) because their message to {} matched {} ({})",
user->nick, gl->Displayable(), Duration::ToString(f->duration),
Time::ToString(ServerInstance->Time() + f->duration),
Time::FromNow(f->duration),
msgtarget.GetName(), f->freeform, f->reason);
if (ServerInstance->XLines->AddLine(gl, nullptr))
{
@ -499,7 +501,7 @@ ModResult ModuleFilter::OnUserPreMessage(User* user, MessageTarget& msgtarget, M
auto* zl = new ZLine(ServerInstance->Time(), f->duration, MODNAME "@" + ServerInstance->Config->ServerName, f->reason, user->GetAddress());
ServerInstance->SNO.WriteGlobalSno('f', "{} ({}) was Z-lined for {} (expires on {}) because their message to {} matched {} ({})",
user->nick, zl->Displayable(), Duration::ToString(f->duration),
Time::ToString(ServerInstance->Time() + f->duration),
Time::FromNow(f->duration),
msgtarget.GetName(), f->freeform, f->reason);
if (ServerInstance->XLines->AddLine(zl, nullptr))
{
@ -577,7 +579,7 @@ ModResult ModuleFilter::OnPreCommand(std::string& command, CommandBase::Params&
ServerInstance->SNO.WriteGlobalSno('f', "{} ({}) was G-lined for {} (expires on {}) because their {} message matched {} ({})",
user->nick, gl->Displayable(),
Duration::ToString(f->duration),
Time::ToString(ServerInstance->Time() + f->duration),
Time::FromNow(f->duration),
command, f->freeform, f->reason);
if (ServerInstance->XLines->AddLine(gl, nullptr))
@ -593,7 +595,7 @@ ModResult ModuleFilter::OnPreCommand(std::string& command, CommandBase::Params&
ServerInstance->SNO.WriteGlobalSno('f', "{} ({}) was Z-lined for {} (expires on {}) because their {} message matched {} ({})",
user->nick, zl->Displayable(),
Duration::ToString(f->duration),
Time::ToString(ServerInstance->Time() + f->duration),
Time::FromNow(f->duration),
command, f->freeform, f->reason);
if (ServerInstance->XLines->AddLine(zl, nullptr))
@ -610,7 +612,7 @@ ModResult ModuleFilter::OnPreCommand(std::string& command, CommandBase::Params&
ServerInstance->SNO.WriteGlobalSno('f', "{} ({}) was shunned for {} (expires on {}) because their {} message matched {} ({})",
user->nick, sh->Displayable(),
Duration::ToString(f->duration),
Time::ToString(ServerInstance->Time() + f->duration),
Time::FromNow(f->duration),
command, f->freeform, f->reason);
if (ServerInstance->XLines->AddLine(sh, nullptr))
@ -645,6 +647,7 @@ void ModuleFilter::ReadConfig(ConfigStatus& status)
const auto& tag = ServerInstance->Config->ConfValue("filteropts");
std::string newrxengine = tag->getString("engine");
enableflags = tag->getBool("enableflags");
notifyuser = tag->getBool("notifyuser", true);
warnonselfmsg = tag->getBool("warnonselfmsg");
filterconf = tag->getString("filename");
@ -680,12 +683,29 @@ void ModuleFilter::ReadConfig(ConfigStatus& status)
ReadFilters();
}
void ModuleFilter::CompareLinkData(const LinkData& otherdata, LinkDataDiff& diffs)
{
Module::CompareLinkData(otherdata, diffs);
auto it = diffs.find("flags");
if (it == diffs.end())
return; // Should never happen.
if (!it->second.first)
it->second.first = "no";
if (!it->second.second)
it->second.second = "no";
}
void ModuleFilter::GetLinkData(LinkData& data)
{
if (RegexEngine)
data["regex"] = RegexEngine->GetName(); // e.g. pcre
else
data["regex"] = "broken";
if (enableflags)
data["flags"] = "yes";
}
std::string ModuleFilter::EncodeFilter(const FilterResult& filter)
@ -812,7 +832,7 @@ std::pair<bool, std::string> ModuleFilter::AddFilter(const std::string& freeform
try
{
filters.emplace_back(RegexEngine, freeform, reason, type, duration, flgs, config);
filters.emplace_back(RegexEngine, freeform, reason, type, duration, flgs, config, enableflags);
dirty = true;
}
catch (const ModuleException& e)

View File

@ -45,10 +45,7 @@ private:
// Check whether a module zapped the message tags.
if (msgdetails.tags_out.empty())
{
source->WriteNumeric(ERR_NOTEXTTOSEND, "No tags to send");
return false;
}
// Inform modules that a TAGMSG is about to be sent.
tagevprov.Call(&CTCTags::EventListener::OnUserTagMessage, source, msgtarget, msgdetails);

View File

@ -118,7 +118,7 @@ static bool WriteDatabase(PermChannel& permchanmode, bool save_listmodes)
{
if (entry != list->begin())
stream << ' ';
stream << entry->mask << ' ' << entry->setter << ' ' << entry->time;
stream << ServerConfig::Escape(entry->mask) << ' ' << ServerConfig::Escape(entry->setter) << ' ' << entry->time;
}
stream << "\"" << std::endl;
}

View File

@ -83,7 +83,8 @@ public:
// channel does not yet exist (record is null, about to be created IF we were to allow it)
if (!override && !chan && !CanCreateChannel(user, cname))
{
user->WriteNumeric(ERR_RESTRICTED, cname, "You are not allowed to create new channels.");
const auto* reason = allowregistered ? "logged into an account" : "a server operator";
user->WriteNumeric(ERR_RESTRICTED, cname, FMT::format("You must be {} to create new channels.", reason));
return MOD_RES_DENY;
}

View File

@ -182,7 +182,7 @@ public:
{
ServerInstance->SNO.WriteToSnoMask('x', "{} added a timed R-line on {}, expires in {} (on {}): {}",
user->nick, parameters[0], Duration::ToString(duration),
Time::ToString(ServerInstance->Time() + duration), parameters[2]);
Time::FromNow(duration), parameters[2]);
}
ServerInstance->XLines->ApplyLines();

View File

@ -129,7 +129,7 @@ public:
{
ServerInstance->SNO.WriteToSnoMask('x', "{} added a timed SHUN on {}, expires in {} (on {}): {}",
user->nick, target, Duration::ToString(duration),
Time::ToString(ServerInstance->Time() + duration), expr);
Time::FromNow(duration), expr);
}
}
else

View File

@ -284,8 +284,8 @@ bool TreeSocket::BuildExtBanList(std::string& out)
if (!extbanmgr)
return false;
const ExtBan::Manager::LetterMap& extbans = extbanmgr->GetLetterMap();
for (ExtBan::Manager::LetterMap::const_iterator iter = extbans.begin(); iter != extbans.end(); ++iter)
const auto& extbans = extbanmgr->GetNameMap();
for (auto iter = extbans.begin(); iter != extbans.end(); ++iter)
{
if (iter != extbans.begin())
out.push_back(' ');
@ -301,9 +301,9 @@ bool TreeSocket::BuildExtBanList(std::string& out)
break;
}
out.append(extban->GetName())
.append("=")
.push_back(extban->GetLetter());
out.append(extban->GetName());
if (extban->GetLetter())
out.append("=").push_back(extban->GetLetter());
}
return true;
}

View File

@ -28,6 +28,7 @@
#include "inspircd.h"
#include "extension.h"
#include "modules/ssl.h"
#include "modules/stats.h"
#include "modules/webirc.h"
#include "modules/who.h"
#include "modules/whois.h"
@ -305,9 +306,10 @@ public:
class ModuleSSLInfo final
: public Module
, public Stats::EventListener
, public WebIRC::EventListener
, public Whois::EventListener
, public Who::EventListener
, public Whois::EventListener
{
private:
CommandSSLInfo cmd;
@ -333,9 +335,10 @@ private:
public:
ModuleSSLInfo()
: Module(VF_VENDOR, "Adds user facing TLS information, various TLS configuration options, and the /SSLINFO command to look up TLS certificate information for other users.")
, Stats::EventListener(this)
, WebIRC::EventListener(this)
, Whois::EventListener(this)
, Who::EventListener(this)
, Whois::EventListener(this)
, cmd(this)
{
}
@ -486,6 +489,46 @@ public:
return MOD_RES_PASSTHRU;
}
ModResult OnStats(Stats::Context& stats) override
{
if (stats.GetSymbol() != 't')
return MOD_RES_PASSTHRU;
// Counter for the number of users using each ciphersuite.
std::map<std::string, size_t> counts;
auto& plaintext = counts["Plain text"];
auto& unknown = counts["Unknown"];
for (auto* user : ServerInstance->Users.GetLocalUsers())
{
const auto* ssliohook = SSLIOHook::IsSSL(&user->eh);
if (!ssliohook)
{
plaintext++;
continue;
}
std::string ciphersuite;
ssliohook->GetCiphersuite(ciphersuite);
if (ciphersuite.empty())
unknown++;
else
counts[ciphersuite]++;
}
for (const auto& [ciphersuite, count] : counts)
{
if (!count)
continue;
stats.AddGenericRow(FMT::format("{}: {}", ciphersuite, count))
.AddTags(stats, {
{ "ciphersuite", ciphersuite },
{ "count", ConvToStr(count) },
});
}
return MOD_RES_DENY;
}
void OnWebIRCAuth(LocalUser* user, const WebIRC::FlagMap* flags) override
{
// We are only interested in connection flags. If none have been

View File

@ -29,6 +29,7 @@
#include <fstream>
#include "inspircd.h"
#include "timeutils.h"
#include "xline.h"
class ModuleXLineDB final
@ -241,12 +242,23 @@ public:
XLine* xl = xlf->Generate(ServerInstance->Time(), ConvToNum<unsigned long>(command_p[5]), command_p[3], command_p[6], command_p[2]);
xl->SetCreateTime(ConvToNum<time_t>(command_p[4]));
if (ServerInstance->XLines->AddLine(xl, nullptr))
if (!ServerInstance->XLines->AddLine(xl, nullptr))
{
ServerInstance->SNO.WriteToSnoMask('x', "database: Added a line of type {}", command_p[1]);
continue;
delete xl;
}
if (xl->duration)
{
ServerInstance->SNO.WriteToSnoMask('x', "database: added a timed {}{} on {}, expires in {} (on {}): {}",
xl->type, xl->type.length() <= 2 ? "-line" : "", xl->Displayable(),
Duration::ToString(xl->duration), Time::FromNow(xl->duration), xl->reason);
}
else
delete xl;
{
ServerInstance->SNO.WriteToSnoMask('x', "database: added a permanent {}{} on {}: {}", xl->type,
xl->type.length() <= 2 ? "-line" : "", xl->Displayable(), xl->reason);
}
}
}
stream.close();

View File

@ -26,16 +26,6 @@
#include "inspircd.h"
enum
{
// From RFC 1459.
ERR_NOTREGISTERED = 451,
ERR_NEEDMOREPARAMS = 461,
// InspIRCd-specific.
RPL_SYNTAX = 650,
};
bool CommandParser::LoopCall(User* user, Command* handler, const CommandBase::Params& parameters, unsigned int splithere, int extra, bool usemax)
{
if (splithere >= parameters.size())

View File

@ -732,12 +732,15 @@ bool ConfigTag::getBool(const std::string& key, bool def) const
return def;
}
unsigned char ConfigTag::getCharacter(const std::string& key, unsigned char def) const
unsigned char ConfigTag::getCharacter(const std::string& key, unsigned char def, bool emptynul) const
{
std::string result;
if (!readString(key, result) || result.size() != 1)
if (!readString(key, result))
return def;
if (result.size() != 1)
return result.empty() && emptynul ? 0 : def;
return result[0];
}

View File

@ -723,6 +723,7 @@ void ConfigReaderThread::OnStop()
// The description of this server may have changed - update it for WHOIS etc.
ServerInstance->FakeClient->server->description = Config->ServerDesc;
ServerInstance->Users.RehashServices();
try
{

View File

@ -23,13 +23,6 @@
#include "inspircd.h"
#include "listmode.h"
enum
{
// InspIRCd-specific.
ERR_LISTMODEALREADYSET = 697,
ERR_LISTMODENOTSET = 698,
};
ListModeBase::ListModeBase(Module* Creator, const std::string& Name, char modechar, unsigned int lnum, unsigned int eolnum)
: ModeHandler(Creator, Name, modechar, PARAM_ALWAYS, MODETYPE_CHANNEL, MC_LIST)
, listnumeric(lnum)

View File

@ -350,6 +350,17 @@ void UserManager::RehashCloneCounts()
AddClone(u);
}
void UserManager::RehashServices()
{
UserManager::ServiceList newservices;
for (const auto& [_, user] : ServerInstance->Users.GetUsers())
{
if (user->server->IsService())
newservices.push_back(user);
}
std::swap(ServerInstance->Users.all_services, newservices);
}
const UserManager::CloneCounts& UserManager::GetCloneCounts(User* user) const
{
CloneMap::const_iterator it = clonemap.find(user->GetCIDRMask());

View File

@ -33,15 +33,6 @@
#include "utility/string.h"
#include "xline.h"
enum
{
// From RFC 1459.
ERR_NICKNAMEINUSE = 433,
// From ircu.
RPL_YOURDISPLAYEDHOST = 396,
};
ClientProtocol::MessageList LocalUser::sendmsglist;
bool User::IsNoticeMaskSet(unsigned char sm) const

View File

@ -158,5 +158,5 @@ print(textwrap.dedent(f"""
openssl s_client -connect {hostip}:{port} -debug -security_debug
If you need any help working out what is wrong then visit our support channel
at irc.chatspike.net #inspircd.
at ircs://irc.teranova.net/inspircd.
""").strip())

View File

@ -10,10 +10,10 @@ argon2/20190702
libmysqlclient/8.1.0
libpq/15.5
libpsl/0.21.1
## openssl/3.2.2
## openssl/3.3.2
pcre2/10.44
re2/20240702
sqlite3/3.46.0
sqlite3/3.47.0
yyjson/0.10.0
[options]