xref: /illumos-gate/usr/src/cmd/sendmail/src/ratectrl.c (revision d4660949)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (c) 2003 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate  *	All rights reserved.
47c478bd9Sstevel@tonic-gate  *
57c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
67c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
77c478bd9Sstevel@tonic-gate  * the sendmail distribution.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * Contributed by Jose Marcio Martins da Cruz - Ecole des Mines de Paris
107c478bd9Sstevel@tonic-gate  *   Jose-Marcio.Martins@ensmp.fr
117c478bd9Sstevel@tonic-gate  */
127c478bd9Sstevel@tonic-gate 
137c478bd9Sstevel@tonic-gate /* a part of this code is based on inetd.c for which this copyright applies: */
147c478bd9Sstevel@tonic-gate /*
157c478bd9Sstevel@tonic-gate  * Copyright (c) 1983, 1991, 1993, 1994
167c478bd9Sstevel@tonic-gate  *      The Regents of the University of California.  All rights reserved.
177c478bd9Sstevel@tonic-gate  *
187c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
197c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
207c478bd9Sstevel@tonic-gate  * are met:
217c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
227c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
237c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
247c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
257c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
267c478bd9Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
277c478bd9Sstevel@tonic-gate  *    must display the following acknowledgement:
287c478bd9Sstevel@tonic-gate  *      This product includes software developed by the University of
297c478bd9Sstevel@tonic-gate  *      California, Berkeley and its contributors.
307c478bd9Sstevel@tonic-gate  * 4. Neither the name of the University nor the names of its contributors
317c478bd9Sstevel@tonic-gate  *    may be used to endorse or promote products derived from this software
327c478bd9Sstevel@tonic-gate  *    without specific prior written permission.
337c478bd9Sstevel@tonic-gate  *
347c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
357c478bd9Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
367c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
377c478bd9Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
387c478bd9Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
397c478bd9Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
407c478bd9Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
417c478bd9Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
427c478bd9Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
437c478bd9Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
447c478bd9Sstevel@tonic-gate  * SUCH DAMAGE.
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #include <sendmail.h>
50*d4660949Sjbeck SM_RCSID("@(#)$Id: ratectrl.c,v 8.12 2008/02/11 22:56:05 ca Exp $")
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate **  stuff included - given some warnings (inet_ntoa)
547c478bd9Sstevel@tonic-gate **	- surely not everything is needed
557c478bd9Sstevel@tonic-gate */
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #if NETINET || NETINET6
587c478bd9Sstevel@tonic-gate # include <arpa/inet.h>
597c478bd9Sstevel@tonic-gate #endif	/* NETINET || NETINET6 */
607c478bd9Sstevel@tonic-gate 
6149218d4fSjbeck #include <sm/time.h>
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate #ifndef HASH_ALG
647c478bd9Sstevel@tonic-gate # define HASH_ALG	2
657c478bd9Sstevel@tonic-gate #endif /* HASH_ALG */
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate #ifndef RATECTL_DEBUG
687c478bd9Sstevel@tonic-gate # define RATECTL_DEBUG  0
697c478bd9Sstevel@tonic-gate #endif /* RATECTL_DEBUG */
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate /* forward declarations */
727c478bd9Sstevel@tonic-gate static int client_rate __P((time_t, SOCKADDR *, bool));
737c478bd9Sstevel@tonic-gate static int total_rate __P((time_t, bool));
747c478bd9Sstevel@tonic-gate #if 0
757c478bd9Sstevel@tonic-gate static int sockaddrcmp __P((SOCKADDR *, SOCKADDR *));
767c478bd9Sstevel@tonic-gate #endif /* 0 */
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate **  CONNECTION_RATE_CHECK - updates connection history data
807c478bd9Sstevel@tonic-gate **      and computes connection rate for the given host
817c478bd9Sstevel@tonic-gate **
827c478bd9Sstevel@tonic-gate **    Parameters:
837c478bd9Sstevel@tonic-gate **      hostaddr -- ip address of smtp client
847c478bd9Sstevel@tonic-gate **      e -- envelope
857c478bd9Sstevel@tonic-gate **
867c478bd9Sstevel@tonic-gate **    Returns:
877c478bd9Sstevel@tonic-gate **      true (always)
887c478bd9Sstevel@tonic-gate **
897c478bd9Sstevel@tonic-gate **    Side Effects:
907c478bd9Sstevel@tonic-gate **      updates connection history
917c478bd9Sstevel@tonic-gate **
927c478bd9Sstevel@tonic-gate **    Warnings:
937c478bd9Sstevel@tonic-gate **      For each connection, this call shall be
947c478bd9Sstevel@tonic-gate **      done only once with the value true for the
957c478bd9Sstevel@tonic-gate **      update parameter.
967c478bd9Sstevel@tonic-gate **      Typically, this call is done with the value
977c478bd9Sstevel@tonic-gate **      true by the father, and once again with
987c478bd9Sstevel@tonic-gate **      the value false by the children.
997c478bd9Sstevel@tonic-gate **
1007c478bd9Sstevel@tonic-gate */
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate bool
1037c478bd9Sstevel@tonic-gate connection_rate_check(hostaddr, e)
1047c478bd9Sstevel@tonic-gate 	SOCKADDR *hostaddr;
1057c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate 	time_t now;
1087c478bd9Sstevel@tonic-gate 	int totalrate, clientrate;
1097c478bd9Sstevel@tonic-gate 	static int clientconn = 0;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	now = time(NULL);
1127c478bd9Sstevel@tonic-gate #if RATECTL_DEBUG
1137c478bd9Sstevel@tonic-gate 	sm_syslog(LOG_INFO, NOQID, "connection_rate_check entering...");
1147c478bd9Sstevel@tonic-gate #endif /* RATECTL_DEBUG */
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	/* update server connection rate */
1177c478bd9Sstevel@tonic-gate 	totalrate = total_rate(now, e == NULL);
1187c478bd9Sstevel@tonic-gate #if RATECTL_DEBUG
119*d4660949Sjbeck 	sm_syslog(LOG_INFO, NOQID, "global connection rate: %d", totalrate);
1207c478bd9Sstevel@tonic-gate #endif /* RATECTL_DEBUG */
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	/* update client connection rate */
1237c478bd9Sstevel@tonic-gate 	clientrate = client_rate(now, hostaddr, e == NULL);
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	if (e == NULL)
1267c478bd9Sstevel@tonic-gate 		clientconn = count_open_connections(hostaddr);
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	if (e != NULL)
1297c478bd9Sstevel@tonic-gate 	{
1307c478bd9Sstevel@tonic-gate 		char s[16];
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 		sm_snprintf(s, sizeof(s), "%d", clientrate);
1337c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_TEMP, macid("{client_rate}"), s);
1347c478bd9Sstevel@tonic-gate 		sm_snprintf(s, sizeof(s), "%d", totalrate);
1357c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_TEMP, macid("{total_rate}"), s);
1367c478bd9Sstevel@tonic-gate 		sm_snprintf(s, sizeof(s), "%d", clientconn);
1377c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_TEMP, macid("{client_connections}"),
1387c478bd9Sstevel@tonic-gate 				s);
1397c478bd9Sstevel@tonic-gate 	}
1407c478bd9Sstevel@tonic-gate 	return true;
1417c478bd9Sstevel@tonic-gate }
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate /*
1447c478bd9Sstevel@tonic-gate **  Data declarations needed to evaluate connection rate
1457c478bd9Sstevel@tonic-gate */
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate static int CollTime = 60;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /* this should be a power of 2, otherwise CPMHMASK doesn't work well */
1507c478bd9Sstevel@tonic-gate #ifndef CPMHSIZE
1517c478bd9Sstevel@tonic-gate # define CPMHSIZE	1024
1527c478bd9Sstevel@tonic-gate #endif /* CPMHSIZE */
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate #define CPMHMASK	(CPMHSIZE-1)
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate #ifndef MAX_CT_STEPS
1577c478bd9Sstevel@tonic-gate # define MAX_CT_STEPS	10
1587c478bd9Sstevel@tonic-gate #endif /* MAX_CT_STEPS */
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate /*
1617c478bd9Sstevel@tonic-gate **  time granularity: 10s (that's one "tick")
1627c478bd9Sstevel@tonic-gate **  will be initialised to ConnectionRateWindowSize/CHTSIZE
1637c478bd9Sstevel@tonic-gate **  before being used the first time
1647c478bd9Sstevel@tonic-gate */
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate static int ChtGran = -1;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate #define CHTSIZE		6
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate /* Number of connections for a certain "tick" */
1717c478bd9Sstevel@tonic-gate typedef struct CTime
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	unsigned long	ct_Ticks;
1747c478bd9Sstevel@tonic-gate 	int		ct_Count;
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate CTime_T;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate typedef struct CHash
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate #if NETINET6 && NETINET
1817c478bd9Sstevel@tonic-gate 	union
1827c478bd9Sstevel@tonic-gate 	{
1837c478bd9Sstevel@tonic-gate 		struct in_addr	c4_Addr;
1847c478bd9Sstevel@tonic-gate 		struct in6_addr	c6_Addr;
1857c478bd9Sstevel@tonic-gate 	} cu_Addr;
1867c478bd9Sstevel@tonic-gate # define ch_Addr4	cu_Addr.c4_Addr
1877c478bd9Sstevel@tonic-gate # define ch_Addr6	cu_Addr.c6_Addr
1887c478bd9Sstevel@tonic-gate #else /* NETINET6 && NETINET */
1897c478bd9Sstevel@tonic-gate # if NETINET6
1907c478bd9Sstevel@tonic-gate 	struct in6_addr	ch_Addr;
1917c478bd9Sstevel@tonic-gate #  define ch_Addr6	ch_Addr
1927c478bd9Sstevel@tonic-gate # else /* NETINET6 */
1937c478bd9Sstevel@tonic-gate 	struct in_addr ch_Addr;
1947c478bd9Sstevel@tonic-gate #  define ch_Addr4	ch_Addr
1957c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
1967c478bd9Sstevel@tonic-gate #endif /* NETINET6 && NETINET */
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	int		ch_Family;
1997c478bd9Sstevel@tonic-gate 	time_t		ch_LTime;
2007c478bd9Sstevel@tonic-gate 	unsigned long	ch_colls;
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	/* 6 buckets for ticks: 60s */
2037c478bd9Sstevel@tonic-gate 	CTime_T		ch_Times[CHTSIZE];
2047c478bd9Sstevel@tonic-gate }
2057c478bd9Sstevel@tonic-gate CHash_T;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate static CHash_T CHashAry[CPMHSIZE];
2087c478bd9Sstevel@tonic-gate static bool CHashAryOK = false;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate /*
2117c478bd9Sstevel@tonic-gate **  CLIENT_RATE - Evaluate connection rate per smtp client
2127c478bd9Sstevel@tonic-gate **
2137c478bd9Sstevel@tonic-gate **	Parameters:
2147c478bd9Sstevel@tonic-gate **		now - current time in secs
2157c478bd9Sstevel@tonic-gate **		saddr - client address
2167c478bd9Sstevel@tonic-gate **		update - update data / check only
2177c478bd9Sstevel@tonic-gate **
2187c478bd9Sstevel@tonic-gate **	Returns:
2197c478bd9Sstevel@tonic-gate **		connection rate (connections / ConnectionRateWindowSize)
2207c478bd9Sstevel@tonic-gate **
2217c478bd9Sstevel@tonic-gate **	Side effects:
2227c478bd9Sstevel@tonic-gate **		update static global data
2237c478bd9Sstevel@tonic-gate **
2247c478bd9Sstevel@tonic-gate */
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate static int
2277c478bd9Sstevel@tonic-gate client_rate(now, saddr, update)
2287c478bd9Sstevel@tonic-gate 	 time_t now;
2297c478bd9Sstevel@tonic-gate 	 SOCKADDR *saddr;
2307c478bd9Sstevel@tonic-gate 	 bool update;
2317c478bd9Sstevel@tonic-gate {
2327c478bd9Sstevel@tonic-gate 	unsigned int hv;
2337c478bd9Sstevel@tonic-gate 	int i;
2347c478bd9Sstevel@tonic-gate 	int cnt;
2357c478bd9Sstevel@tonic-gate 	bool coll;
2367c478bd9Sstevel@tonic-gate 	CHash_T *chBest = NULL;
2377c478bd9Sstevel@tonic-gate 	unsigned int ticks;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	cnt = 0;
2407c478bd9Sstevel@tonic-gate 	hv = 0xABC3D20F;
2417c478bd9Sstevel@tonic-gate 	if (ChtGran < 0)
2427c478bd9Sstevel@tonic-gate 		ChtGran = ConnectionRateWindowSize / CHTSIZE;
2437c478bd9Sstevel@tonic-gate 	if (ChtGran <= 0)
2447c478bd9Sstevel@tonic-gate 		ChtGran = 10;
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	ticks = now / ChtGran;
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	if (!CHashAryOK)
2497c478bd9Sstevel@tonic-gate 	{
250058561cbSjbeck 		memset(CHashAry, 0, sizeof(CHashAry));
2517c478bd9Sstevel@tonic-gate 		CHashAryOK = true;
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	{
2557c478bd9Sstevel@tonic-gate 		char *p;
2567c478bd9Sstevel@tonic-gate 		int addrlen;
2577c478bd9Sstevel@tonic-gate #if HASH_ALG != 1
2587c478bd9Sstevel@tonic-gate 		int c, d;
2597c478bd9Sstevel@tonic-gate #endif /* HASH_ALG != 1 */
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 		switch (saddr->sa.sa_family)
2627c478bd9Sstevel@tonic-gate 		{
2637c478bd9Sstevel@tonic-gate #if NETINET
2647c478bd9Sstevel@tonic-gate 		  case AF_INET:
2657c478bd9Sstevel@tonic-gate 			p = (char *)&saddr->sin.sin_addr;
2667c478bd9Sstevel@tonic-gate 			addrlen = sizeof(struct in_addr);
2677c478bd9Sstevel@tonic-gate 			break;
2687c478bd9Sstevel@tonic-gate #endif /* NETINET */
2697c478bd9Sstevel@tonic-gate #if NETINET6
2707c478bd9Sstevel@tonic-gate 		  case AF_INET6:
2717c478bd9Sstevel@tonic-gate 			p = (char *)&saddr->sin6.sin6_addr;
2727c478bd9Sstevel@tonic-gate 			addrlen = sizeof(struct in6_addr);
2737c478bd9Sstevel@tonic-gate 			break;
2747c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2757c478bd9Sstevel@tonic-gate 		  default:
2767c478bd9Sstevel@tonic-gate 			/* should not happen */
2777c478bd9Sstevel@tonic-gate 			return -1;
2787c478bd9Sstevel@tonic-gate 		}
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 		/* compute hash value */
2817c478bd9Sstevel@tonic-gate 		for (i = 0; i < addrlen; ++i, ++p)
2827c478bd9Sstevel@tonic-gate #if HASH_ALG == 1
2837c478bd9Sstevel@tonic-gate 			hv = (hv << 5) ^ (hv >> 23) ^ *p;
2847c478bd9Sstevel@tonic-gate 		hv = (hv ^ (hv >> 16));
2857c478bd9Sstevel@tonic-gate #elif HASH_ALG == 2
2867c478bd9Sstevel@tonic-gate 		{
2877c478bd9Sstevel@tonic-gate 			d = *p;
2887c478bd9Sstevel@tonic-gate 			c = d;
2897c478bd9Sstevel@tonic-gate 			c ^= c<<6;
2907c478bd9Sstevel@tonic-gate 			hv += (c<<11) ^ (c>>1);
2917c478bd9Sstevel@tonic-gate 			hv ^= (d<<14) + (d<<7) + (d<<4) + d;
2927c478bd9Sstevel@tonic-gate 		}
2937c478bd9Sstevel@tonic-gate #elif HASH_ALG == 3
2947c478bd9Sstevel@tonic-gate 		{
2957c478bd9Sstevel@tonic-gate 			hv = (hv << 4) + *p;
2967c478bd9Sstevel@tonic-gate 			d = hv & 0xf0000000;
2977c478bd9Sstevel@tonic-gate 			if (d != 0)
2987c478bd9Sstevel@tonic-gate 			{
2997c478bd9Sstevel@tonic-gate 				hv ^= (d >> 24);
3007c478bd9Sstevel@tonic-gate 				hv ^= d;
3017c478bd9Sstevel@tonic-gate 			}
3027c478bd9Sstevel@tonic-gate 		}
3037c478bd9Sstevel@tonic-gate #else /* HASH_ALG == 1 */
3047c478bd9Sstevel@tonic-gate 			hv = ((hv << 1) ^ (*p & 0377)) % cctx->cc_size;
3057c478bd9Sstevel@tonic-gate #endif /* HASH_ALG == 1 */
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	coll = true;
3097c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CT_STEPS; ++i)
3107c478bd9Sstevel@tonic-gate 	{
3117c478bd9Sstevel@tonic-gate 		CHash_T *ch = &CHashAry[(hv + i) & CPMHMASK];
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate #if NETINET
3147c478bd9Sstevel@tonic-gate 		if (saddr->sa.sa_family == AF_INET &&
3157c478bd9Sstevel@tonic-gate 		    ch->ch_Family == AF_INET &&
3167c478bd9Sstevel@tonic-gate 		    (saddr->sin.sin_addr.s_addr == ch->ch_Addr4.s_addr ||
3177c478bd9Sstevel@tonic-gate 		     ch->ch_Addr4.s_addr == 0))
3187c478bd9Sstevel@tonic-gate 		{
3197c478bd9Sstevel@tonic-gate 			chBest = ch;
3207c478bd9Sstevel@tonic-gate 			coll = false;
3217c478bd9Sstevel@tonic-gate 			break;
3227c478bd9Sstevel@tonic-gate 		}
3237c478bd9Sstevel@tonic-gate #endif /* NETINET */
3247c478bd9Sstevel@tonic-gate #if NETINET6
3257c478bd9Sstevel@tonic-gate 		if (saddr->sa.sa_family == AF_INET6 &&
3267c478bd9Sstevel@tonic-gate 		    ch->ch_Family == AF_INET6 &&
3277c478bd9Sstevel@tonic-gate 		    (IN6_ARE_ADDR_EQUAL(&saddr->sin6.sin6_addr,
3287c478bd9Sstevel@tonic-gate 				       &ch->ch_Addr6) != 0 ||
3297c478bd9Sstevel@tonic-gate 		     IN6_IS_ADDR_UNSPECIFIED(&ch->ch_Addr6)))
3307c478bd9Sstevel@tonic-gate 		{
3317c478bd9Sstevel@tonic-gate 			chBest = ch;
3327c478bd9Sstevel@tonic-gate 			coll = false;
3337c478bd9Sstevel@tonic-gate 			break;
3347c478bd9Sstevel@tonic-gate 		}
3357c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
3367c478bd9Sstevel@tonic-gate 		if (chBest == NULL || ch->ch_LTime == 0 ||
3377c478bd9Sstevel@tonic-gate 		    ch->ch_LTime < chBest->ch_LTime)
3387c478bd9Sstevel@tonic-gate 			chBest = ch;
3397c478bd9Sstevel@tonic-gate 	}
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	/* Let's update data... */
3427c478bd9Sstevel@tonic-gate 	if (update)
3437c478bd9Sstevel@tonic-gate 	{
3447c478bd9Sstevel@tonic-gate 		if (coll && (now - chBest->ch_LTime < CollTime))
3457c478bd9Sstevel@tonic-gate 		{
3467c478bd9Sstevel@tonic-gate 			/*
3477c478bd9Sstevel@tonic-gate 			**  increment the number of collisions last
3487c478bd9Sstevel@tonic-gate 			**  CollTime for this client
3497c478bd9Sstevel@tonic-gate 			*/
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 			chBest->ch_colls++;
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 			/*
3547c478bd9Sstevel@tonic-gate 			**  Maybe shall log if collision rate is too high...
3557c478bd9Sstevel@tonic-gate 			**  and take measures to resize tables
3567c478bd9Sstevel@tonic-gate 			**  if this is the case
3577c478bd9Sstevel@tonic-gate 			*/
3587c478bd9Sstevel@tonic-gate 		}
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 		/*
3617c478bd9Sstevel@tonic-gate 		**  If it's not a match, then replace the data.
3627c478bd9Sstevel@tonic-gate 		**  Note: this purges the history of a colliding entry,
3637c478bd9Sstevel@tonic-gate 		**  which may cause "overruns", i.e., if two entries are
3647c478bd9Sstevel@tonic-gate 		**  "cancelling" each other out, then they may exceed
3657c478bd9Sstevel@tonic-gate 		**  the limits that are set. This might be mitigated a bit
3667c478bd9Sstevel@tonic-gate 		**  by the above "best of 5" function however.
3677c478bd9Sstevel@tonic-gate 		**
3687c478bd9Sstevel@tonic-gate 		**  Alternative approach: just use the old data, which may
3697c478bd9Sstevel@tonic-gate 		**  cause false positives however.
3707c478bd9Sstevel@tonic-gate 		**  To activate this, change deactivate following memset call.
3717c478bd9Sstevel@tonic-gate 		*/
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 		if (coll)
3747c478bd9Sstevel@tonic-gate 		{
3757c478bd9Sstevel@tonic-gate #if NETINET
3767c478bd9Sstevel@tonic-gate 			if (saddr->sa.sa_family == AF_INET)
3777c478bd9Sstevel@tonic-gate 			{
3787c478bd9Sstevel@tonic-gate 				chBest->ch_Family = AF_INET;
3797c478bd9Sstevel@tonic-gate 				chBest->ch_Addr4 = saddr->sin.sin_addr;
3807c478bd9Sstevel@tonic-gate 			}
3817c478bd9Sstevel@tonic-gate #endif /* NETINET */
3827c478bd9Sstevel@tonic-gate #if NETINET6
3837c478bd9Sstevel@tonic-gate 			if (saddr->sa.sa_family == AF_INET6)
3847c478bd9Sstevel@tonic-gate 			{
3857c478bd9Sstevel@tonic-gate 				chBest->ch_Family = AF_INET6;
3867c478bd9Sstevel@tonic-gate 				chBest->ch_Addr6 = saddr->sin6.sin6_addr;
3877c478bd9Sstevel@tonic-gate 			}
3887c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
3897c478bd9Sstevel@tonic-gate #if 1
3907c478bd9Sstevel@tonic-gate 			memset(chBest->ch_Times, '\0',
391058561cbSjbeck 			       sizeof(chBest->ch_Times));
3927c478bd9Sstevel@tonic-gate #endif /* 1 */
3937c478bd9Sstevel@tonic-gate 		}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 		chBest->ch_LTime = now;
3967c478bd9Sstevel@tonic-gate 		{
3977c478bd9Sstevel@tonic-gate 			CTime_T *ct = &chBest->ch_Times[ticks % CHTSIZE];
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 			if (ct->ct_Ticks != ticks)
4007c478bd9Sstevel@tonic-gate 			{
4017c478bd9Sstevel@tonic-gate 				ct->ct_Ticks = ticks;
4027c478bd9Sstevel@tonic-gate 				ct->ct_Count = 0;
4037c478bd9Sstevel@tonic-gate 			}
4047c478bd9Sstevel@tonic-gate 			++ct->ct_Count;
4057c478bd9Sstevel@tonic-gate 		}
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	/* Now let's count connections on the window */
4097c478bd9Sstevel@tonic-gate 	for (i = 0; i < CHTSIZE; ++i)
4107c478bd9Sstevel@tonic-gate 	{
4117c478bd9Sstevel@tonic-gate 		CTime_T *ct = &chBest->ch_Times[i];
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 		if (ct->ct_Ticks <= ticks && ct->ct_Ticks >= ticks - CHTSIZE)
4147c478bd9Sstevel@tonic-gate 			cnt += ct->ct_Count;
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate #if RATECTL_DEBUG
4187c478bd9Sstevel@tonic-gate 	sm_syslog(LOG_WARNING, NOQID,
4197c478bd9Sstevel@tonic-gate 		"cln: cnt=(%d), CHTSIZE=(%d), ChtGran=(%d)",
4207c478bd9Sstevel@tonic-gate 		cnt, CHTSIZE, ChtGran);
4217c478bd9Sstevel@tonic-gate #endif /* RATECTL_DEBUG */
4227c478bd9Sstevel@tonic-gate 	return cnt;
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate /*
4267c478bd9Sstevel@tonic-gate **  TOTAL_RATE - Evaluate global connection rate
4277c478bd9Sstevel@tonic-gate **
4287c478bd9Sstevel@tonic-gate **	Parameters:
4297c478bd9Sstevel@tonic-gate **		now - current time in secs
4307c478bd9Sstevel@tonic-gate **		update - update data / check only
4317c478bd9Sstevel@tonic-gate **
4327c478bd9Sstevel@tonic-gate **	Returns:
4337c478bd9Sstevel@tonic-gate **		connection rate (connections / ConnectionRateWindowSize)
4347c478bd9Sstevel@tonic-gate */
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate static CTime_T srv_Times[CHTSIZE];
4377c478bd9Sstevel@tonic-gate static bool srv_Times_OK = false;
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate static int
4407c478bd9Sstevel@tonic-gate total_rate(now, update)
4417c478bd9Sstevel@tonic-gate 	 time_t now;
4427c478bd9Sstevel@tonic-gate 	 bool update;
4437c478bd9Sstevel@tonic-gate {
4447c478bd9Sstevel@tonic-gate 	int i;
4457c478bd9Sstevel@tonic-gate 	int cnt = 0;
4467c478bd9Sstevel@tonic-gate 	CTime_T *ct;
4477c478bd9Sstevel@tonic-gate 	unsigned int ticks;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	if (ChtGran < 0)
4507c478bd9Sstevel@tonic-gate 		ChtGran = ConnectionRateWindowSize / CHTSIZE;
4517c478bd9Sstevel@tonic-gate 	if (ChtGran == 0)
4527c478bd9Sstevel@tonic-gate 		ChtGran = 10;
4537c478bd9Sstevel@tonic-gate 	ticks = now / ChtGran;
4547c478bd9Sstevel@tonic-gate 	if (!srv_Times_OK)
4557c478bd9Sstevel@tonic-gate 	{
4567c478bd9Sstevel@tonic-gate 		memset(srv_Times, 0, sizeof(srv_Times));
4577c478bd9Sstevel@tonic-gate 		srv_Times_OK = true;
4587c478bd9Sstevel@tonic-gate 	}
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	/* Let's update data */
4617c478bd9Sstevel@tonic-gate 	if (update)
4627c478bd9Sstevel@tonic-gate 	{
4637c478bd9Sstevel@tonic-gate 		ct = &srv_Times[ticks % CHTSIZE];
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 		if (ct->ct_Ticks != ticks)
4667c478bd9Sstevel@tonic-gate 		{
4677c478bd9Sstevel@tonic-gate 			ct->ct_Ticks = ticks;
4687c478bd9Sstevel@tonic-gate 			ct->ct_Count = 0;
4697c478bd9Sstevel@tonic-gate 		}
4707c478bd9Sstevel@tonic-gate 		++ct->ct_Count;
4717c478bd9Sstevel@tonic-gate 	}
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	/* Let's count connections on the window */
4747c478bd9Sstevel@tonic-gate 	for (i = 0; i < CHTSIZE; ++i)
4757c478bd9Sstevel@tonic-gate 	{
4767c478bd9Sstevel@tonic-gate 		ct = &srv_Times[i];
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 		if (ct->ct_Ticks <= ticks && ct->ct_Ticks >= ticks - CHTSIZE)
4797c478bd9Sstevel@tonic-gate 			cnt += ct->ct_Count;
4807c478bd9Sstevel@tonic-gate 	}
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate #if RATECTL_DEBUG
4837c478bd9Sstevel@tonic-gate 	sm_syslog(LOG_WARNING, NOQID,
4847c478bd9Sstevel@tonic-gate 		"srv: cnt=(%d), CHTSIZE=(%d), ChtGran=(%d)",
4857c478bd9Sstevel@tonic-gate 		 cnt, CHTSIZE, ChtGran);
4867c478bd9Sstevel@tonic-gate #endif /* RATECTL_DEBUG */
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	return cnt;
4897c478bd9Sstevel@tonic-gate }
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate #if 0
4927c478bd9Sstevel@tonic-gate /*
4937c478bd9Sstevel@tonic-gate ** SOCKADDRCMP - compare two SOCKADDR structures
4947c478bd9Sstevel@tonic-gate **   this function may be used to compare SOCKADDR
4957c478bd9Sstevel@tonic-gate **   structures when using bsearch and qsort functions
4967c478bd9Sstevel@tonic-gate **   in the same way we do with strcmp
4977c478bd9Sstevel@tonic-gate **
4987c478bd9Sstevel@tonic-gate ** Parameters:
4997c478bd9Sstevel@tonic-gate **   a, b - addresses
5007c478bd9Sstevel@tonic-gate **
5017c478bd9Sstevel@tonic-gate ** Returns:
5027c478bd9Sstevel@tonic-gate **   1 if a > b
5037c478bd9Sstevel@tonic-gate **  -1 if a < b
5047c478bd9Sstevel@tonic-gate **   0 if a = b
5057c478bd9Sstevel@tonic-gate **
5067c478bd9Sstevel@tonic-gate ** OBS: This call isn't used at the moment, it will
5077c478bd9Sstevel@tonic-gate ** be used when code will be extended to work with IPV6
5087c478bd9Sstevel@tonic-gate */
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate static int
5117c478bd9Sstevel@tonic-gate sockaddrcmp(a, b)
5127c478bd9Sstevel@tonic-gate 	 SOCKADDR *a;
5137c478bd9Sstevel@tonic-gate 	 SOCKADDR *b;
5147c478bd9Sstevel@tonic-gate {
5157c478bd9Sstevel@tonic-gate 	if (a->sa.sa_family > b->sa.sa_family)
5167c478bd9Sstevel@tonic-gate 		return 1;
5177c478bd9Sstevel@tonic-gate 	if (a->sa.sa_family < b->sa.sa_family)
5187c478bd9Sstevel@tonic-gate 		return -1;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	switch (a->sa.sa_family)
5217c478bd9Sstevel@tonic-gate 	{
5227c478bd9Sstevel@tonic-gate 	  case AF_INET:
5237c478bd9Sstevel@tonic-gate 		if (a->sin.sin_addr.s_addr > b->sin.sin_addr.s_addr)
5247c478bd9Sstevel@tonic-gate 			return 1;
5257c478bd9Sstevel@tonic-gate 		if (a->sin.sin_addr.s_addr < b->sin.sin_addr.s_addr)
5267c478bd9Sstevel@tonic-gate 			return -1;
5277c478bd9Sstevel@tonic-gate 		return 0;
5287c478bd9Sstevel@tonic-gate 		break;
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	  case AF_INET6:
5317c478bd9Sstevel@tonic-gate 		/* TO BE DONE */
5327c478bd9Sstevel@tonic-gate 		break;
5337c478bd9Sstevel@tonic-gate 	}
5347c478bd9Sstevel@tonic-gate 	return 0;
5357c478bd9Sstevel@tonic-gate }
5367c478bd9Sstevel@tonic-gate #endif /* 0 */
537