diff --git a/include/client.h b/include/client.h index 5ed61a7f..c0b0edf9 100644 --- a/include/client.h +++ b/include/client.h @@ -171,9 +171,10 @@ enum Flag FLAG_ACCOUNT, /**< account name has been set */ FLAG_HIDDENHOST, /**< user's host is hidden */ FLAG_CAP302, /**< client supports IRCv3.2 */ - FLAG_LAST_FLAG, /**< number of flags */ + FLAG_EXEMPTFLOOD, /**< Client is exempt from flood limits */ FLAG_LOCAL_UMODES = FLAG_LOCOP, /**< First local mode flag */ - FLAG_GLOBAL_UMODES = FLAG_OPER /**< First global mode flag */ + FLAG_GLOBAL_UMODES = FLAG_OPER, /**< First global mode flag */ + FLAG_LAST_FLAG /**< number of flags */ }; /** Declare flagset type for operator privileges. */ @@ -614,6 +615,8 @@ struct Client { #define IsHiddenHost(x) HasFlag(x, FLAG_HIDDENHOST) /** Return non-zero if the client has an active PING request. */ #define IsPingSent(x) HasFlag(x, FLAG_PINGSENT) +/** Return non-zero if the client is exempt from flood limits. */ +#define IsExemptFlood(x) HasFlag(x, FLAG_EXEMPTFLOOD) /** Return non-zero if the client has operator or server privileges. */ #define IsPrivileged(x) (IsAnOper(x) || IsServer(x)) @@ -660,6 +663,8 @@ struct Client { #define SetHiddenHost(x) SetFlag(x, FLAG_HIDDENHOST) /** Mark a client as having a pending PING. */ #define SetPingSent(x) SetFlag(x, FLAG_PINGSENT) +/** Mark a client as being exempt from flood limits. */ +#define SetExemptFlood(x) SetFlag(x, FLAG_EXEMPTFLOOD) /** Return non-zero if \a sptr sees \a acptr as an operator. */ #define SeeOper(sptr,acptr) (IsAnOper(acptr) && (HasPriv(acptr, PRIV_DISPLAY) \ diff --git a/ircd/s_bsd.c b/ircd/s_bsd.c index 369faaca..71536378 100644 --- a/ircd/s_bsd.c +++ b/ircd/s_bsd.c @@ -636,8 +636,15 @@ static int read_packet(struct Client *cptr, int socket_ready) if (DBufLength(&(cli_recvQ(cptr))) > GetMaxFlood(cptr)) return exit_client(cptr, cptr, &me, "Excess Flood"); + /* If client has a higher sendq limit than default, + * mark them flood exempt to avoid throttling + */ + if (GetMaxFlood(cptr) > feature_int(FEAT_CLIENT_FLOOD)) { + SetExemptFlood(cptr); + } + while (DBufLength(&(cli_recvQ(cptr))) && !NoNewLine(cptr) && - (IsTrusted(cptr) || cli_since(cptr) - CurrentTime < 10)) + (IsTrusted(cptr) || IsExemptFlood(cptr) || cli_since(cptr) - CurrentTime < 10)) { dolen = dbuf_getmsg(&(cli_recvQ(cptr)), cli_buffer(cptr), BUFSIZE); /* @@ -682,14 +689,16 @@ static int read_packet(struct Client *cptr, int socket_ready) } } - /* If there's still data to process, wait 2 seconds first */ + /* If there's still data to process, wait 2 seconds first, + * unless the user is exempt from throttling + */ if (DBufLength(&(cli_recvQ(cptr))) && !NoNewLine(cptr) && - !t_onqueue(&(cli_proc(cptr)))) + !IsExemptFlood(cptr) && !t_onqueue(&(cli_proc(cptr)))) { Debug((DEBUG_LIST, "Adding client process timer for %C", cptr)); cli_freeflag(cptr) |= FREEFLAG_TIMER; timer_add(&(cli_proc(cptr)), client_timer_callback, cli_connect(cptr), - TT_RELATIVE, 2); + TT_RELATIVE, 2); } } return 1;