ircd: rework sendq limits a bit.

The sendq limit is now soft, now we halt processing if a sendq is exceeded, until it is sufficiently drained.
This allows us to implement SAFELIST and other floody commands without hacks.
This commit is contained in:
William Pitcock 2016-01-09 23:14:04 -06:00
parent 8dacf9e917
commit 9a5958119c
4 changed files with 53 additions and 5 deletions

View file

@ -40,6 +40,7 @@ struct Class
int max_global;
int max_ident;
int max_sendq;
int max_sendq_hard;
int con_freq;
int ping_freq;
int total;
@ -61,6 +62,7 @@ extern struct Class *default_class;
#define MaxUsers(x) ((x)->max_total)
#define PingFreq(x) ((x)->ping_freq)
#define MaxSendq(x) ((x)->max_sendq)
#define MaxSendqHard(x) ((x)->max_sendq_hard)
#define CurrUsers(x) ((x)->total)
#define IpLimits(x) ((x)->ip_limits)
#define CidrIpv4Bitlen(x) ((x)->cidr_ipv4_bitlen)
@ -81,12 +83,14 @@ extern struct Class *default_class;
#define ConfCidrAmount(x) (ClassPtr(x)->cidr_amount)
#define ConfCidrIpv4Bitlen(x) (ClassPtr(x)->cidr_ipv4_bitlen)
#define ConfCidrIpv6Bitlen(x) (ClassPtr(x)->cidr_ipv6_bitlen)
#define ConfMaxSendqHard(x) (ClassPtr(x)->max_sendq_hard)
void add_class(struct Class *);
struct Class *make_class(void);
extern long get_sendq(struct Client *);
extern long get_sendq_hard(struct Client *);
extern int get_con_freq(struct Class *);
extern struct Class *find_class(const char *);
extern const char *get_client_class(struct Client *);

View file

@ -55,6 +55,7 @@ make_class(void)
PingFreq(tmp) = DEFAULT_PINGFREQUENCY;
MaxUsers(tmp) = 1;
MaxSendq(tmp) = DEFAULT_SENDQ;
MaxSendqHard(tmp) = DEFAULT_SENDQ * 4;
tmp->ip_limits = rb_new_patricia(PATRICIA_BITS);
return tmp;
@ -198,6 +199,7 @@ add_class(struct Class *classptr)
MaxIdent(tmpptr) = MaxIdent(classptr);
PingFreq(tmpptr) = PingFreq(classptr);
MaxSendq(tmpptr) = MaxSendq(classptr);
MaxSendqHard(tmpptr) = MaxSendq(classptr) * 4;
ConFreq(tmpptr) = ConFreq(classptr);
CidrIpv4Bitlen(tmpptr) = CidrIpv4Bitlen(classptr);
CidrIpv6Bitlen(tmpptr) = CidrIpv6Bitlen(classptr);
@ -342,3 +344,33 @@ get_sendq(struct Client *client_p)
return DEFAULT_SENDQ;
}
/*
* get_sendq_hard
*
* inputs - pointer to client
* output - hard sendq limit for this client as found from its class
* side effects - NONE
*/
long
get_sendq_hard(struct Client *client_p)
{
if(client_p == NULL || IsMe(client_p))
return DEFAULT_SENDQ;
if(IsServer(client_p))
{
struct server_conf *server_p;
server_p = client_p->localClient->att_sconf;
return MaxSendqHard(server_p->class);
}
else
{
struct ConfItem *aconf = client_p->localClient->att_conf;
if(aconf != NULL && aconf->status & CONF_CLIENT)
return ConfMaxSendqHard(aconf);
}
return DEFAULT_SENDQ;
}

View file

@ -108,11 +108,23 @@ parse_client_queued(struct Client *client_p)
else
allow_read = ConfigFileEntry.client_flood_burst_rate;
allow_read *= ConfigFileEntry.client_flood_message_time;
/* allow opers 4 times the amount of messages as users. why 4?
* why not. :) --fl_
*/
if(IsOper(client_p) && ConfigFileEntry.no_oper_flood)
allow_read *= 4;
else
{
/*
* If a client's sendq is greater than the soft limit, do not allow any
* more messages to be read. This allows us to safely handle commands like
* LIST without harming the server. --kaniini
*/
if (rb_linebuf_len(&client_p->localClient->buf_sendq) > (get_sendq(client_p)))
allow_read = 0;
}
/*
* Handle flood protection here - if we exceed our flood limit on
* messages in this loop, we simply drop out of the loop prematurely.

View file

@ -69,20 +69,20 @@ _send_linebuf(struct Client *to, buf_head_t *linebuf)
if(!MyConnect(to) || IsIOError(to))
return 0;
if(rb_linebuf_len(&to->localClient->buf_sendq) > get_sendq(to))
if(rb_linebuf_len(&to->localClient->buf_sendq) > get_sendq_hard(to))
{
if(IsServer(to))
{
sendto_realops_snomask(SNO_GENERAL, L_ALL,
"Max SendQ limit exceeded for %s: %u > %lu",
"Hard SendQ limit exceeded for %s: %u > %lu",
to->name,
rb_linebuf_len(&to->localClient->buf_sendq),
get_sendq(to));
get_sendq_hard(to));
ilog(L_SERVER, "Max SendQ limit exceeded for %s: %u > %lu",
ilog(L_SERVER, "Hard SendQ limit exceeded for %s: %u > %lu",
log_client_name(to, SHOW_IP),
rb_linebuf_len(&to->localClient->buf_sendq),
get_sendq(to));
get_sendq_hard(to));
}
dead_link(to, 1);