xref: /freebsd/contrib/sendmail/src/ratectrl.c (revision 4313cc83440a39bdf976f955b1d4d3f3c4d1552f)
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 
47e92d3f3fSGregory Neil Shapiro #include <sendmail.h>
48*4313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: ratectrl.c,v 8.14 2013-11-22 20:51:56 ca Exp $")
49e92d3f3fSGregory Neil Shapiro 
50e92d3f3fSGregory Neil Shapiro /*
51e92d3f3fSGregory Neil Shapiro **  stuff included - given some warnings (inet_ntoa)
52e92d3f3fSGregory Neil Shapiro **	- surely not everything is needed
53e92d3f3fSGregory Neil Shapiro */
54e92d3f3fSGregory Neil Shapiro 
55e92d3f3fSGregory Neil Shapiro #if NETINET || NETINET6
56e92d3f3fSGregory Neil Shapiro # include <arpa/inet.h>
57e92d3f3fSGregory Neil Shapiro #endif	/* NETINET || NETINET6 */
58e92d3f3fSGregory Neil Shapiro 
594e4196cbSGregory Neil Shapiro #include <sm/time.h>
60e92d3f3fSGregory Neil Shapiro 
61e92d3f3fSGregory Neil Shapiro #ifndef HASH_ALG
62e92d3f3fSGregory Neil Shapiro # define HASH_ALG	2
63e92d3f3fSGregory Neil Shapiro #endif /* HASH_ALG */
64e92d3f3fSGregory Neil Shapiro 
65e92d3f3fSGregory Neil Shapiro #ifndef RATECTL_DEBUG
66e92d3f3fSGregory Neil Shapiro # define RATECTL_DEBUG  0
67e92d3f3fSGregory Neil Shapiro #endif /* RATECTL_DEBUG */
68e92d3f3fSGregory Neil Shapiro 
69e92d3f3fSGregory Neil Shapiro /* forward declarations */
70e92d3f3fSGregory Neil Shapiro static int client_rate __P((time_t, SOCKADDR *, bool));
71e92d3f3fSGregory Neil Shapiro static int total_rate __P((time_t, bool));
72e92d3f3fSGregory Neil Shapiro 
73e92d3f3fSGregory Neil Shapiro /*
74e92d3f3fSGregory Neil Shapiro **  CONNECTION_RATE_CHECK - updates connection history data
75e92d3f3fSGregory Neil Shapiro **      and computes connection rate for the given host
76e92d3f3fSGregory Neil Shapiro **
77e92d3f3fSGregory Neil Shapiro **    Parameters:
78e92d3f3fSGregory Neil Shapiro **      hostaddr -- ip address of smtp client
79e92d3f3fSGregory Neil Shapiro **      e -- envelope
80e92d3f3fSGregory Neil Shapiro **
81e92d3f3fSGregory Neil Shapiro **    Returns:
82e92d3f3fSGregory Neil Shapiro **      true (always)
83e92d3f3fSGregory Neil Shapiro **
84e92d3f3fSGregory Neil Shapiro **    Side Effects:
85e92d3f3fSGregory Neil Shapiro **      updates connection history
86e92d3f3fSGregory Neil Shapiro **
87e92d3f3fSGregory Neil Shapiro **    Warnings:
88e92d3f3fSGregory Neil Shapiro **      For each connection, this call shall be
89e92d3f3fSGregory Neil Shapiro **      done only once with the value true for the
90e92d3f3fSGregory Neil Shapiro **      update parameter.
91e92d3f3fSGregory Neil Shapiro **      Typically, this call is done with the value
92e92d3f3fSGregory Neil Shapiro **      true by the father, and once again with
93e92d3f3fSGregory Neil Shapiro **      the value false by the children.
94e92d3f3fSGregory Neil Shapiro **
95e92d3f3fSGregory Neil Shapiro */
96e92d3f3fSGregory Neil Shapiro 
97e92d3f3fSGregory Neil Shapiro bool
98e92d3f3fSGregory Neil Shapiro connection_rate_check(hostaddr, e)
99e92d3f3fSGregory Neil Shapiro 	SOCKADDR *hostaddr;
100e92d3f3fSGregory Neil Shapiro 	ENVELOPE *e;
101e92d3f3fSGregory Neil Shapiro {
102e92d3f3fSGregory Neil Shapiro 	time_t now;
103e92d3f3fSGregory Neil Shapiro 	int totalrate, clientrate;
104e92d3f3fSGregory Neil Shapiro 	static int clientconn = 0;
105e92d3f3fSGregory Neil Shapiro 
106e92d3f3fSGregory Neil Shapiro 	now = time(NULL);
107e92d3f3fSGregory Neil Shapiro #if RATECTL_DEBUG
108e92d3f3fSGregory Neil Shapiro 	sm_syslog(LOG_INFO, NOQID, "connection_rate_check entering...");
109e92d3f3fSGregory Neil Shapiro #endif /* RATECTL_DEBUG */
110e92d3f3fSGregory Neil Shapiro 
111e92d3f3fSGregory Neil Shapiro 	/* update server connection rate */
112e92d3f3fSGregory Neil Shapiro 	totalrate = total_rate(now, e == NULL);
113e92d3f3fSGregory Neil Shapiro #if RATECTL_DEBUG
114e3793f76SGregory Neil Shapiro 	sm_syslog(LOG_INFO, NOQID, "global connection rate: %d", totalrate);
115e92d3f3fSGregory Neil Shapiro #endif /* RATECTL_DEBUG */
116e92d3f3fSGregory Neil Shapiro 
117e92d3f3fSGregory Neil Shapiro 	/* update client connection rate */
118e92d3f3fSGregory Neil Shapiro 	clientrate = client_rate(now, hostaddr, e == NULL);
119e92d3f3fSGregory Neil Shapiro 
120e92d3f3fSGregory Neil Shapiro 	if (e == NULL)
121e92d3f3fSGregory Neil Shapiro 		clientconn = count_open_connections(hostaddr);
122e92d3f3fSGregory Neil Shapiro 
123e92d3f3fSGregory Neil Shapiro 	if (e != NULL)
124e92d3f3fSGregory Neil Shapiro 	{
125e92d3f3fSGregory Neil Shapiro 		char s[16];
126e92d3f3fSGregory Neil Shapiro 
127e92d3f3fSGregory Neil Shapiro 		sm_snprintf(s, sizeof(s), "%d", clientrate);
128e92d3f3fSGregory Neil Shapiro 		macdefine(&e->e_macro, A_TEMP, macid("{client_rate}"), s);
129e92d3f3fSGregory Neil Shapiro 		sm_snprintf(s, sizeof(s), "%d", totalrate);
130e92d3f3fSGregory Neil Shapiro 		macdefine(&e->e_macro, A_TEMP, macid("{total_rate}"), s);
131e92d3f3fSGregory Neil Shapiro 		sm_snprintf(s, sizeof(s), "%d", clientconn);
132e92d3f3fSGregory Neil Shapiro 		macdefine(&e->e_macro, A_TEMP, macid("{client_connections}"),
133e92d3f3fSGregory Neil Shapiro 				s);
134e92d3f3fSGregory Neil Shapiro 	}
135e92d3f3fSGregory Neil Shapiro 	return true;
136e92d3f3fSGregory Neil Shapiro }
137e92d3f3fSGregory Neil Shapiro 
138e92d3f3fSGregory Neil Shapiro /*
139e92d3f3fSGregory Neil Shapiro **  Data declarations needed to evaluate connection rate
140e92d3f3fSGregory Neil Shapiro */
141e92d3f3fSGregory Neil Shapiro 
142e92d3f3fSGregory Neil Shapiro static int CollTime = 60;
143e92d3f3fSGregory Neil Shapiro 
144e92d3f3fSGregory Neil Shapiro /* this should be a power of 2, otherwise CPMHMASK doesn't work well */
145e92d3f3fSGregory Neil Shapiro #ifndef CPMHSIZE
146e92d3f3fSGregory Neil Shapiro # define CPMHSIZE	1024
147e92d3f3fSGregory Neil Shapiro #endif /* CPMHSIZE */
148e92d3f3fSGregory Neil Shapiro 
149e92d3f3fSGregory Neil Shapiro #define CPMHMASK	(CPMHSIZE-1)
150e92d3f3fSGregory Neil Shapiro 
151e92d3f3fSGregory Neil Shapiro #ifndef MAX_CT_STEPS
152e92d3f3fSGregory Neil Shapiro # define MAX_CT_STEPS	10
153e92d3f3fSGregory Neil Shapiro #endif /* MAX_CT_STEPS */
154e92d3f3fSGregory Neil Shapiro 
155e92d3f3fSGregory Neil Shapiro /*
156e92d3f3fSGregory Neil Shapiro **  time granularity: 10s (that's one "tick")
157e92d3f3fSGregory Neil Shapiro **  will be initialised to ConnectionRateWindowSize/CHTSIZE
158e92d3f3fSGregory Neil Shapiro **  before being used the first time
159e92d3f3fSGregory Neil Shapiro */
160e92d3f3fSGregory Neil Shapiro 
161e92d3f3fSGregory Neil Shapiro static int ChtGran = -1;
162e92d3f3fSGregory Neil Shapiro 
163e92d3f3fSGregory Neil Shapiro #define CHTSIZE		6
164e92d3f3fSGregory Neil Shapiro 
165e92d3f3fSGregory Neil Shapiro /* Number of connections for a certain "tick" */
166e92d3f3fSGregory Neil Shapiro typedef struct CTime
167e92d3f3fSGregory Neil Shapiro {
168e92d3f3fSGregory Neil Shapiro 	unsigned long	ct_Ticks;
169e92d3f3fSGregory Neil Shapiro 	int		ct_Count;
170e92d3f3fSGregory Neil Shapiro }
171e92d3f3fSGregory Neil Shapiro CTime_T;
172e92d3f3fSGregory Neil Shapiro 
173e92d3f3fSGregory Neil Shapiro typedef struct CHash
174e92d3f3fSGregory Neil Shapiro {
175e92d3f3fSGregory Neil Shapiro #if NETINET6 && NETINET
176e92d3f3fSGregory Neil Shapiro 	union
177e92d3f3fSGregory Neil Shapiro 	{
178e92d3f3fSGregory Neil Shapiro 		struct in_addr	c4_Addr;
179e92d3f3fSGregory Neil Shapiro 		struct in6_addr	c6_Addr;
180e92d3f3fSGregory Neil Shapiro 	} cu_Addr;
181e92d3f3fSGregory Neil Shapiro # define ch_Addr4	cu_Addr.c4_Addr
182e92d3f3fSGregory Neil Shapiro # define ch_Addr6	cu_Addr.c6_Addr
183e92d3f3fSGregory Neil Shapiro #else /* NETINET6 && NETINET */
184e92d3f3fSGregory Neil Shapiro # if NETINET6
185e92d3f3fSGregory Neil Shapiro 	struct in6_addr	ch_Addr;
186e92d3f3fSGregory Neil Shapiro #  define ch_Addr6	ch_Addr
187e92d3f3fSGregory Neil Shapiro # else /* NETINET6 */
188e92d3f3fSGregory Neil Shapiro 	struct in_addr ch_Addr;
189e92d3f3fSGregory Neil Shapiro #  define ch_Addr4	ch_Addr
190e92d3f3fSGregory Neil Shapiro # endif /* NETINET6 */
191e92d3f3fSGregory Neil Shapiro #endif /* NETINET6 && NETINET */
192e92d3f3fSGregory Neil Shapiro 
193e92d3f3fSGregory Neil Shapiro 	int		ch_Family;
194e92d3f3fSGregory Neil Shapiro 	time_t		ch_LTime;
195e92d3f3fSGregory Neil Shapiro 	unsigned long	ch_colls;
196e92d3f3fSGregory Neil Shapiro 
197e92d3f3fSGregory Neil Shapiro 	/* 6 buckets for ticks: 60s */
198e92d3f3fSGregory Neil Shapiro 	CTime_T		ch_Times[CHTSIZE];
199e92d3f3fSGregory Neil Shapiro }
200e92d3f3fSGregory Neil Shapiro CHash_T;
201e92d3f3fSGregory Neil Shapiro 
202e92d3f3fSGregory Neil Shapiro static CHash_T CHashAry[CPMHSIZE];
203e92d3f3fSGregory Neil Shapiro static bool CHashAryOK = false;
204e92d3f3fSGregory Neil Shapiro 
205e92d3f3fSGregory Neil Shapiro /*
206e92d3f3fSGregory Neil Shapiro **  CLIENT_RATE - Evaluate connection rate per smtp client
207e92d3f3fSGregory Neil Shapiro **
208e92d3f3fSGregory Neil Shapiro **	Parameters:
209e92d3f3fSGregory Neil Shapiro **		now - current time in secs
210e92d3f3fSGregory Neil Shapiro **		saddr - client address
211e92d3f3fSGregory Neil Shapiro **		update - update data / check only
212e92d3f3fSGregory Neil Shapiro **
213e92d3f3fSGregory Neil Shapiro **	Returns:
214e92d3f3fSGregory Neil Shapiro **		connection rate (connections / ConnectionRateWindowSize)
215e92d3f3fSGregory Neil Shapiro **
216e92d3f3fSGregory Neil Shapiro **	Side effects:
217e92d3f3fSGregory Neil Shapiro **		update static global data
218e92d3f3fSGregory Neil Shapiro **
219e92d3f3fSGregory Neil Shapiro */
220e92d3f3fSGregory Neil Shapiro 
221e92d3f3fSGregory Neil Shapiro static int
222e92d3f3fSGregory Neil Shapiro client_rate(now, saddr, update)
223e92d3f3fSGregory Neil Shapiro 	 time_t now;
224e92d3f3fSGregory Neil Shapiro 	 SOCKADDR *saddr;
225e92d3f3fSGregory Neil Shapiro 	 bool update;
226e92d3f3fSGregory Neil Shapiro {
227e92d3f3fSGregory Neil Shapiro 	unsigned int hv;
228e92d3f3fSGregory Neil Shapiro 	int i;
229e92d3f3fSGregory Neil Shapiro 	int cnt;
230e92d3f3fSGregory Neil Shapiro 	bool coll;
231e92d3f3fSGregory Neil Shapiro 	CHash_T *chBest = NULL;
232e92d3f3fSGregory Neil Shapiro 	unsigned int ticks;
233e92d3f3fSGregory Neil Shapiro 
234e92d3f3fSGregory Neil Shapiro 	cnt = 0;
235e92d3f3fSGregory Neil Shapiro 	hv = 0xABC3D20F;
236e92d3f3fSGregory Neil Shapiro 	if (ChtGran < 0)
237e92d3f3fSGregory Neil Shapiro 		ChtGran = ConnectionRateWindowSize / CHTSIZE;
238e92d3f3fSGregory Neil Shapiro 	if (ChtGran <= 0)
239e92d3f3fSGregory Neil Shapiro 		ChtGran = 10;
240e92d3f3fSGregory Neil Shapiro 
241e92d3f3fSGregory Neil Shapiro 	ticks = now / ChtGran;
242e92d3f3fSGregory Neil Shapiro 
243e92d3f3fSGregory Neil Shapiro 	if (!CHashAryOK)
244e92d3f3fSGregory Neil Shapiro 	{
245e92d3f3fSGregory Neil Shapiro 		memset(CHashAry, 0, sizeof(CHashAry));
246e92d3f3fSGregory Neil Shapiro 		CHashAryOK = true;
247e92d3f3fSGregory Neil Shapiro 	}
248e92d3f3fSGregory Neil Shapiro 
249e92d3f3fSGregory Neil Shapiro 	{
250e92d3f3fSGregory Neil Shapiro 		char *p;
251e92d3f3fSGregory Neil Shapiro 		int addrlen;
252e92d3f3fSGregory Neil Shapiro #if HASH_ALG != 1
253e92d3f3fSGregory Neil Shapiro 		int c, d;
254e92d3f3fSGregory Neil Shapiro #endif /* HASH_ALG != 1 */
255e92d3f3fSGregory Neil Shapiro 
256e92d3f3fSGregory Neil Shapiro 		switch (saddr->sa.sa_family)
257e92d3f3fSGregory Neil Shapiro 		{
258e92d3f3fSGregory Neil Shapiro #if NETINET
259e92d3f3fSGregory Neil Shapiro 		  case AF_INET:
260e92d3f3fSGregory Neil Shapiro 			p = (char *)&saddr->sin.sin_addr;
261e92d3f3fSGregory Neil Shapiro 			addrlen = sizeof(struct in_addr);
262e92d3f3fSGregory Neil Shapiro 			break;
263e92d3f3fSGregory Neil Shapiro #endif /* NETINET */
264e92d3f3fSGregory Neil Shapiro #if NETINET6
265e92d3f3fSGregory Neil Shapiro 		  case AF_INET6:
266e92d3f3fSGregory Neil Shapiro 			p = (char *)&saddr->sin6.sin6_addr;
267e92d3f3fSGregory Neil Shapiro 			addrlen = sizeof(struct in6_addr);
268e92d3f3fSGregory Neil Shapiro 			break;
269e92d3f3fSGregory Neil Shapiro #endif /* NETINET6 */
270e92d3f3fSGregory Neil Shapiro 		  default:
271e92d3f3fSGregory Neil Shapiro 			/* should not happen */
272e92d3f3fSGregory Neil Shapiro 			return -1;
273e92d3f3fSGregory Neil Shapiro 		}
274e92d3f3fSGregory Neil Shapiro 
275e92d3f3fSGregory Neil Shapiro 		/* compute hash value */
276e92d3f3fSGregory Neil Shapiro 		for (i = 0; i < addrlen; ++i, ++p)
277e92d3f3fSGregory Neil Shapiro #if HASH_ALG == 1
278e92d3f3fSGregory Neil Shapiro 			hv = (hv << 5) ^ (hv >> 23) ^ *p;
279e92d3f3fSGregory Neil Shapiro 		hv = (hv ^ (hv >> 16));
280e92d3f3fSGregory Neil Shapiro #elif HASH_ALG == 2
281e92d3f3fSGregory Neil Shapiro 		{
282e92d3f3fSGregory Neil Shapiro 			d = *p;
283e92d3f3fSGregory Neil Shapiro 			c = d;
284e92d3f3fSGregory Neil Shapiro 			c ^= c<<6;
285e92d3f3fSGregory Neil Shapiro 			hv += (c<<11) ^ (c>>1);
286e92d3f3fSGregory Neil Shapiro 			hv ^= (d<<14) + (d<<7) + (d<<4) + d;
287e92d3f3fSGregory Neil Shapiro 		}
288e92d3f3fSGregory Neil Shapiro #elif HASH_ALG == 3
289e92d3f3fSGregory Neil Shapiro 		{
290e92d3f3fSGregory Neil Shapiro 			hv = (hv << 4) + *p;
291e92d3f3fSGregory Neil Shapiro 			d = hv & 0xf0000000;
292e92d3f3fSGregory Neil Shapiro 			if (d != 0)
293e92d3f3fSGregory Neil Shapiro 			{
294e92d3f3fSGregory Neil Shapiro 				hv ^= (d >> 24);
295e92d3f3fSGregory Neil Shapiro 				hv ^= d;
296e92d3f3fSGregory Neil Shapiro 			}
297e92d3f3fSGregory Neil Shapiro 		}
298e92d3f3fSGregory Neil Shapiro #else /* HASH_ALG == 1 */
299e92d3f3fSGregory Neil Shapiro 			hv = ((hv << 1) ^ (*p & 0377)) % cctx->cc_size;
300e92d3f3fSGregory Neil Shapiro #endif /* HASH_ALG == 1 */
301e92d3f3fSGregory Neil Shapiro 	}
302e92d3f3fSGregory Neil Shapiro 
303e92d3f3fSGregory Neil Shapiro 	coll = true;
304e92d3f3fSGregory Neil Shapiro 	for (i = 0; i < MAX_CT_STEPS; ++i)
305e92d3f3fSGregory Neil Shapiro 	{
306e92d3f3fSGregory Neil Shapiro 		CHash_T *ch = &CHashAry[(hv + i) & CPMHMASK];
307e92d3f3fSGregory Neil Shapiro 
308e92d3f3fSGregory Neil Shapiro #if NETINET
309e92d3f3fSGregory Neil Shapiro 		if (saddr->sa.sa_family == AF_INET &&
310e92d3f3fSGregory Neil Shapiro 		    ch->ch_Family == AF_INET &&
311e92d3f3fSGregory Neil Shapiro 		    (saddr->sin.sin_addr.s_addr == ch->ch_Addr4.s_addr ||
312e92d3f3fSGregory Neil Shapiro 		     ch->ch_Addr4.s_addr == 0))
313e92d3f3fSGregory Neil Shapiro 		{
314e92d3f3fSGregory Neil Shapiro 			chBest = ch;
315e92d3f3fSGregory Neil Shapiro 			coll = false;
316e92d3f3fSGregory Neil Shapiro 			break;
317e92d3f3fSGregory Neil Shapiro 		}
318e92d3f3fSGregory Neil Shapiro #endif /* NETINET */
319e92d3f3fSGregory Neil Shapiro #if NETINET6
320e92d3f3fSGregory Neil Shapiro 		if (saddr->sa.sa_family == AF_INET6 &&
321e92d3f3fSGregory Neil Shapiro 		    ch->ch_Family == AF_INET6 &&
322e92d3f3fSGregory Neil Shapiro 		    (IN6_ARE_ADDR_EQUAL(&saddr->sin6.sin6_addr,
323e92d3f3fSGregory Neil Shapiro 				       &ch->ch_Addr6) != 0 ||
324e92d3f3fSGregory Neil Shapiro 		     IN6_IS_ADDR_UNSPECIFIED(&ch->ch_Addr6)))
325e92d3f3fSGregory Neil Shapiro 		{
326e92d3f3fSGregory Neil Shapiro 			chBest = ch;
327e92d3f3fSGregory Neil Shapiro 			coll = false;
328e92d3f3fSGregory Neil Shapiro 			break;
329e92d3f3fSGregory Neil Shapiro 		}
330e92d3f3fSGregory Neil Shapiro #endif /* NETINET6 */
331e92d3f3fSGregory Neil Shapiro 		if (chBest == NULL || ch->ch_LTime == 0 ||
332e92d3f3fSGregory Neil Shapiro 		    ch->ch_LTime < chBest->ch_LTime)
333e92d3f3fSGregory Neil Shapiro 			chBest = ch;
334e92d3f3fSGregory Neil Shapiro 	}
335e92d3f3fSGregory Neil Shapiro 
336e92d3f3fSGregory Neil Shapiro 	/* Let's update data... */
337e92d3f3fSGregory Neil Shapiro 	if (update)
338e92d3f3fSGregory Neil Shapiro 	{
339e92d3f3fSGregory Neil Shapiro 		if (coll && (now - chBest->ch_LTime < CollTime))
340e92d3f3fSGregory Neil Shapiro 		{
341e92d3f3fSGregory Neil Shapiro 			/*
342e92d3f3fSGregory Neil Shapiro 			**  increment the number of collisions last
343e92d3f3fSGregory Neil Shapiro 			**  CollTime for this client
344e92d3f3fSGregory Neil Shapiro 			*/
345e92d3f3fSGregory Neil Shapiro 
346e92d3f3fSGregory Neil Shapiro 			chBest->ch_colls++;
347e92d3f3fSGregory Neil Shapiro 
348e92d3f3fSGregory Neil Shapiro 			/*
349e92d3f3fSGregory Neil Shapiro 			**  Maybe shall log if collision rate is too high...
350e92d3f3fSGregory Neil Shapiro 			**  and take measures to resize tables
351e92d3f3fSGregory Neil Shapiro 			**  if this is the case
352e92d3f3fSGregory Neil Shapiro 			*/
353e92d3f3fSGregory Neil Shapiro 		}
354e92d3f3fSGregory Neil Shapiro 
355e92d3f3fSGregory Neil Shapiro 		/*
356e92d3f3fSGregory Neil Shapiro 		**  If it's not a match, then replace the data.
357e92d3f3fSGregory Neil Shapiro 		**  Note: this purges the history of a colliding entry,
358e92d3f3fSGregory Neil Shapiro 		**  which may cause "overruns", i.e., if two entries are
359e92d3f3fSGregory Neil Shapiro 		**  "cancelling" each other out, then they may exceed
360e92d3f3fSGregory Neil Shapiro 		**  the limits that are set. This might be mitigated a bit
361e92d3f3fSGregory Neil Shapiro 		**  by the above "best of 5" function however.
362e92d3f3fSGregory Neil Shapiro 		**
363e92d3f3fSGregory Neil Shapiro 		**  Alternative approach: just use the old data, which may
364e92d3f3fSGregory Neil Shapiro 		**  cause false positives however.
365e92d3f3fSGregory Neil Shapiro 		**  To activate this, change deactivate following memset call.
366e92d3f3fSGregory Neil Shapiro 		*/
367e92d3f3fSGregory Neil Shapiro 
368e92d3f3fSGregory Neil Shapiro 		if (coll)
369e92d3f3fSGregory Neil Shapiro 		{
370e92d3f3fSGregory Neil Shapiro #if NETINET
371e92d3f3fSGregory Neil Shapiro 			if (saddr->sa.sa_family == AF_INET)
372e92d3f3fSGregory Neil Shapiro 			{
373e92d3f3fSGregory Neil Shapiro 				chBest->ch_Family = AF_INET;
374e92d3f3fSGregory Neil Shapiro 				chBest->ch_Addr4 = saddr->sin.sin_addr;
375e92d3f3fSGregory Neil Shapiro 			}
376e92d3f3fSGregory Neil Shapiro #endif /* NETINET */
377e92d3f3fSGregory Neil Shapiro #if NETINET6
378e92d3f3fSGregory Neil Shapiro 			if (saddr->sa.sa_family == AF_INET6)
379e92d3f3fSGregory Neil Shapiro 			{
380e92d3f3fSGregory Neil Shapiro 				chBest->ch_Family = AF_INET6;
381e92d3f3fSGregory Neil Shapiro 				chBest->ch_Addr6 = saddr->sin6.sin6_addr;
382e92d3f3fSGregory Neil Shapiro 			}
383e92d3f3fSGregory Neil Shapiro #endif /* NETINET6 */
384e92d3f3fSGregory Neil Shapiro #if 1
385e92d3f3fSGregory Neil Shapiro 			memset(chBest->ch_Times, '\0',
386e92d3f3fSGregory Neil Shapiro 			       sizeof(chBest->ch_Times));
387e92d3f3fSGregory Neil Shapiro #endif /* 1 */
388e92d3f3fSGregory Neil Shapiro 		}
389e92d3f3fSGregory Neil Shapiro 
390e92d3f3fSGregory Neil Shapiro 		chBest->ch_LTime = now;
391e92d3f3fSGregory Neil Shapiro 		{
392e92d3f3fSGregory Neil Shapiro 			CTime_T *ct = &chBest->ch_Times[ticks % CHTSIZE];
393e92d3f3fSGregory Neil Shapiro 
394e92d3f3fSGregory Neil Shapiro 			if (ct->ct_Ticks != ticks)
395e92d3f3fSGregory Neil Shapiro 			{
396e92d3f3fSGregory Neil Shapiro 				ct->ct_Ticks = ticks;
397e92d3f3fSGregory Neil Shapiro 				ct->ct_Count = 0;
398e92d3f3fSGregory Neil Shapiro 			}
399e92d3f3fSGregory Neil Shapiro 			++ct->ct_Count;
400e92d3f3fSGregory Neil Shapiro 		}
401e92d3f3fSGregory Neil Shapiro 	}
402e92d3f3fSGregory Neil Shapiro 
403e92d3f3fSGregory Neil Shapiro 	/* Now let's count connections on the window */
404e92d3f3fSGregory Neil Shapiro 	for (i = 0; i < CHTSIZE; ++i)
405e92d3f3fSGregory Neil Shapiro 	{
406e92d3f3fSGregory Neil Shapiro 		CTime_T *ct = &chBest->ch_Times[i];
407e92d3f3fSGregory Neil Shapiro 
408e92d3f3fSGregory Neil Shapiro 		if (ct->ct_Ticks <= ticks && ct->ct_Ticks >= ticks - CHTSIZE)
409e92d3f3fSGregory Neil Shapiro 			cnt += ct->ct_Count;
410e92d3f3fSGregory Neil Shapiro 	}
411e92d3f3fSGregory Neil Shapiro 
412e92d3f3fSGregory Neil Shapiro #if RATECTL_DEBUG
413e92d3f3fSGregory Neil Shapiro 	sm_syslog(LOG_WARNING, NOQID,
414e92d3f3fSGregory Neil Shapiro 		"cln: cnt=(%d), CHTSIZE=(%d), ChtGran=(%d)",
415e92d3f3fSGregory Neil Shapiro 		cnt, CHTSIZE, ChtGran);
416e92d3f3fSGregory Neil Shapiro #endif /* RATECTL_DEBUG */
417e92d3f3fSGregory Neil Shapiro 	return cnt;
418e92d3f3fSGregory Neil Shapiro }
419e92d3f3fSGregory Neil Shapiro 
420e92d3f3fSGregory Neil Shapiro /*
421e92d3f3fSGregory Neil Shapiro **  TOTAL_RATE - Evaluate global connection rate
422e92d3f3fSGregory Neil Shapiro **
423e92d3f3fSGregory Neil Shapiro **	Parameters:
424e92d3f3fSGregory Neil Shapiro **		now - current time in secs
425e92d3f3fSGregory Neil Shapiro **		update - update data / check only
426e92d3f3fSGregory Neil Shapiro **
427e92d3f3fSGregory Neil Shapiro **	Returns:
428e92d3f3fSGregory Neil Shapiro **		connection rate (connections / ConnectionRateWindowSize)
429e92d3f3fSGregory Neil Shapiro */
430e92d3f3fSGregory Neil Shapiro 
431e92d3f3fSGregory Neil Shapiro static CTime_T srv_Times[CHTSIZE];
432e92d3f3fSGregory Neil Shapiro static bool srv_Times_OK = false;
433e92d3f3fSGregory Neil Shapiro 
434e92d3f3fSGregory Neil Shapiro static int
435e92d3f3fSGregory Neil Shapiro total_rate(now, update)
436e92d3f3fSGregory Neil Shapiro 	 time_t now;
437e92d3f3fSGregory Neil Shapiro 	 bool update;
438e92d3f3fSGregory Neil Shapiro {
439e92d3f3fSGregory Neil Shapiro 	int i;
440e92d3f3fSGregory Neil Shapiro 	int cnt = 0;
441e92d3f3fSGregory Neil Shapiro 	CTime_T *ct;
442e92d3f3fSGregory Neil Shapiro 	unsigned int ticks;
443e92d3f3fSGregory Neil Shapiro 
444e92d3f3fSGregory Neil Shapiro 	if (ChtGran < 0)
445e92d3f3fSGregory Neil Shapiro 		ChtGran = ConnectionRateWindowSize / CHTSIZE;
446e92d3f3fSGregory Neil Shapiro 	if (ChtGran == 0)
447e92d3f3fSGregory Neil Shapiro 		ChtGran = 10;
448e92d3f3fSGregory Neil Shapiro 	ticks = now / ChtGran;
449e92d3f3fSGregory Neil Shapiro 	if (!srv_Times_OK)
450e92d3f3fSGregory Neil Shapiro 	{
451e92d3f3fSGregory Neil Shapiro 		memset(srv_Times, 0, sizeof(srv_Times));
452e92d3f3fSGregory Neil Shapiro 		srv_Times_OK = true;
453e92d3f3fSGregory Neil Shapiro 	}
454e92d3f3fSGregory Neil Shapiro 
455e92d3f3fSGregory Neil Shapiro 	/* Let's update data */
456e92d3f3fSGregory Neil Shapiro 	if (update)
457e92d3f3fSGregory Neil Shapiro 	{
458e92d3f3fSGregory Neil Shapiro 		ct = &srv_Times[ticks % CHTSIZE];
459e92d3f3fSGregory Neil Shapiro 
460e92d3f3fSGregory Neil Shapiro 		if (ct->ct_Ticks != ticks)
461e92d3f3fSGregory Neil Shapiro 		{
462e92d3f3fSGregory Neil Shapiro 			ct->ct_Ticks = ticks;
463e92d3f3fSGregory Neil Shapiro 			ct->ct_Count = 0;
464e92d3f3fSGregory Neil Shapiro 		}
465e92d3f3fSGregory Neil Shapiro 		++ct->ct_Count;
466e92d3f3fSGregory Neil Shapiro 	}
467e92d3f3fSGregory Neil Shapiro 
468e92d3f3fSGregory Neil Shapiro 	/* Let's count connections on the window */
469e92d3f3fSGregory Neil Shapiro 	for (i = 0; i < CHTSIZE; ++i)
470e92d3f3fSGregory Neil Shapiro 	{
471e92d3f3fSGregory Neil Shapiro 		ct = &srv_Times[i];
472e92d3f3fSGregory Neil Shapiro 
473e92d3f3fSGregory Neil Shapiro 		if (ct->ct_Ticks <= ticks && ct->ct_Ticks >= ticks - CHTSIZE)
474e92d3f3fSGregory Neil Shapiro 			cnt += ct->ct_Count;
475e92d3f3fSGregory Neil Shapiro 	}
476e92d3f3fSGregory Neil Shapiro 
477e92d3f3fSGregory Neil Shapiro #if RATECTL_DEBUG
478e92d3f3fSGregory Neil Shapiro 	sm_syslog(LOG_WARNING, NOQID,
479e92d3f3fSGregory Neil Shapiro 		"srv: cnt=(%d), CHTSIZE=(%d), ChtGran=(%d)",
480e92d3f3fSGregory Neil Shapiro 		 cnt, CHTSIZE, ChtGran);
481e92d3f3fSGregory Neil Shapiro #endif /* RATECTL_DEBUG */
482e92d3f3fSGregory Neil Shapiro 
483e92d3f3fSGregory Neil Shapiro 	return cnt;
484e92d3f3fSGregory Neil Shapiro }
485