From 1608b0e70eccd97485af83cf5c80b4e09e95ba93 Mon Sep 17 00:00:00 2001 From: David Schultz Date: Thu, 18 May 2023 14:44:23 -0500 Subject: [PATCH] m_shedding: user shedding module based on oftc-hybrid --- doc/reference.conf | 1 + extensions/Makefile.am | 1 + extensions/m_shedding.c | 176 ++++++++++++++++++++++++++++++++++++++++ help/opers/shedding | 9 ++ 4 files changed, 187 insertions(+) create mode 100644 extensions/m_shedding.c create mode 100644 help/opers/shedding diff --git a/doc/reference.conf b/doc/reference.conf index a68379a4..9df3494c 100644 --- a/doc/reference.conf +++ b/doc/reference.conf @@ -479,6 +479,7 @@ privset "local_op" { * usermode:helpops allows setting +h (from extensions/helpops) * auspex:usertimes: * allows viewing user idle/connect times even when +I is set (from extensions/umode_hide_idle_time) + * oper:shedding: allows the SHEDDING command (from extensions/m_shedding) */ privs = oper:general, oper:privs, oper:testline, oper:kill, oper:operwall, oper:message, usermode:servnotice, auspex:oper, auspex:hostname, auspex:umodes, auspex:cmodes; diff --git a/extensions/Makefile.am b/extensions/Makefile.am index e404a9ee..4ab221fa 100644 --- a/extensions/Makefile.am +++ b/extensions/Makefile.am @@ -55,6 +55,7 @@ extension_LTLIBRARIES = \ m_omode.la \ m_opme.la \ m_sendbans.la \ + m_shedding.la \ m_webirc.la \ m_remove.la \ hide_uncommon_channels.la \ diff --git a/extensions/m_shedding.c b/extensions/m_shedding.c new file mode 100644 index 00000000..a5cdc19d --- /dev/null +++ b/extensions/m_shedding.c @@ -0,0 +1,176 @@ +/* + * Solanum: a slightly advanced ircd + * shedding.c: Enables/disables user shedding. + * + * Based on oftc-hybrid's m_shedding.c + * + * Copyright (C) 2021 David Schultz + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * + */ + +#include "stdinc.h" +#include "modules.h" +#include "hook.h" +#include "client.h" +#include "ircd.h" +#include "send.h" +#include "s_conf.h" +#include "s_serv.h" +#include "s_newconf.h" +#include "messages.h" +#include "numeric.h" + +#define SHED_RATE_MIN 5 + +static struct ev_entry *user_shedding_ev = NULL; + +static const char shed_desc[] = "Enables/disables user shedding."; + +static void mo_shedding(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]); +static void me_shedding(struct MsgBuf *msgbuf, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]); +static void do_user_shedding(void *unused); + +static struct Message shedding_msgtab = { + "SHEDDING", 0, 0, 0, 0, + {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_shedding, 2}, {mo_shedding, 3}} +}; + +mapi_clist_av1 shedding_clist[] = { &shedding_msgtab, NULL }; + +static void +moddeinit(void) +{ + rb_event_delete(user_shedding_ev); +} + +DECLARE_MODULE_AV2(shed, NULL, moddeinit, shedding_clist, NULL, NULL, NULL, NULL, shed_desc); + +static void +set_shedding_state(struct Client *source_p, const char *chr, const char *reason) +{ + int rate; + if (irccmp(chr, "OFF") == 0) + { + // disable shedding + sendto_realops_snomask(SNO_GENERAL, L_ALL | L_NETWIDE, "%s disabled user shedding", get_oper_name(source_p)); + rb_event_delete(user_shedding_ev); + user_shedding_ev = NULL; + return; + } + + rate = atoi(chr); + + if(rate < SHED_RATE_MIN) + { + sendto_one_notice(source_p, "Shedding rate must be at least %d", SHED_RATE_MIN); + return; + } + + sendto_realops_snomask(SNO_GENERAL, L_ALL | L_NETWIDE, "%s enabled user shedding (interval: %d seconds, reason: %s)", + get_oper_name(source_p), rate, reason); + + rb_event_delete(user_shedding_ev); + user_shedding_ev = NULL; + user_shedding_ev = rb_event_add("user shedding event", do_user_shedding, NULL, rate); +} + +/* + * mo_shedding + * + * inputs - pointer to server + * - pointer to client + * - parameter count + * - parameter list + * output - + * side effects - user shedding is enabled or disabled + * + * SHEDDING OFF - disable shedding + * SHEDDING : + * (parv[#] 1 2 3) + * + */ +static void +mo_shedding(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) +{ + if (!HasPrivilege(source_p, "oper:shedding")) + { + sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "SHEDDING"); + return; + } + + /* I can think of a thousand ways this could go wrong... */ + if (strchr(parv[1], '*') != NULL) + { + sendto_one_notice(source_p, "Wildcards are not permitted for shedding targets"); + return; + } + + if (parc != 4 && !(parc == 3 && irccmp(parv[2], "OFF") == 0)) + { + sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), + me.name, source_p->name, "SHEDDING"); + return; + } + + if (irccmp(parv[1], me.name) != 0) { + /* it's not for us, pass it around */ + if (irccmp(parv[2], "OFF") == 0) + sendto_match_servs(source_p, parv[1], + CAP_ENCAP, NOCAPS, + "ENCAP %s SHEDDING OFF", parv[1]); + else + sendto_match_servs(source_p, parv[1], + CAP_ENCAP, NOCAPS, + "ENCAP %s SHEDDING %s :%s", + parv[1], parv[2], parv[3]); + return; + } + + set_shedding_state(source_p, parv[2], parv[3]); +} + +static void +me_shedding(struct MsgBuf *msgbuf, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) +{ + if(!IsPerson(source_p)) + return; + + set_shedding_state(source_p, parv[1], parv[2]); +} + + +static void +do_user_shedding(void *unused) +{ + rb_dlink_node *ptr; + struct Client *client_p; + + RB_DLINK_FOREACH_PREV(ptr, lclient_list.tail) + { + client_p = ptr->data; + + if (!IsClient(client_p)) /* It could be servers */ + continue; + if (IsExemptKline(client_p)) + continue; + exit_client(client_p, client_p, &me, "Server closed connection"); + break; + } +} diff --git a/help/opers/shedding b/help/opers/shedding new file mode 100644 index 00000000..e7dfa5c1 --- /dev/null +++ b/help/opers/shedding @@ -0,0 +1,9 @@ +SHEDDING : +SHEDDING OFF + +Turns user shedding on or off on the specified server. When a server is +shedding, a client will be disconnected from the server at a time period +defined by rate, until shedding is turned off. Clients with kline_exempt +are never affected by this feature. + +- Requires Oper Priv: oper:shedding