1e92d3f3fSGregory Neil Shapiro /*
25dd76dd0SGregory Neil Shapiro * Copyright (c) 2003 Proofpoint, Inc. and its suppliers.
3e92d3f3fSGregory Neil Shapiro * All rights reserved.
4e92d3f3fSGregory Neil Shapiro *
5e92d3f3fSGregory Neil Shapiro * By using this file, you agree to the terms and conditions set
6e92d3f3fSGregory Neil Shapiro * forth in the LICENSE file which can be found at the top level of
7e92d3f3fSGregory Neil Shapiro * the sendmail distribution.
8e92d3f3fSGregory Neil Shapiro *
9e92d3f3fSGregory Neil Shapiro * Contributed by Jose Marcio Martins da Cruz - Ecole des Mines de Paris
10e92d3f3fSGregory Neil Shapiro * Jose-Marcio.Martins@ensmp.fr
11e92d3f3fSGregory Neil Shapiro */
12e92d3f3fSGregory Neil Shapiro
13e92d3f3fSGregory Neil Shapiro /* a part of this code is based on inetd.c for which this copyright applies: */
14e92d3f3fSGregory Neil Shapiro /*
15e92d3f3fSGregory Neil Shapiro * Copyright (c) 1983, 1991, 1993, 1994
16e92d3f3fSGregory Neil Shapiro * The Regents of the University of California. All rights reserved.
17e92d3f3fSGregory Neil Shapiro *
18e92d3f3fSGregory Neil Shapiro * Redistribution and use in source and binary forms, with or without
19e92d3f3fSGregory Neil Shapiro * modification, are permitted provided that the following conditions
20e92d3f3fSGregory Neil Shapiro * are met:
21e92d3f3fSGregory Neil Shapiro * 1. Redistributions of source code must retain the above copyright
22e92d3f3fSGregory Neil Shapiro * notice, this list of conditions and the following disclaimer.
23e92d3f3fSGregory Neil Shapiro * 2. Redistributions in binary form must reproduce the above copyright
24e92d3f3fSGregory Neil Shapiro * notice, this list of conditions and the following disclaimer in the
25e92d3f3fSGregory Neil Shapiro * documentation and/or other materials provided with the distribution.
26e92d3f3fSGregory Neil Shapiro * 3. All advertising materials mentioning features or use of this software
27e92d3f3fSGregory Neil Shapiro * must display the following acknowledgement:
28e92d3f3fSGregory Neil Shapiro * This product includes software developed by the University of
29e92d3f3fSGregory Neil Shapiro * California, Berkeley and its contributors.
30e92d3f3fSGregory Neil Shapiro * 4. Neither the name of the University nor the names of its contributors
31e92d3f3fSGregory Neil Shapiro * may be used to endorse or promote products derived from this software
32e92d3f3fSGregory Neil Shapiro * without specific prior written permission.
33e92d3f3fSGregory Neil Shapiro *
34e92d3f3fSGregory Neil Shapiro * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35e92d3f3fSGregory Neil Shapiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36e92d3f3fSGregory Neil Shapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37e92d3f3fSGregory Neil Shapiro * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38e92d3f3fSGregory Neil Shapiro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39e92d3f3fSGregory Neil Shapiro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40e92d3f3fSGregory Neil Shapiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41e92d3f3fSGregory Neil Shapiro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42e92d3f3fSGregory Neil Shapiro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43e92d3f3fSGregory Neil Shapiro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44e92d3f3fSGregory Neil Shapiro * SUCH DAMAGE.
45e92d3f3fSGregory Neil Shapiro */
46e92d3f3fSGregory Neil Shapiro
475b0945b5SGregory Neil Shapiro #include <ratectrl.h>
484313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: ratectrl.c,v 8.14 2013-11-22 20:51:56 ca Exp $")
49e92d3f3fSGregory Neil Shapiro
505b0945b5SGregory Neil Shapiro static int client_rate __P((time_t, SOCKADDR *, int));
51e92d3f3fSGregory Neil Shapiro static int total_rate __P((time_t, bool));
525b0945b5SGregory Neil Shapiro static unsigned int gen_hash __P((SOCKADDR *));
535b0945b5SGregory Neil Shapiro static void rate_init __P((void));
54e92d3f3fSGregory Neil Shapiro
55e92d3f3fSGregory Neil Shapiro /*
56e92d3f3fSGregory Neil Shapiro ** CONNECTION_RATE_CHECK - updates connection history data
57e92d3f3fSGregory Neil Shapiro ** and computes connection rate for the given host
58e92d3f3fSGregory Neil Shapiro **
59e92d3f3fSGregory Neil Shapiro ** Parameters:
605b0945b5SGregory Neil Shapiro ** hostaddr -- IP address of SMTP client
61e92d3f3fSGregory Neil Shapiro ** e -- envelope
62e92d3f3fSGregory Neil Shapiro **
63e92d3f3fSGregory Neil Shapiro ** Returns:
645b0945b5SGregory Neil Shapiro ** none
65e92d3f3fSGregory Neil Shapiro **
66e92d3f3fSGregory Neil Shapiro ** Side Effects:
67e92d3f3fSGregory Neil Shapiro ** updates connection history
68e92d3f3fSGregory Neil Shapiro **
69e92d3f3fSGregory Neil Shapiro ** Warnings:
70e92d3f3fSGregory Neil Shapiro ** For each connection, this call shall be
71e92d3f3fSGregory Neil Shapiro ** done only once with the value true for the
72e92d3f3fSGregory Neil Shapiro ** update parameter.
73e92d3f3fSGregory Neil Shapiro ** Typically, this call is done with the value
74e92d3f3fSGregory Neil Shapiro ** true by the father, and once again with
75e92d3f3fSGregory Neil Shapiro ** the value false by the children.
76e92d3f3fSGregory Neil Shapiro */
77e92d3f3fSGregory Neil Shapiro
785b0945b5SGregory Neil Shapiro void
connection_rate_check(hostaddr,e)79e92d3f3fSGregory Neil Shapiro connection_rate_check(hostaddr, e)
80e92d3f3fSGregory Neil Shapiro SOCKADDR *hostaddr;
81e92d3f3fSGregory Neil Shapiro ENVELOPE *e;
82e92d3f3fSGregory Neil Shapiro {
83e92d3f3fSGregory Neil Shapiro time_t now;
84e92d3f3fSGregory Neil Shapiro int totalrate, clientrate;
85e92d3f3fSGregory Neil Shapiro static int clientconn = 0;
86e92d3f3fSGregory Neil Shapiro
87e92d3f3fSGregory Neil Shapiro now = time(NULL);
88e92d3f3fSGregory Neil Shapiro #if RATECTL_DEBUG
89e92d3f3fSGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "connection_rate_check entering...");
905b0945b5SGregory Neil Shapiro #endif
91e92d3f3fSGregory Neil Shapiro
92e92d3f3fSGregory Neil Shapiro /* update server connection rate */
93e92d3f3fSGregory Neil Shapiro totalrate = total_rate(now, e == NULL);
94e92d3f3fSGregory Neil Shapiro #if RATECTL_DEBUG
95e3793f76SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "global connection rate: %d", totalrate);
965b0945b5SGregory Neil Shapiro #endif
97e92d3f3fSGregory Neil Shapiro
98e92d3f3fSGregory Neil Shapiro /* update client connection rate */
995b0945b5SGregory Neil Shapiro clientrate = client_rate(now, hostaddr, e == NULL ? SM_CLFL_UPDATE : SM_CLFL_NONE);
100e92d3f3fSGregory Neil Shapiro
101e92d3f3fSGregory Neil Shapiro if (e == NULL)
102e92d3f3fSGregory Neil Shapiro clientconn = count_open_connections(hostaddr);
103e92d3f3fSGregory Neil Shapiro
104e92d3f3fSGregory Neil Shapiro if (e != NULL)
105e92d3f3fSGregory Neil Shapiro {
106e92d3f3fSGregory Neil Shapiro char s[16];
107e92d3f3fSGregory Neil Shapiro
108e92d3f3fSGregory Neil Shapiro sm_snprintf(s, sizeof(s), "%d", clientrate);
109e92d3f3fSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{client_rate}"), s);
110e92d3f3fSGregory Neil Shapiro sm_snprintf(s, sizeof(s), "%d", totalrate);
111e92d3f3fSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{total_rate}"), s);
112e92d3f3fSGregory Neil Shapiro sm_snprintf(s, sizeof(s), "%d", clientconn);
113e92d3f3fSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{client_connections}"),
114e92d3f3fSGregory Neil Shapiro s);
115e92d3f3fSGregory Neil Shapiro }
1165b0945b5SGregory Neil Shapiro return;
117e92d3f3fSGregory Neil Shapiro }
118e92d3f3fSGregory Neil Shapiro
119e92d3f3fSGregory Neil Shapiro /*
120e92d3f3fSGregory Neil Shapiro ** Data declarations needed to evaluate connection rate
121e92d3f3fSGregory Neil Shapiro */
122e92d3f3fSGregory Neil Shapiro
123e92d3f3fSGregory Neil Shapiro static int CollTime = 60;
124e92d3f3fSGregory Neil Shapiro
125e92d3f3fSGregory Neil Shapiro /*
126e92d3f3fSGregory Neil Shapiro ** time granularity: 10s (that's one "tick")
127e92d3f3fSGregory Neil Shapiro ** will be initialised to ConnectionRateWindowSize/CHTSIZE
128e92d3f3fSGregory Neil Shapiro ** before being used the first time
129e92d3f3fSGregory Neil Shapiro */
130e92d3f3fSGregory Neil Shapiro
131e92d3f3fSGregory Neil Shapiro static int ChtGran = -1;
132e92d3f3fSGregory Neil Shapiro static CHash_T CHashAry[CPMHSIZE];
1335b0945b5SGregory Neil Shapiro static CTime_T srv_Times[CHTSIZE];
1345b0945b5SGregory Neil Shapiro
1355b0945b5SGregory Neil Shapiro #ifndef MAX_CT_STEPS
1365b0945b5SGregory Neil Shapiro # define MAX_CT_STEPS 10
1375b0945b5SGregory Neil Shapiro #endif
138e92d3f3fSGregory Neil Shapiro
139e92d3f3fSGregory Neil Shapiro /*
1405b0945b5SGregory Neil Shapiro ** RATE_INIT - initialize local data
141e92d3f3fSGregory Neil Shapiro **
142e92d3f3fSGregory Neil Shapiro ** Parameters:
1435b0945b5SGregory Neil Shapiro ** none
144e92d3f3fSGregory Neil Shapiro **
145e92d3f3fSGregory Neil Shapiro ** Returns:
1465b0945b5SGregory Neil Shapiro ** none
147e92d3f3fSGregory Neil Shapiro **
148e92d3f3fSGregory Neil Shapiro ** Side effects:
1495b0945b5SGregory Neil Shapiro ** initializes static global data
150e92d3f3fSGregory Neil Shapiro */
151e92d3f3fSGregory Neil Shapiro
1525b0945b5SGregory Neil Shapiro static void
rate_init()1535b0945b5SGregory Neil Shapiro rate_init()
154e92d3f3fSGregory Neil Shapiro {
1555b0945b5SGregory Neil Shapiro if (ChtGran > 0)
1565b0945b5SGregory Neil Shapiro return;
157e92d3f3fSGregory Neil Shapiro ChtGran = ConnectionRateWindowSize / CHTSIZE;
158e92d3f3fSGregory Neil Shapiro if (ChtGran <= 0)
159e92d3f3fSGregory Neil Shapiro ChtGran = 10;
160e92d3f3fSGregory Neil Shapiro memset(CHashAry, 0, sizeof(CHashAry));
1615b0945b5SGregory Neil Shapiro memset(srv_Times, 0, sizeof(srv_Times));
1625b0945b5SGregory Neil Shapiro return;
163e92d3f3fSGregory Neil Shapiro }
164e92d3f3fSGregory Neil Shapiro
1655b0945b5SGregory Neil Shapiro /*
1665b0945b5SGregory Neil Shapiro ** GEN_HASH - calculate a hash value
1675b0945b5SGregory Neil Shapiro **
1685b0945b5SGregory Neil Shapiro ** Parameters:
1695b0945b5SGregory Neil Shapiro ** saddr - client address
1705b0945b5SGregory Neil Shapiro **
1715b0945b5SGregory Neil Shapiro ** Returns:
1725b0945b5SGregory Neil Shapiro ** hash value
1735b0945b5SGregory Neil Shapiro */
1745b0945b5SGregory Neil Shapiro
1755b0945b5SGregory Neil Shapiro static unsigned int
gen_hash(saddr)1765b0945b5SGregory Neil Shapiro gen_hash(saddr)
1775b0945b5SGregory Neil Shapiro SOCKADDR *saddr;
178e92d3f3fSGregory Neil Shapiro {
1795b0945b5SGregory Neil Shapiro unsigned int hv;
1805b0945b5SGregory Neil Shapiro int i;
181e92d3f3fSGregory Neil Shapiro int addrlen;
1825b0945b5SGregory Neil Shapiro char *p;
183e92d3f3fSGregory Neil Shapiro #if HASH_ALG != 1
184e92d3f3fSGregory Neil Shapiro int c, d;
1855b0945b5SGregory Neil Shapiro #endif
186e92d3f3fSGregory Neil Shapiro
1875b0945b5SGregory Neil Shapiro hv = 0xABC3D20F;
188e92d3f3fSGregory Neil Shapiro switch (saddr->sa.sa_family)
189e92d3f3fSGregory Neil Shapiro {
190e92d3f3fSGregory Neil Shapiro #if NETINET
191e92d3f3fSGregory Neil Shapiro case AF_INET:
192e92d3f3fSGregory Neil Shapiro p = (char *)&saddr->sin.sin_addr;
193e92d3f3fSGregory Neil Shapiro addrlen = sizeof(struct in_addr);
194e92d3f3fSGregory Neil Shapiro break;
195e92d3f3fSGregory Neil Shapiro #endif /* NETINET */
196e92d3f3fSGregory Neil Shapiro #if NETINET6
197e92d3f3fSGregory Neil Shapiro case AF_INET6:
198e92d3f3fSGregory Neil Shapiro p = (char *)&saddr->sin6.sin6_addr;
199e92d3f3fSGregory Neil Shapiro addrlen = sizeof(struct in6_addr);
200e92d3f3fSGregory Neil Shapiro break;
201e92d3f3fSGregory Neil Shapiro #endif /* NETINET6 */
202e92d3f3fSGregory Neil Shapiro default:
203e92d3f3fSGregory Neil Shapiro /* should not happen */
204e92d3f3fSGregory Neil Shapiro return -1;
205e92d3f3fSGregory Neil Shapiro }
206e92d3f3fSGregory Neil Shapiro
207e92d3f3fSGregory Neil Shapiro /* compute hash value */
208e92d3f3fSGregory Neil Shapiro for (i = 0; i < addrlen; ++i, ++p)
209e92d3f3fSGregory Neil Shapiro #if HASH_ALG == 1
210e92d3f3fSGregory Neil Shapiro hv = (hv << 5) ^ (hv >> 23) ^ *p;
211e92d3f3fSGregory Neil Shapiro hv = (hv ^ (hv >> 16));
212e92d3f3fSGregory Neil Shapiro #elif HASH_ALG == 2
213e92d3f3fSGregory Neil Shapiro {
214e92d3f3fSGregory Neil Shapiro d = *p;
215e92d3f3fSGregory Neil Shapiro c = d;
216e92d3f3fSGregory Neil Shapiro c ^= c<<6;
217e92d3f3fSGregory Neil Shapiro hv += (c<<11) ^ (c>>1);
218e92d3f3fSGregory Neil Shapiro hv ^= (d<<14) + (d<<7) + (d<<4) + d;
219e92d3f3fSGregory Neil Shapiro }
220e92d3f3fSGregory Neil Shapiro #elif HASH_ALG == 3
221e92d3f3fSGregory Neil Shapiro {
222e92d3f3fSGregory Neil Shapiro hv = (hv << 4) + *p;
223e92d3f3fSGregory Neil Shapiro d = hv & 0xf0000000;
224e92d3f3fSGregory Neil Shapiro if (d != 0)
225e92d3f3fSGregory Neil Shapiro {
226e92d3f3fSGregory Neil Shapiro hv ^= (d >> 24);
227e92d3f3fSGregory Neil Shapiro hv ^= d;
228e92d3f3fSGregory Neil Shapiro }
229e92d3f3fSGregory Neil Shapiro }
230e92d3f3fSGregory Neil Shapiro #else /* HASH_ALG == 1 */
231*d39bd2c1SGregory Neil Shapiro # error "unsupported HASH_ALG"
2325b0945b5SGregory Neil Shapiro hv = ((hv << 1) ^ (*p & 0377)) % cctx->cc_size; ???
233e92d3f3fSGregory Neil Shapiro #endif /* HASH_ALG == 1 */
2345b0945b5SGregory Neil Shapiro
2355b0945b5SGregory Neil Shapiro return hv;
236e92d3f3fSGregory Neil Shapiro }
237e92d3f3fSGregory Neil Shapiro
2385b0945b5SGregory Neil Shapiro /*
2395b0945b5SGregory Neil Shapiro ** CONN_LIMIT - Evaluate connection limits
2405b0945b5SGregory Neil Shapiro **
2415b0945b5SGregory Neil Shapiro ** Parameters:
2425b0945b5SGregory Neil Shapiro ** e -- envelope (_FFR_OCC, for logging only)
2435b0945b5SGregory Neil Shapiro ** now - current time in secs
2445b0945b5SGregory Neil Shapiro ** saddr - client address
2455b0945b5SGregory Neil Shapiro ** clflags - update data / check only / ...
2465b0945b5SGregory Neil Shapiro ** hashary - hash array
2475b0945b5SGregory Neil Shapiro ** ratelimit - rate limit (_FFR_OCC only)
2485b0945b5SGregory Neil Shapiro ** conclimit - concurrency limit (_FFR_OCC only)
2495b0945b5SGregory Neil Shapiro **
2505b0945b5SGregory Neil Shapiro ** Returns:
2515b0945b5SGregory Neil Shapiro #if _FFR_OCC
2525b0945b5SGregory Neil Shapiro ** outgoing: limit exceeded?
2535b0945b5SGregory Neil Shapiro #endif
2545b0945b5SGregory Neil Shapiro ** incoming:
2555b0945b5SGregory Neil Shapiro ** connection rate (connections / ConnectionRateWindowSize)
2565b0945b5SGregory Neil Shapiro */
2575b0945b5SGregory Neil Shapiro
2585b0945b5SGregory Neil Shapiro int
conn_limits(e,now,saddr,clflags,hashary,ratelimit,conclimit)2595b0945b5SGregory Neil Shapiro conn_limits(e, now, saddr, clflags, hashary, ratelimit, conclimit)
2605b0945b5SGregory Neil Shapiro ENVELOPE *e;
2615b0945b5SGregory Neil Shapiro time_t now;
2625b0945b5SGregory Neil Shapiro SOCKADDR *saddr;
2635b0945b5SGregory Neil Shapiro int clflags;
2645b0945b5SGregory Neil Shapiro CHash_T hashary[];
2655b0945b5SGregory Neil Shapiro int ratelimit;
2665b0945b5SGregory Neil Shapiro int conclimit;
2675b0945b5SGregory Neil Shapiro {
2685b0945b5SGregory Neil Shapiro int i;
2695b0945b5SGregory Neil Shapiro int cnt;
2705b0945b5SGregory Neil Shapiro bool coll;
2715b0945b5SGregory Neil Shapiro CHash_T *chBest = NULL;
2725b0945b5SGregory Neil Shapiro CTime_T *ct = NULL;
2735b0945b5SGregory Neil Shapiro unsigned int ticks;
2745b0945b5SGregory Neil Shapiro unsigned int hv;
2755b0945b5SGregory Neil Shapiro #if _FFR_OCC
2765b0945b5SGregory Neil Shapiro bool exceeded = false;
2775b0945b5SGregory Neil Shapiro int *prv, *pcv;
2785b0945b5SGregory Neil Shapiro #endif
2795b0945b5SGregory Neil Shapiro #if RATECTL_DEBUG || _FFR_OCC
2805b0945b5SGregory Neil Shapiro bool logit = false;
2815b0945b5SGregory Neil Shapiro #endif
2825b0945b5SGregory Neil Shapiro
2835b0945b5SGregory Neil Shapiro cnt = 0;
2845b0945b5SGregory Neil Shapiro hv = gen_hash(saddr);
2855b0945b5SGregory Neil Shapiro ticks = now / ChtGran;
2865b0945b5SGregory Neil Shapiro
287e92d3f3fSGregory Neil Shapiro coll = true;
288e92d3f3fSGregory Neil Shapiro for (i = 0; i < MAX_CT_STEPS; ++i)
289e92d3f3fSGregory Neil Shapiro {
2905b0945b5SGregory Neil Shapiro CHash_T *ch = &hashary[(hv + i) & CPMHMASK];
291e92d3f3fSGregory Neil Shapiro
292e92d3f3fSGregory Neil Shapiro #if NETINET
293e92d3f3fSGregory Neil Shapiro if (saddr->sa.sa_family == AF_INET &&
294e92d3f3fSGregory Neil Shapiro ch->ch_Family == AF_INET &&
295e92d3f3fSGregory Neil Shapiro (saddr->sin.sin_addr.s_addr == ch->ch_Addr4.s_addr ||
296e92d3f3fSGregory Neil Shapiro ch->ch_Addr4.s_addr == 0))
297e92d3f3fSGregory Neil Shapiro {
298e92d3f3fSGregory Neil Shapiro chBest = ch;
299e92d3f3fSGregory Neil Shapiro coll = false;
300e92d3f3fSGregory Neil Shapiro break;
301e92d3f3fSGregory Neil Shapiro }
302e92d3f3fSGregory Neil Shapiro #endif /* NETINET */
303e92d3f3fSGregory Neil Shapiro #if NETINET6
304e92d3f3fSGregory Neil Shapiro if (saddr->sa.sa_family == AF_INET6 &&
305e92d3f3fSGregory Neil Shapiro ch->ch_Family == AF_INET6 &&
306e92d3f3fSGregory Neil Shapiro (IN6_ARE_ADDR_EQUAL(&saddr->sin6.sin6_addr,
307e92d3f3fSGregory Neil Shapiro &ch->ch_Addr6) != 0 ||
308e92d3f3fSGregory Neil Shapiro IN6_IS_ADDR_UNSPECIFIED(&ch->ch_Addr6)))
309e92d3f3fSGregory Neil Shapiro {
310e92d3f3fSGregory Neil Shapiro chBest = ch;
311e92d3f3fSGregory Neil Shapiro coll = false;
312e92d3f3fSGregory Neil Shapiro break;
313e92d3f3fSGregory Neil Shapiro }
314e92d3f3fSGregory Neil Shapiro #endif /* NETINET6 */
315e92d3f3fSGregory Neil Shapiro if (chBest == NULL || ch->ch_LTime == 0 ||
316e92d3f3fSGregory Neil Shapiro ch->ch_LTime < chBest->ch_LTime)
317e92d3f3fSGregory Neil Shapiro chBest = ch;
318e92d3f3fSGregory Neil Shapiro }
319e92d3f3fSGregory Neil Shapiro
320e92d3f3fSGregory Neil Shapiro /* Let's update data... */
3215b0945b5SGregory Neil Shapiro if ((clflags & (SM_CLFL_UPDATE|SM_CLFL_EXC)) != 0)
322e92d3f3fSGregory Neil Shapiro {
323e92d3f3fSGregory Neil Shapiro if (coll && (now - chBest->ch_LTime < CollTime))
324e92d3f3fSGregory Neil Shapiro {
325e92d3f3fSGregory Neil Shapiro /*
326e92d3f3fSGregory Neil Shapiro ** increment the number of collisions last
327e92d3f3fSGregory Neil Shapiro ** CollTime for this client
328e92d3f3fSGregory Neil Shapiro */
329e92d3f3fSGregory Neil Shapiro
330e92d3f3fSGregory Neil Shapiro chBest->ch_colls++;
331e92d3f3fSGregory Neil Shapiro
332e92d3f3fSGregory Neil Shapiro /*
333e92d3f3fSGregory Neil Shapiro ** Maybe shall log if collision rate is too high...
334e92d3f3fSGregory Neil Shapiro ** and take measures to resize tables
335e92d3f3fSGregory Neil Shapiro ** if this is the case
336e92d3f3fSGregory Neil Shapiro */
337e92d3f3fSGregory Neil Shapiro }
338e92d3f3fSGregory Neil Shapiro
339e92d3f3fSGregory Neil Shapiro /*
340e92d3f3fSGregory Neil Shapiro ** If it's not a match, then replace the data.
341e92d3f3fSGregory Neil Shapiro ** Note: this purges the history of a colliding entry,
342e92d3f3fSGregory Neil Shapiro ** which may cause "overruns", i.e., if two entries are
343e92d3f3fSGregory Neil Shapiro ** "cancelling" each other out, then they may exceed
344e92d3f3fSGregory Neil Shapiro ** the limits that are set. This might be mitigated a bit
345e92d3f3fSGregory Neil Shapiro ** by the above "best of 5" function however.
346e92d3f3fSGregory Neil Shapiro **
347e92d3f3fSGregory Neil Shapiro ** Alternative approach: just use the old data, which may
348e92d3f3fSGregory Neil Shapiro ** cause false positives however.
3495b0945b5SGregory Neil Shapiro ** To activate this, deactivate the memset() call.
350e92d3f3fSGregory Neil Shapiro */
351e92d3f3fSGregory Neil Shapiro
352e92d3f3fSGregory Neil Shapiro if (coll)
353e92d3f3fSGregory Neil Shapiro {
354e92d3f3fSGregory Neil Shapiro #if NETINET
355e92d3f3fSGregory Neil Shapiro if (saddr->sa.sa_family == AF_INET)
356e92d3f3fSGregory Neil Shapiro {
357e92d3f3fSGregory Neil Shapiro chBest->ch_Family = AF_INET;
358e92d3f3fSGregory Neil Shapiro chBest->ch_Addr4 = saddr->sin.sin_addr;
359e92d3f3fSGregory Neil Shapiro }
360e92d3f3fSGregory Neil Shapiro #endif /* NETINET */
361e92d3f3fSGregory Neil Shapiro #if NETINET6
362e92d3f3fSGregory Neil Shapiro if (saddr->sa.sa_family == AF_INET6)
363e92d3f3fSGregory Neil Shapiro {
364e92d3f3fSGregory Neil Shapiro chBest->ch_Family = AF_INET6;
365e92d3f3fSGregory Neil Shapiro chBest->ch_Addr6 = saddr->sin6.sin6_addr;
366e92d3f3fSGregory Neil Shapiro }
367e92d3f3fSGregory Neil Shapiro #endif /* NETINET6 */
368e92d3f3fSGregory Neil Shapiro memset(chBest->ch_Times, '\0',
369e92d3f3fSGregory Neil Shapiro sizeof(chBest->ch_Times));
370e92d3f3fSGregory Neil Shapiro }
371e92d3f3fSGregory Neil Shapiro
372e92d3f3fSGregory Neil Shapiro chBest->ch_LTime = now;
3735b0945b5SGregory Neil Shapiro ct = &chBest->ch_Times[ticks % CHTSIZE];
374e92d3f3fSGregory Neil Shapiro
375e92d3f3fSGregory Neil Shapiro if (ct->ct_Ticks != ticks)
376e92d3f3fSGregory Neil Shapiro {
377e92d3f3fSGregory Neil Shapiro ct->ct_Ticks = ticks;
378e92d3f3fSGregory Neil Shapiro ct->ct_Count = 0;
379e92d3f3fSGregory Neil Shapiro }
3805b0945b5SGregory Neil Shapiro if ((clflags & SM_CLFL_UPDATE) != 0)
381e92d3f3fSGregory Neil Shapiro ++ct->ct_Count;
382e92d3f3fSGregory Neil Shapiro }
383e92d3f3fSGregory Neil Shapiro
384e92d3f3fSGregory Neil Shapiro /* Now let's count connections on the window */
385e92d3f3fSGregory Neil Shapiro for (i = 0; i < CHTSIZE; ++i)
386e92d3f3fSGregory Neil Shapiro {
3875b0945b5SGregory Neil Shapiro CTime_T *cth;
388e92d3f3fSGregory Neil Shapiro
3895b0945b5SGregory Neil Shapiro cth = &chBest->ch_Times[i];
3905b0945b5SGregory Neil Shapiro if (cth->ct_Ticks <= ticks && cth->ct_Ticks >= ticks - CHTSIZE)
3915b0945b5SGregory Neil Shapiro cnt += cth->ct_Count;
3925b0945b5SGregory Neil Shapiro }
3935b0945b5SGregory Neil Shapiro #if _FFR_OCC
3945b0945b5SGregory Neil Shapiro prv = pcv = NULL;
3955b0945b5SGregory Neil Shapiro if (ct != NULL && ((clflags & SM_CLFL_EXC) != 0))
3965b0945b5SGregory Neil Shapiro {
3975b0945b5SGregory Neil Shapiro if (ratelimit > 0)
3985b0945b5SGregory Neil Shapiro {
3995b0945b5SGregory Neil Shapiro if (cnt < ratelimit)
4005b0945b5SGregory Neil Shapiro prv = &(ct->ct_Count);
4015b0945b5SGregory Neil Shapiro else
4025b0945b5SGregory Neil Shapiro exceeded = true;
4035b0945b5SGregory Neil Shapiro }
4045b0945b5SGregory Neil Shapiro else if (ratelimit < 0 && ct->ct_Count > 0)
4055b0945b5SGregory Neil Shapiro --ct->ct_Count;
406e92d3f3fSGregory Neil Shapiro }
407e92d3f3fSGregory Neil Shapiro
4085b0945b5SGregory Neil Shapiro if (chBest != NULL && ((clflags & SM_CLFL_EXC) != 0))
4095b0945b5SGregory Neil Shapiro {
4105b0945b5SGregory Neil Shapiro if (conclimit > 0)
4115b0945b5SGregory Neil Shapiro {
4125b0945b5SGregory Neil Shapiro if (chBest->ch_oc < conclimit)
4135b0945b5SGregory Neil Shapiro pcv = &(chBest->ch_oc);
4145b0945b5SGregory Neil Shapiro else
4155b0945b5SGregory Neil Shapiro exceeded = true;
4165b0945b5SGregory Neil Shapiro }
4175b0945b5SGregory Neil Shapiro else if (conclimit < 0 && chBest->ch_oc > 0)
4185b0945b5SGregory Neil Shapiro --chBest->ch_oc;
4195b0945b5SGregory Neil Shapiro }
4205b0945b5SGregory Neil Shapiro #endif
4215b0945b5SGregory Neil Shapiro
422e92d3f3fSGregory Neil Shapiro #if RATECTL_DEBUG
4235b0945b5SGregory Neil Shapiro logit = true;
4245b0945b5SGregory Neil Shapiro #endif
4255b0945b5SGregory Neil Shapiro #if RATECTL_DEBUG || _FFR_OCC
4265b0945b5SGregory Neil Shapiro # if _FFR_OCC
4275b0945b5SGregory Neil Shapiro if (!exceeded)
4285b0945b5SGregory Neil Shapiro {
4295b0945b5SGregory Neil Shapiro if (prv != NULL)
4305b0945b5SGregory Neil Shapiro ++*prv, ++cnt;
4315b0945b5SGregory Neil Shapiro if (pcv != NULL)
4325b0945b5SGregory Neil Shapiro ++*pcv;
4335b0945b5SGregory Neil Shapiro }
4345b0945b5SGregory Neil Shapiro logit = exceeded || LogLevel > 11;
4355b0945b5SGregory Neil Shapiro # endif
4365b0945b5SGregory Neil Shapiro if (logit)
4375b0945b5SGregory Neil Shapiro sm_syslog(LOG_DEBUG, e != NULL ? e->e_id : NOQID,
4385b0945b5SGregory Neil Shapiro "conn_limits: addr=%s, flags=0x%x, rate=%d/%d, conc=%d/%d, exc=%d",
4395b0945b5SGregory Neil Shapiro saddr->sa.sa_family == AF_INET
4405b0945b5SGregory Neil Shapiro ? inet_ntoa(saddr->sin.sin_addr) : "???",
4415b0945b5SGregory Neil Shapiro clflags, cnt, ratelimit,
4425b0945b5SGregory Neil Shapiro # if _FFR_OCC
4435b0945b5SGregory Neil Shapiro chBest != NULL ? chBest->ch_oc : -1
4445b0945b5SGregory Neil Shapiro # else
4455b0945b5SGregory Neil Shapiro -2
4465b0945b5SGregory Neil Shapiro # endif
4475b0945b5SGregory Neil Shapiro , conclimit
4485b0945b5SGregory Neil Shapiro # if _FFR_OCC
4495b0945b5SGregory Neil Shapiro , exceeded
4505b0945b5SGregory Neil Shapiro # else
4515b0945b5SGregory Neil Shapiro , 0
4525b0945b5SGregory Neil Shapiro # endif
4535b0945b5SGregory Neil Shapiro );
4545b0945b5SGregory Neil Shapiro #endif
4555b0945b5SGregory Neil Shapiro #if _FFR_OCC
4565b0945b5SGregory Neil Shapiro if ((clflags & SM_CLFL_EXC) != 0)
4575b0945b5SGregory Neil Shapiro return exceeded;
4585b0945b5SGregory Neil Shapiro #endif
459e92d3f3fSGregory Neil Shapiro return cnt;
460e92d3f3fSGregory Neil Shapiro }
461e92d3f3fSGregory Neil Shapiro
462e92d3f3fSGregory Neil Shapiro /*
4635b0945b5SGregory Neil Shapiro ** CLIENT_RATE - Evaluate connection rate per SMTP client
4645b0945b5SGregory Neil Shapiro **
4655b0945b5SGregory Neil Shapiro ** Parameters:
4665b0945b5SGregory Neil Shapiro ** now - current time in secs
4675b0945b5SGregory Neil Shapiro ** saddr - client address
4685b0945b5SGregory Neil Shapiro ** clflags - update data / check only
4695b0945b5SGregory Neil Shapiro **
4705b0945b5SGregory Neil Shapiro ** Returns:
4715b0945b5SGregory Neil Shapiro ** connection rate (connections / ConnectionRateWindowSize)
4725b0945b5SGregory Neil Shapiro **
4735b0945b5SGregory Neil Shapiro ** Side effects:
4745b0945b5SGregory Neil Shapiro ** update static global data
4755b0945b5SGregory Neil Shapiro */
4765b0945b5SGregory Neil Shapiro
4775b0945b5SGregory Neil Shapiro static int
client_rate(now,saddr,clflags)4785b0945b5SGregory Neil Shapiro client_rate(now, saddr, clflags)
4795b0945b5SGregory Neil Shapiro time_t now;
4805b0945b5SGregory Neil Shapiro SOCKADDR *saddr;
4815b0945b5SGregory Neil Shapiro int clflags;
4825b0945b5SGregory Neil Shapiro {
4835b0945b5SGregory Neil Shapiro rate_init();
4845b0945b5SGregory Neil Shapiro return conn_limits(NULL, now, saddr, clflags, CHashAry, 0, 0);
4855b0945b5SGregory Neil Shapiro }
4865b0945b5SGregory Neil Shapiro
4875b0945b5SGregory Neil Shapiro /*
488e92d3f3fSGregory Neil Shapiro ** TOTAL_RATE - Evaluate global connection rate
489e92d3f3fSGregory Neil Shapiro **
490e92d3f3fSGregory Neil Shapiro ** Parameters:
491e92d3f3fSGregory Neil Shapiro ** now - current time in secs
492e92d3f3fSGregory Neil Shapiro ** update - update data / check only
493e92d3f3fSGregory Neil Shapiro **
494e92d3f3fSGregory Neil Shapiro ** Returns:
495e92d3f3fSGregory Neil Shapiro ** connection rate (connections / ConnectionRateWindowSize)
496e92d3f3fSGregory Neil Shapiro */
497e92d3f3fSGregory Neil Shapiro
498e92d3f3fSGregory Neil Shapiro static int
total_rate(now,update)499e92d3f3fSGregory Neil Shapiro total_rate(now, update)
500e92d3f3fSGregory Neil Shapiro time_t now;
501e92d3f3fSGregory Neil Shapiro bool update;
502e92d3f3fSGregory Neil Shapiro {
503e92d3f3fSGregory Neil Shapiro int i;
504e92d3f3fSGregory Neil Shapiro int cnt = 0;
505e92d3f3fSGregory Neil Shapiro CTime_T *ct;
506e92d3f3fSGregory Neil Shapiro unsigned int ticks;
507e92d3f3fSGregory Neil Shapiro
5085b0945b5SGregory Neil Shapiro rate_init();
509e92d3f3fSGregory Neil Shapiro ticks = now / ChtGran;
510e92d3f3fSGregory Neil Shapiro
511e92d3f3fSGregory Neil Shapiro /* Let's update data */
512e92d3f3fSGregory Neil Shapiro if (update)
513e92d3f3fSGregory Neil Shapiro {
514e92d3f3fSGregory Neil Shapiro ct = &srv_Times[ticks % CHTSIZE];
515e92d3f3fSGregory Neil Shapiro
516e92d3f3fSGregory Neil Shapiro if (ct->ct_Ticks != ticks)
517e92d3f3fSGregory Neil Shapiro {
518e92d3f3fSGregory Neil Shapiro ct->ct_Ticks = ticks;
519e92d3f3fSGregory Neil Shapiro ct->ct_Count = 0;
520e92d3f3fSGregory Neil Shapiro }
521e92d3f3fSGregory Neil Shapiro ++ct->ct_Count;
522e92d3f3fSGregory Neil Shapiro }
523e92d3f3fSGregory Neil Shapiro
524e92d3f3fSGregory Neil Shapiro /* Let's count connections on the window */
525e92d3f3fSGregory Neil Shapiro for (i = 0; i < CHTSIZE; ++i)
526e92d3f3fSGregory Neil Shapiro {
527e92d3f3fSGregory Neil Shapiro ct = &srv_Times[i];
528e92d3f3fSGregory Neil Shapiro
529e92d3f3fSGregory Neil Shapiro if (ct->ct_Ticks <= ticks && ct->ct_Ticks >= ticks - CHTSIZE)
530e92d3f3fSGregory Neil Shapiro cnt += ct->ct_Count;
531e92d3f3fSGregory Neil Shapiro }
532e92d3f3fSGregory Neil Shapiro
533e92d3f3fSGregory Neil Shapiro #if RATECTL_DEBUG
534e92d3f3fSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID,
5355b0945b5SGregory Neil Shapiro "total: cnt=%d, CHTSIZE=%d, ChtGran=%d",
536e92d3f3fSGregory Neil Shapiro cnt, CHTSIZE, ChtGran);
5375b0945b5SGregory Neil Shapiro #endif
538e92d3f3fSGregory Neil Shapiro
539e92d3f3fSGregory Neil Shapiro return cnt;
540e92d3f3fSGregory Neil Shapiro }
5415b0945b5SGregory Neil Shapiro
5425b0945b5SGregory Neil Shapiro #if RATECTL_DEBUG || _FFR_OCC
5435b0945b5SGregory Neil Shapiro void
dump_ch(fp)5445b0945b5SGregory Neil Shapiro dump_ch(fp)
5455b0945b5SGregory Neil Shapiro SM_FILE_T *fp;
5465b0945b5SGregory Neil Shapiro {
5475b0945b5SGregory Neil Shapiro int i, j, cnt;
5485b0945b5SGregory Neil Shapiro unsigned int ticks;
5495b0945b5SGregory Neil Shapiro
5505b0945b5SGregory Neil Shapiro ticks = time(NULL) / ChtGran;
5515b0945b5SGregory Neil Shapiro sm_io_fprintf(fp, SM_TIME_DEFAULT, "dump_ch\n");
5525b0945b5SGregory Neil Shapiro for (i = 0; i < CPMHSIZE; i++)
5535b0945b5SGregory Neil Shapiro {
5545b0945b5SGregory Neil Shapiro CHash_T *ch = &CHashAry[i];
5555b0945b5SGregory Neil Shapiro bool valid;
5565b0945b5SGregory Neil Shapiro
5575b0945b5SGregory Neil Shapiro valid = false;
5585b0945b5SGregory Neil Shapiro # if NETINET
5595b0945b5SGregory Neil Shapiro valid = (ch->ch_Family == AF_INET);
5605b0945b5SGregory Neil Shapiro if (valid)
5615b0945b5SGregory Neil Shapiro sm_io_fprintf(fp, SM_TIME_DEFAULT, "ip=%s ",
5625b0945b5SGregory Neil Shapiro inet_ntoa(ch->ch_Addr4));
5635b0945b5SGregory Neil Shapiro # endif /* NETINET */
5645b0945b5SGregory Neil Shapiro # if NETINET6
5655b0945b5SGregory Neil Shapiro if (ch->ch_Family == AF_INET6)
5665b0945b5SGregory Neil Shapiro {
5675b0945b5SGregory Neil Shapiro char buf[64], *str;
5685b0945b5SGregory Neil Shapiro
5695b0945b5SGregory Neil Shapiro valid = true;
5705b0945b5SGregory Neil Shapiro str = anynet_ntop(&ch->ch_Addr6, buf, sizeof(buf));
5715b0945b5SGregory Neil Shapiro if (str != NULL)
5725b0945b5SGregory Neil Shapiro sm_io_fprintf(fp, SM_TIME_DEFAULT, "ip=%s ",
5735b0945b5SGregory Neil Shapiro str);
5745b0945b5SGregory Neil Shapiro }
5755b0945b5SGregory Neil Shapiro # endif /* NETINET6 */
5765b0945b5SGregory Neil Shapiro if (!valid)
5775b0945b5SGregory Neil Shapiro continue;
5785b0945b5SGregory Neil Shapiro
5795b0945b5SGregory Neil Shapiro cnt = 0;
5805b0945b5SGregory Neil Shapiro for (j = 0; j < CHTSIZE; ++j)
5815b0945b5SGregory Neil Shapiro {
5825b0945b5SGregory Neil Shapiro CTime_T *cth;
5835b0945b5SGregory Neil Shapiro
5845b0945b5SGregory Neil Shapiro cth = &ch->ch_Times[j];
5855b0945b5SGregory Neil Shapiro if (cth->ct_Ticks <= ticks && cth->ct_Ticks >= ticks - CHTSIZE)
5865b0945b5SGregory Neil Shapiro cnt += cth->ct_Count;
5875b0945b5SGregory Neil Shapiro }
5885b0945b5SGregory Neil Shapiro
5895b0945b5SGregory Neil Shapiro sm_io_fprintf(fp, SM_TIME_DEFAULT, "time=%ld cnt=%d ",
5905b0945b5SGregory Neil Shapiro (long) ch->ch_LTime, cnt);
5915b0945b5SGregory Neil Shapiro # if _FFR_OCC
5925b0945b5SGregory Neil Shapiro sm_io_fprintf(fp, SM_TIME_DEFAULT, "oc=%d", ch->ch_oc);
5935b0945b5SGregory Neil Shapiro # endif
5945b0945b5SGregory Neil Shapiro sm_io_fprintf(fp, SM_TIME_DEFAULT, "\n");
5955b0945b5SGregory Neil Shapiro }
5965b0945b5SGregory Neil Shapiro sm_io_flush(fp, SM_TIME_DEFAULT);
5975b0945b5SGregory Neil Shapiro }
5985b0945b5SGregory Neil Shapiro
5995b0945b5SGregory Neil Shapiro #endif /* RATECTL_DEBUG || _FFR_OCC */
600