]> jfr.im git - solanum.git/blob - ircd/ratelimit.c
ircd/authproc.c: avoid crash on lack of any configured DNSBLs
[solanum.git] / ircd / ratelimit.c
1 /*
2 * Solanum: a slightly advanced ircd
3 * ratelimit.c: Per-client ratelimiting for high-bandwidth commands.
4 *
5 * Copyright (c) 2012 Keith Buck <mr_flea -at- esper.net>
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice is present in all copies.
10 *
11 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
12 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
13 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
14 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
15 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
18 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
19 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
20 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21 * POSSIBILITY OF SUCH DAMAGE.
22 */
23
24 #include "stdinc.h"
25 #include "s_conf.h"
26 #include "s_stats.h"
27 #include "ratelimit.h"
28 #include "s_assert.h"
29
30 /*
31 * ratelimit_client(struct Client *client_p, int penalty)
32 *
33 * Applies a penalty to a client for executing a rate-limited command.
34 *
35 * Inputs:
36 * - the client to be rate-limited
37 * - the penalty to apply
38 *
39 * Outputs:
40 * - 1 if the user has been penalized and the command should be
41 * allowed to execute
42 * - 0 if the command should not execute and the user has not
43 * been penalized (they are executing commands too fast and have
44 * been rate-limited)
45 * The caller should return RPL_LOAD2HI
46 *
47 * Side effects:
48 * - The ratelimit for the user will be initialized if it hasn't
49 * been initialized yet.
50 */
51 int ratelimit_client(struct Client *client_p, unsigned int penalty)
52 {
53 s_assert(client_p);
54 s_assert(MyClient(client_p));
55
56 if (!client_p->localClient->ratelimit)
57 {
58 /* Not initialized yet - do it now. */
59 client_p->localClient->ratelimit = rb_current_time() - ConfigFileEntry.max_ratelimit_tokens;
60 }
61
62 /* Don't make it impossible to execute anything. */
63 if (penalty > (unsigned int)ConfigFileEntry.max_ratelimit_tokens)
64 penalty = ConfigFileEntry.max_ratelimit_tokens;
65
66 if (client_p->localClient->ratelimit <= rb_current_time() - ConfigFileEntry.max_ratelimit_tokens)
67 {
68 client_p->localClient->ratelimit = rb_current_time() - ConfigFileEntry.max_ratelimit_tokens + penalty;
69 return 1;
70 }
71
72 if (client_p->localClient->ratelimit + penalty > rb_current_time())
73 {
74 ServerStats.is_rl++;
75 return 0;
76 }
77
78 client_p->localClient->ratelimit += penalty;
79
80 return 1;
81 }
82
83 /*
84 * ratelimit_client_who(struct Client *client_p, int penalty)
85 *
86 * Rate-limits a client for a WHO query if they have no remaining "free"
87 * WHO queries to execute.
88 *
89 * Inputs:
90 * - same as ratelimit_client
91 *
92 * Outputs:
93 * - same as ratelimit_client
94 *
95 * Side effects:
96 * - A "free who" token will be removed from the user if one exists.
97 * If one doesn't exist, the user will be ratelimited as normal.
98 */
99 int ratelimit_client_who(struct Client *client_p, unsigned int penalty)
100 {
101 s_assert(client_p);
102 s_assert(MyClient(client_p));
103
104 if (client_p->localClient->join_who_credits)
105 {
106 --client_p->localClient->join_who_credits;
107 return 1;
108 }
109
110 return ratelimit_client(client_p, penalty);
111 }
112
113 /*
114 * credit_client_join(struct Client *client_p)
115 *
116 * Gives a user a credit to execute a WHO for joining a channel.
117 *
118 * Inputs:
119 * - the client to be credited
120 *
121 * Outputs:
122 * - (none)
123 *
124 * Side effects:
125 * - (none)
126 */
127 void credit_client_join(struct Client *client_p)
128 {
129 s_assert(client_p);
130 s_assert(MyClient(client_p));
131
132 ++client_p->localClient->join_who_credits;
133 }