xref: /illumos-gate/usr/src/cmd/sendmail/src/ratectrl.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright (c) 2003 Sendmail, Inc. and its suppliers.
3*7c478bd9Sstevel@tonic-gate  *	All rights reserved.
4*7c478bd9Sstevel@tonic-gate  *
5*7c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
6*7c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
7*7c478bd9Sstevel@tonic-gate  * the sendmail distribution.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * Contributed by Jose Marcio Martins da Cruz - Ecole des Mines de Paris
10*7c478bd9Sstevel@tonic-gate  *   Jose-Marcio.Martins@ensmp.fr
11*7c478bd9Sstevel@tonic-gate  */
12*7c478bd9Sstevel@tonic-gate 
13*7c478bd9Sstevel@tonic-gate /* a part of this code is based on inetd.c for which this copyright applies: */
14*7c478bd9Sstevel@tonic-gate /*
15*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1983, 1991, 1993, 1994
16*7c478bd9Sstevel@tonic-gate  *      The Regents of the University of California.  All rights reserved.
17*7c478bd9Sstevel@tonic-gate  *
18*7c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
19*7c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
20*7c478bd9Sstevel@tonic-gate  * are met:
21*7c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
22*7c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
23*7c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
24*7c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
25*7c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
26*7c478bd9Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
27*7c478bd9Sstevel@tonic-gate  *    must display the following acknowledgement:
28*7c478bd9Sstevel@tonic-gate  *      This product includes software developed by the University of
29*7c478bd9Sstevel@tonic-gate  *      California, Berkeley and its contributors.
30*7c478bd9Sstevel@tonic-gate  * 4. Neither the name of the University nor the names of its contributors
31*7c478bd9Sstevel@tonic-gate  *    may be used to endorse or promote products derived from this software
32*7c478bd9Sstevel@tonic-gate  *    without specific prior written permission.
33*7c478bd9Sstevel@tonic-gate  *
34*7c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35*7c478bd9Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36*7c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37*7c478bd9Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38*7c478bd9Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39*7c478bd9Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40*7c478bd9Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41*7c478bd9Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42*7c478bd9Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43*7c478bd9Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44*7c478bd9Sstevel@tonic-gate  * SUCH DAMAGE.
45*7c478bd9Sstevel@tonic-gate  */
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate #include <sendmail.h>
50*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: ratectrl.c,v 8.9 2004/07/07 21:23:57 ca Exp $")
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate /*
53*7c478bd9Sstevel@tonic-gate **  stuff included - given some warnings (inet_ntoa)
54*7c478bd9Sstevel@tonic-gate **	- surely not everything is needed
55*7c478bd9Sstevel@tonic-gate */
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate #if NETINET || NETINET6
58*7c478bd9Sstevel@tonic-gate # include <arpa/inet.h>
59*7c478bd9Sstevel@tonic-gate #endif	/* NETINET || NETINET6 */
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate #ifndef HASH_ALG
64*7c478bd9Sstevel@tonic-gate # define HASH_ALG	2
65*7c478bd9Sstevel@tonic-gate #endif /* HASH_ALG */
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate #ifndef RATECTL_DEBUG
68*7c478bd9Sstevel@tonic-gate # define RATECTL_DEBUG  0
69*7c478bd9Sstevel@tonic-gate #endif /* RATECTL_DEBUG */
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate /* forward declarations */
72*7c478bd9Sstevel@tonic-gate static int client_rate __P((time_t, SOCKADDR *, bool));
73*7c478bd9Sstevel@tonic-gate static int total_rate __P((time_t, bool));
74*7c478bd9Sstevel@tonic-gate #if 0
75*7c478bd9Sstevel@tonic-gate static int sockaddrcmp __P((SOCKADDR *, SOCKADDR *));
76*7c478bd9Sstevel@tonic-gate #endif /* 0 */
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate /*
79*7c478bd9Sstevel@tonic-gate **  CONNECTION_RATE_CHECK - updates connection history data
80*7c478bd9Sstevel@tonic-gate **      and computes connection rate for the given host
81*7c478bd9Sstevel@tonic-gate **
82*7c478bd9Sstevel@tonic-gate **    Parameters:
83*7c478bd9Sstevel@tonic-gate **      hostaddr -- ip address of smtp client
84*7c478bd9Sstevel@tonic-gate **      e -- envelope
85*7c478bd9Sstevel@tonic-gate **
86*7c478bd9Sstevel@tonic-gate **    Returns:
87*7c478bd9Sstevel@tonic-gate **      true (always)
88*7c478bd9Sstevel@tonic-gate **
89*7c478bd9Sstevel@tonic-gate **    Side Effects:
90*7c478bd9Sstevel@tonic-gate **      updates connection history
91*7c478bd9Sstevel@tonic-gate **
92*7c478bd9Sstevel@tonic-gate **    Warnings:
93*7c478bd9Sstevel@tonic-gate **      For each connection, this call shall be
94*7c478bd9Sstevel@tonic-gate **      done only once with the value true for the
95*7c478bd9Sstevel@tonic-gate **      update parameter.
96*7c478bd9Sstevel@tonic-gate **      Typically, this call is done with the value
97*7c478bd9Sstevel@tonic-gate **      true by the father, and once again with
98*7c478bd9Sstevel@tonic-gate **      the value false by the children.
99*7c478bd9Sstevel@tonic-gate **
100*7c478bd9Sstevel@tonic-gate */
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate bool
103*7c478bd9Sstevel@tonic-gate connection_rate_check(hostaddr, e)
104*7c478bd9Sstevel@tonic-gate 	SOCKADDR *hostaddr;
105*7c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
106*7c478bd9Sstevel@tonic-gate {
107*7c478bd9Sstevel@tonic-gate 	time_t now;
108*7c478bd9Sstevel@tonic-gate 	int totalrate, clientrate;
109*7c478bd9Sstevel@tonic-gate 	static int clientconn = 0;
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate 	now = time(NULL);
112*7c478bd9Sstevel@tonic-gate #if RATECTL_DEBUG
113*7c478bd9Sstevel@tonic-gate 	sm_syslog(LOG_INFO, NOQID, "connection_rate_check entering...");
114*7c478bd9Sstevel@tonic-gate #endif /* RATECTL_DEBUG */
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	/* update server connection rate */
117*7c478bd9Sstevel@tonic-gate 	totalrate = total_rate(now, e == NULL);
118*7c478bd9Sstevel@tonic-gate #if RATECTL_DEBUG
119*7c478bd9Sstevel@tonic-gate 	sm_syslog(LOG_INFO, NOQID, "global connection rate: %d", globalRate);
120*7c478bd9Sstevel@tonic-gate #endif /* RATECTL_DEBUG */
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate 	/* update client connection rate */
123*7c478bd9Sstevel@tonic-gate 	clientrate = client_rate(now, hostaddr, e == NULL);
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	if (e == NULL)
126*7c478bd9Sstevel@tonic-gate 		clientconn = count_open_connections(hostaddr);
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	if (e != NULL)
129*7c478bd9Sstevel@tonic-gate 	{
130*7c478bd9Sstevel@tonic-gate 		char s[16];
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 		sm_snprintf(s, sizeof(s), "%d", clientrate);
133*7c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_TEMP, macid("{client_rate}"), s);
134*7c478bd9Sstevel@tonic-gate 		sm_snprintf(s, sizeof(s), "%d", totalrate);
135*7c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_TEMP, macid("{total_rate}"), s);
136*7c478bd9Sstevel@tonic-gate 		sm_snprintf(s, sizeof(s), "%d", clientconn);
137*7c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_TEMP, macid("{client_connections}"),
138*7c478bd9Sstevel@tonic-gate 				s);
139*7c478bd9Sstevel@tonic-gate 	}
140*7c478bd9Sstevel@tonic-gate 	return true;
141*7c478bd9Sstevel@tonic-gate }
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate /*
144*7c478bd9Sstevel@tonic-gate **  Data declarations needed to evaluate connection rate
145*7c478bd9Sstevel@tonic-gate */
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate static int CollTime = 60;
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate /* this should be a power of 2, otherwise CPMHMASK doesn't work well */
150*7c478bd9Sstevel@tonic-gate #ifndef CPMHSIZE
151*7c478bd9Sstevel@tonic-gate # define CPMHSIZE	1024
152*7c478bd9Sstevel@tonic-gate #endif /* CPMHSIZE */
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate #define CPMHMASK	(CPMHSIZE-1)
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate #ifndef MAX_CT_STEPS
157*7c478bd9Sstevel@tonic-gate # define MAX_CT_STEPS	10
158*7c478bd9Sstevel@tonic-gate #endif /* MAX_CT_STEPS */
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate /*
161*7c478bd9Sstevel@tonic-gate **  time granularity: 10s (that's one "tick")
162*7c478bd9Sstevel@tonic-gate **  will be initialised to ConnectionRateWindowSize/CHTSIZE
163*7c478bd9Sstevel@tonic-gate **  before being used the first time
164*7c478bd9Sstevel@tonic-gate */
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate static int ChtGran = -1;
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate #define CHTSIZE		6
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate /* Number of connections for a certain "tick" */
171*7c478bd9Sstevel@tonic-gate typedef struct CTime
172*7c478bd9Sstevel@tonic-gate {
173*7c478bd9Sstevel@tonic-gate 	unsigned long	ct_Ticks;
174*7c478bd9Sstevel@tonic-gate 	int		ct_Count;
175*7c478bd9Sstevel@tonic-gate }
176*7c478bd9Sstevel@tonic-gate CTime_T;
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate typedef struct CHash
179*7c478bd9Sstevel@tonic-gate {
180*7c478bd9Sstevel@tonic-gate #if NETINET6 && NETINET
181*7c478bd9Sstevel@tonic-gate 	union
182*7c478bd9Sstevel@tonic-gate 	{
183*7c478bd9Sstevel@tonic-gate 		struct in_addr	c4_Addr;
184*7c478bd9Sstevel@tonic-gate 		struct in6_addr	c6_Addr;
185*7c478bd9Sstevel@tonic-gate 	} cu_Addr;
186*7c478bd9Sstevel@tonic-gate # define ch_Addr4	cu_Addr.c4_Addr
187*7c478bd9Sstevel@tonic-gate # define ch_Addr6	cu_Addr.c6_Addr
188*7c478bd9Sstevel@tonic-gate #else /* NETINET6 && NETINET */
189*7c478bd9Sstevel@tonic-gate # if NETINET6
190*7c478bd9Sstevel@tonic-gate 	struct in6_addr	ch_Addr;
191*7c478bd9Sstevel@tonic-gate #  define ch_Addr6	ch_Addr
192*7c478bd9Sstevel@tonic-gate # else /* NETINET6 */
193*7c478bd9Sstevel@tonic-gate 	struct in_addr ch_Addr;
194*7c478bd9Sstevel@tonic-gate #  define ch_Addr4	ch_Addr
195*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
196*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 && NETINET */
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	int		ch_Family;
199*7c478bd9Sstevel@tonic-gate 	time_t		ch_LTime;
200*7c478bd9Sstevel@tonic-gate 	unsigned long	ch_colls;
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 	/* 6 buckets for ticks: 60s */
203*7c478bd9Sstevel@tonic-gate 	CTime_T		ch_Times[CHTSIZE];
204*7c478bd9Sstevel@tonic-gate }
205*7c478bd9Sstevel@tonic-gate CHash_T;
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate static CHash_T CHashAry[CPMHSIZE];
208*7c478bd9Sstevel@tonic-gate static bool CHashAryOK = false;
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate /*
211*7c478bd9Sstevel@tonic-gate **  CLIENT_RATE - Evaluate connection rate per smtp client
212*7c478bd9Sstevel@tonic-gate **
213*7c478bd9Sstevel@tonic-gate **	Parameters:
214*7c478bd9Sstevel@tonic-gate **		now - current time in secs
215*7c478bd9Sstevel@tonic-gate **		saddr - client address
216*7c478bd9Sstevel@tonic-gate **		update - update data / check only
217*7c478bd9Sstevel@tonic-gate **
218*7c478bd9Sstevel@tonic-gate **	Returns:
219*7c478bd9Sstevel@tonic-gate **		connection rate (connections / ConnectionRateWindowSize)
220*7c478bd9Sstevel@tonic-gate **
221*7c478bd9Sstevel@tonic-gate **	Side effects:
222*7c478bd9Sstevel@tonic-gate **		update static global data
223*7c478bd9Sstevel@tonic-gate **
224*7c478bd9Sstevel@tonic-gate */
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate static int
227*7c478bd9Sstevel@tonic-gate client_rate(now, saddr, update)
228*7c478bd9Sstevel@tonic-gate 	 time_t now;
229*7c478bd9Sstevel@tonic-gate 	 SOCKADDR *saddr;
230*7c478bd9Sstevel@tonic-gate 	 bool update;
231*7c478bd9Sstevel@tonic-gate {
232*7c478bd9Sstevel@tonic-gate 	unsigned int hv;
233*7c478bd9Sstevel@tonic-gate 	int i;
234*7c478bd9Sstevel@tonic-gate 	int cnt;
235*7c478bd9Sstevel@tonic-gate 	bool coll;
236*7c478bd9Sstevel@tonic-gate 	CHash_T *chBest = NULL;
237*7c478bd9Sstevel@tonic-gate 	unsigned int ticks;
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	cnt = 0;
240*7c478bd9Sstevel@tonic-gate 	hv = 0xABC3D20F;
241*7c478bd9Sstevel@tonic-gate 	if (ChtGran < 0)
242*7c478bd9Sstevel@tonic-gate 		ChtGran = ConnectionRateWindowSize / CHTSIZE;
243*7c478bd9Sstevel@tonic-gate 	if (ChtGran <= 0)
244*7c478bd9Sstevel@tonic-gate 		ChtGran = 10;
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 	ticks = now / ChtGran;
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 	if (!CHashAryOK)
249*7c478bd9Sstevel@tonic-gate 	{
250*7c478bd9Sstevel@tonic-gate 		memset(CHashAry, 0, sizeof (CHashAry));
251*7c478bd9Sstevel@tonic-gate 		CHashAryOK = true;
252*7c478bd9Sstevel@tonic-gate 	}
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 	{
255*7c478bd9Sstevel@tonic-gate 		char *p;
256*7c478bd9Sstevel@tonic-gate 		int addrlen;
257*7c478bd9Sstevel@tonic-gate #if HASH_ALG != 1
258*7c478bd9Sstevel@tonic-gate 		int c, d;
259*7c478bd9Sstevel@tonic-gate #endif /* HASH_ALG != 1 */
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 		switch (saddr->sa.sa_family)
262*7c478bd9Sstevel@tonic-gate 		{
263*7c478bd9Sstevel@tonic-gate #if NETINET
264*7c478bd9Sstevel@tonic-gate 		  case AF_INET:
265*7c478bd9Sstevel@tonic-gate 			p = (char *)&saddr->sin.sin_addr;
266*7c478bd9Sstevel@tonic-gate 			addrlen = sizeof(struct in_addr);
267*7c478bd9Sstevel@tonic-gate 			break;
268*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
269*7c478bd9Sstevel@tonic-gate #if NETINET6
270*7c478bd9Sstevel@tonic-gate 		  case AF_INET6:
271*7c478bd9Sstevel@tonic-gate 			p = (char *)&saddr->sin6.sin6_addr;
272*7c478bd9Sstevel@tonic-gate 			addrlen = sizeof(struct in6_addr);
273*7c478bd9Sstevel@tonic-gate 			break;
274*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
275*7c478bd9Sstevel@tonic-gate 		  default:
276*7c478bd9Sstevel@tonic-gate 			/* should not happen */
277*7c478bd9Sstevel@tonic-gate 			return -1;
278*7c478bd9Sstevel@tonic-gate 		}
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 		/* compute hash value */
281*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < addrlen; ++i, ++p)
282*7c478bd9Sstevel@tonic-gate #if HASH_ALG == 1
283*7c478bd9Sstevel@tonic-gate 			hv = (hv << 5) ^ (hv >> 23) ^ *p;
284*7c478bd9Sstevel@tonic-gate 		hv = (hv ^ (hv >> 16));
285*7c478bd9Sstevel@tonic-gate #elif HASH_ALG == 2
286*7c478bd9Sstevel@tonic-gate 		{
287*7c478bd9Sstevel@tonic-gate 			d = *p;
288*7c478bd9Sstevel@tonic-gate 			c = d;
289*7c478bd9Sstevel@tonic-gate 			c ^= c<<6;
290*7c478bd9Sstevel@tonic-gate 			hv += (c<<11) ^ (c>>1);
291*7c478bd9Sstevel@tonic-gate 			hv ^= (d<<14) + (d<<7) + (d<<4) + d;
292*7c478bd9Sstevel@tonic-gate 		}
293*7c478bd9Sstevel@tonic-gate #elif HASH_ALG == 3
294*7c478bd9Sstevel@tonic-gate 		{
295*7c478bd9Sstevel@tonic-gate 			hv = (hv << 4) + *p;
296*7c478bd9Sstevel@tonic-gate 			d = hv & 0xf0000000;
297*7c478bd9Sstevel@tonic-gate 			if (d != 0)
298*7c478bd9Sstevel@tonic-gate 			{
299*7c478bd9Sstevel@tonic-gate 				hv ^= (d >> 24);
300*7c478bd9Sstevel@tonic-gate 				hv ^= d;
301*7c478bd9Sstevel@tonic-gate 			}
302*7c478bd9Sstevel@tonic-gate 		}
303*7c478bd9Sstevel@tonic-gate #else /* HASH_ALG == 1 */
304*7c478bd9Sstevel@tonic-gate 			hv = ((hv << 1) ^ (*p & 0377)) % cctx->cc_size;
305*7c478bd9Sstevel@tonic-gate #endif /* HASH_ALG == 1 */
306*7c478bd9Sstevel@tonic-gate 	}
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	coll = true;
309*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CT_STEPS; ++i)
310*7c478bd9Sstevel@tonic-gate 	{
311*7c478bd9Sstevel@tonic-gate 		CHash_T *ch = &CHashAry[(hv + i) & CPMHMASK];
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate #if NETINET
314*7c478bd9Sstevel@tonic-gate 		if (saddr->sa.sa_family == AF_INET &&
315*7c478bd9Sstevel@tonic-gate 		    ch->ch_Family == AF_INET &&
316*7c478bd9Sstevel@tonic-gate 		    (saddr->sin.sin_addr.s_addr == ch->ch_Addr4.s_addr ||
317*7c478bd9Sstevel@tonic-gate 		     ch->ch_Addr4.s_addr == 0))
318*7c478bd9Sstevel@tonic-gate 		{
319*7c478bd9Sstevel@tonic-gate 			chBest = ch;
320*7c478bd9Sstevel@tonic-gate 			coll = false;
321*7c478bd9Sstevel@tonic-gate 			break;
322*7c478bd9Sstevel@tonic-gate 		}
323*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
324*7c478bd9Sstevel@tonic-gate #if NETINET6
325*7c478bd9Sstevel@tonic-gate 		if (saddr->sa.sa_family == AF_INET6 &&
326*7c478bd9Sstevel@tonic-gate 		    ch->ch_Family == AF_INET6 &&
327*7c478bd9Sstevel@tonic-gate 		    (IN6_ARE_ADDR_EQUAL(&saddr->sin6.sin6_addr,
328*7c478bd9Sstevel@tonic-gate 				       &ch->ch_Addr6) != 0 ||
329*7c478bd9Sstevel@tonic-gate 		     IN6_IS_ADDR_UNSPECIFIED(&ch->ch_Addr6)))
330*7c478bd9Sstevel@tonic-gate 		{
331*7c478bd9Sstevel@tonic-gate 			chBest = ch;
332*7c478bd9Sstevel@tonic-gate 			coll = false;
333*7c478bd9Sstevel@tonic-gate 			break;
334*7c478bd9Sstevel@tonic-gate 		}
335*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
336*7c478bd9Sstevel@tonic-gate 		if (chBest == NULL || ch->ch_LTime == 0 ||
337*7c478bd9Sstevel@tonic-gate 		    ch->ch_LTime < chBest->ch_LTime)
338*7c478bd9Sstevel@tonic-gate 			chBest = ch;
339*7c478bd9Sstevel@tonic-gate 	}
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	/* Let's update data... */
342*7c478bd9Sstevel@tonic-gate 	if (update)
343*7c478bd9Sstevel@tonic-gate 	{
344*7c478bd9Sstevel@tonic-gate 		if (coll && (now - chBest->ch_LTime < CollTime))
345*7c478bd9Sstevel@tonic-gate 		{
346*7c478bd9Sstevel@tonic-gate 			/*
347*7c478bd9Sstevel@tonic-gate 			**  increment the number of collisions last
348*7c478bd9Sstevel@tonic-gate 			**  CollTime for this client
349*7c478bd9Sstevel@tonic-gate 			*/
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 			chBest->ch_colls++;
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 			/*
354*7c478bd9Sstevel@tonic-gate 			**  Maybe shall log if collision rate is too high...
355*7c478bd9Sstevel@tonic-gate 			**  and take measures to resize tables
356*7c478bd9Sstevel@tonic-gate 			**  if this is the case
357*7c478bd9Sstevel@tonic-gate 			*/
358*7c478bd9Sstevel@tonic-gate 		}
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 		/*
361*7c478bd9Sstevel@tonic-gate 		**  If it's not a match, then replace the data.
362*7c478bd9Sstevel@tonic-gate 		**  Note: this purges the history of a colliding entry,
363*7c478bd9Sstevel@tonic-gate 		**  which may cause "overruns", i.e., if two entries are
364*7c478bd9Sstevel@tonic-gate 		**  "cancelling" each other out, then they may exceed
365*7c478bd9Sstevel@tonic-gate 		**  the limits that are set. This might be mitigated a bit
366*7c478bd9Sstevel@tonic-gate 		**  by the above "best of 5" function however.
367*7c478bd9Sstevel@tonic-gate 		**
368*7c478bd9Sstevel@tonic-gate 		**  Alternative approach: just use the old data, which may
369*7c478bd9Sstevel@tonic-gate 		**  cause false positives however.
370*7c478bd9Sstevel@tonic-gate 		**  To activate this, change deactivate following memset call.
371*7c478bd9Sstevel@tonic-gate 		*/
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 		if (coll)
374*7c478bd9Sstevel@tonic-gate 		{
375*7c478bd9Sstevel@tonic-gate #if NETINET
376*7c478bd9Sstevel@tonic-gate 			if (saddr->sa.sa_family == AF_INET)
377*7c478bd9Sstevel@tonic-gate 			{
378*7c478bd9Sstevel@tonic-gate 				chBest->ch_Family = AF_INET;
379*7c478bd9Sstevel@tonic-gate 				chBest->ch_Addr4 = saddr->sin.sin_addr;
380*7c478bd9Sstevel@tonic-gate 			}
381*7c478bd9Sstevel@tonic-gate #endif /* NETINET */
382*7c478bd9Sstevel@tonic-gate #if NETINET6
383*7c478bd9Sstevel@tonic-gate 			if (saddr->sa.sa_family == AF_INET6)
384*7c478bd9Sstevel@tonic-gate 			{
385*7c478bd9Sstevel@tonic-gate 				chBest->ch_Family = AF_INET6;
386*7c478bd9Sstevel@tonic-gate 				chBest->ch_Addr6 = saddr->sin6.sin6_addr;
387*7c478bd9Sstevel@tonic-gate 			}
388*7c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
389*7c478bd9Sstevel@tonic-gate #if 1
390*7c478bd9Sstevel@tonic-gate 			memset(chBest->ch_Times, '\0',
391*7c478bd9Sstevel@tonic-gate 			       sizeof (chBest->ch_Times));
392*7c478bd9Sstevel@tonic-gate #endif /* 1 */
393*7c478bd9Sstevel@tonic-gate 		}
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 		chBest->ch_LTime = now;
396*7c478bd9Sstevel@tonic-gate 		{
397*7c478bd9Sstevel@tonic-gate 			CTime_T *ct = &chBest->ch_Times[ticks % CHTSIZE];
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 			if (ct->ct_Ticks != ticks)
400*7c478bd9Sstevel@tonic-gate 			{
401*7c478bd9Sstevel@tonic-gate 				ct->ct_Ticks = ticks;
402*7c478bd9Sstevel@tonic-gate 				ct->ct_Count = 0;
403*7c478bd9Sstevel@tonic-gate 			}
404*7c478bd9Sstevel@tonic-gate 			++ct->ct_Count;
405*7c478bd9Sstevel@tonic-gate 		}
406*7c478bd9Sstevel@tonic-gate 	}
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	/* Now let's count connections on the window */
409*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < CHTSIZE; ++i)
410*7c478bd9Sstevel@tonic-gate 	{
411*7c478bd9Sstevel@tonic-gate 		CTime_T *ct = &chBest->ch_Times[i];
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 		if (ct->ct_Ticks <= ticks && ct->ct_Ticks >= ticks - CHTSIZE)
414*7c478bd9Sstevel@tonic-gate 			cnt += ct->ct_Count;
415*7c478bd9Sstevel@tonic-gate 	}
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate #if RATECTL_DEBUG
418*7c478bd9Sstevel@tonic-gate 	sm_syslog(LOG_WARNING, NOQID,
419*7c478bd9Sstevel@tonic-gate 		"cln: cnt=(%d), CHTSIZE=(%d), ChtGran=(%d)",
420*7c478bd9Sstevel@tonic-gate 		cnt, CHTSIZE, ChtGran);
421*7c478bd9Sstevel@tonic-gate #endif /* RATECTL_DEBUG */
422*7c478bd9Sstevel@tonic-gate 	return cnt;
423*7c478bd9Sstevel@tonic-gate }
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate /*
426*7c478bd9Sstevel@tonic-gate **  TOTAL_RATE - Evaluate global connection rate
427*7c478bd9Sstevel@tonic-gate **
428*7c478bd9Sstevel@tonic-gate **	Parameters:
429*7c478bd9Sstevel@tonic-gate **		now - current time in secs
430*7c478bd9Sstevel@tonic-gate **		update - update data / check only
431*7c478bd9Sstevel@tonic-gate **
432*7c478bd9Sstevel@tonic-gate **	Returns:
433*7c478bd9Sstevel@tonic-gate **		connection rate (connections / ConnectionRateWindowSize)
434*7c478bd9Sstevel@tonic-gate */
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate static CTime_T srv_Times[CHTSIZE];
437*7c478bd9Sstevel@tonic-gate static bool srv_Times_OK = false;
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate static int
440*7c478bd9Sstevel@tonic-gate total_rate(now, update)
441*7c478bd9Sstevel@tonic-gate 	 time_t now;
442*7c478bd9Sstevel@tonic-gate 	 bool update;
443*7c478bd9Sstevel@tonic-gate {
444*7c478bd9Sstevel@tonic-gate 	int i;
445*7c478bd9Sstevel@tonic-gate 	int cnt = 0;
446*7c478bd9Sstevel@tonic-gate 	CTime_T *ct;
447*7c478bd9Sstevel@tonic-gate 	unsigned int ticks;
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	if (ChtGran < 0)
450*7c478bd9Sstevel@tonic-gate 		ChtGran = ConnectionRateWindowSize / CHTSIZE;
451*7c478bd9Sstevel@tonic-gate 	if (ChtGran == 0)
452*7c478bd9Sstevel@tonic-gate 		ChtGran = 10;
453*7c478bd9Sstevel@tonic-gate 	ticks = now / ChtGran;
454*7c478bd9Sstevel@tonic-gate 	if (!srv_Times_OK)
455*7c478bd9Sstevel@tonic-gate 	{
456*7c478bd9Sstevel@tonic-gate 		memset(srv_Times, 0, sizeof(srv_Times));
457*7c478bd9Sstevel@tonic-gate 		srv_Times_OK = true;
458*7c478bd9Sstevel@tonic-gate 	}
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 	/* Let's update data */
461*7c478bd9Sstevel@tonic-gate 	if (update)
462*7c478bd9Sstevel@tonic-gate 	{
463*7c478bd9Sstevel@tonic-gate 		ct = &srv_Times[ticks % CHTSIZE];
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 		if (ct->ct_Ticks != ticks)
466*7c478bd9Sstevel@tonic-gate 		{
467*7c478bd9Sstevel@tonic-gate 			ct->ct_Ticks = ticks;
468*7c478bd9Sstevel@tonic-gate 			ct->ct_Count = 0;
469*7c478bd9Sstevel@tonic-gate 		}
470*7c478bd9Sstevel@tonic-gate 		++ct->ct_Count;
471*7c478bd9Sstevel@tonic-gate 	}
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 	/* Let's count connections on the window */
474*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < CHTSIZE; ++i)
475*7c478bd9Sstevel@tonic-gate 	{
476*7c478bd9Sstevel@tonic-gate 		ct = &srv_Times[i];
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 		if (ct->ct_Ticks <= ticks && ct->ct_Ticks >= ticks - CHTSIZE)
479*7c478bd9Sstevel@tonic-gate 			cnt += ct->ct_Count;
480*7c478bd9Sstevel@tonic-gate 	}
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate #if RATECTL_DEBUG
483*7c478bd9Sstevel@tonic-gate 	sm_syslog(LOG_WARNING, NOQID,
484*7c478bd9Sstevel@tonic-gate 		"srv: cnt=(%d), CHTSIZE=(%d), ChtGran=(%d)",
485*7c478bd9Sstevel@tonic-gate 		 cnt, CHTSIZE, ChtGran);
486*7c478bd9Sstevel@tonic-gate #endif /* RATECTL_DEBUG */
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	return cnt;
489*7c478bd9Sstevel@tonic-gate }
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate #if 0
492*7c478bd9Sstevel@tonic-gate /*
493*7c478bd9Sstevel@tonic-gate ** SOCKADDRCMP - compare two SOCKADDR structures
494*7c478bd9Sstevel@tonic-gate **   this function may be used to compare SOCKADDR
495*7c478bd9Sstevel@tonic-gate **   structures when using bsearch and qsort functions
496*7c478bd9Sstevel@tonic-gate **   in the same way we do with strcmp
497*7c478bd9Sstevel@tonic-gate **
498*7c478bd9Sstevel@tonic-gate ** Parameters:
499*7c478bd9Sstevel@tonic-gate **   a, b - addresses
500*7c478bd9Sstevel@tonic-gate **
501*7c478bd9Sstevel@tonic-gate ** Returns:
502*7c478bd9Sstevel@tonic-gate **   1 if a > b
503*7c478bd9Sstevel@tonic-gate **  -1 if a < b
504*7c478bd9Sstevel@tonic-gate **   0 if a = b
505*7c478bd9Sstevel@tonic-gate **
506*7c478bd9Sstevel@tonic-gate ** OBS: This call isn't used at the moment, it will
507*7c478bd9Sstevel@tonic-gate ** be used when code will be extended to work with IPV6
508*7c478bd9Sstevel@tonic-gate */
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate static int
511*7c478bd9Sstevel@tonic-gate sockaddrcmp(a, b)
512*7c478bd9Sstevel@tonic-gate 	 SOCKADDR *a;
513*7c478bd9Sstevel@tonic-gate 	 SOCKADDR *b;
514*7c478bd9Sstevel@tonic-gate {
515*7c478bd9Sstevel@tonic-gate 	if (a->sa.sa_family > b->sa.sa_family)
516*7c478bd9Sstevel@tonic-gate 		return 1;
517*7c478bd9Sstevel@tonic-gate 	if (a->sa.sa_family < b->sa.sa_family)
518*7c478bd9Sstevel@tonic-gate 		return -1;
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 	switch (a->sa.sa_family)
521*7c478bd9Sstevel@tonic-gate 	{
522*7c478bd9Sstevel@tonic-gate 	  case AF_INET:
523*7c478bd9Sstevel@tonic-gate 		if (a->sin.sin_addr.s_addr > b->sin.sin_addr.s_addr)
524*7c478bd9Sstevel@tonic-gate 			return 1;
525*7c478bd9Sstevel@tonic-gate 		if (a->sin.sin_addr.s_addr < b->sin.sin_addr.s_addr)
526*7c478bd9Sstevel@tonic-gate 			return -1;
527*7c478bd9Sstevel@tonic-gate 		return 0;
528*7c478bd9Sstevel@tonic-gate 		break;
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 	  case AF_INET6:
531*7c478bd9Sstevel@tonic-gate 		/* TO BE DONE */
532*7c478bd9Sstevel@tonic-gate 		break;
533*7c478bd9Sstevel@tonic-gate 	}
534*7c478bd9Sstevel@tonic-gate 	return 0;
535*7c478bd9Sstevel@tonic-gate }
536*7c478bd9Sstevel@tonic-gate #endif /* 0 */
537