xref: /titanic_44/usr/src/cmd/sendmail/src/ratectrl.c (revision e9af4bc0b1cc30cea75d6ad4aa2fde97d985e9be)
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 #include <sendmail.h>
48*e9af4bc0SJohn Beck SM_RCSID("@(#)$Id: ratectrl.c,v 8.13 2009/05/05 23:19:34 ca Exp $")
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate **  stuff included - given some warnings (inet_ntoa)
527c478bd9Sstevel@tonic-gate **	- surely not everything is needed
537c478bd9Sstevel@tonic-gate */
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #if NETINET || NETINET6
567c478bd9Sstevel@tonic-gate # include <arpa/inet.h>
577c478bd9Sstevel@tonic-gate #endif	/* NETINET || NETINET6 */
587c478bd9Sstevel@tonic-gate 
5949218d4fSjbeck #include <sm/time.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #ifndef HASH_ALG
627c478bd9Sstevel@tonic-gate # define HASH_ALG	2
637c478bd9Sstevel@tonic-gate #endif /* HASH_ALG */
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate #ifndef RATECTL_DEBUG
667c478bd9Sstevel@tonic-gate # define RATECTL_DEBUG  0
677c478bd9Sstevel@tonic-gate #endif /* RATECTL_DEBUG */
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /* forward declarations */
707c478bd9Sstevel@tonic-gate static int client_rate __P((time_t, SOCKADDR *, bool));
717c478bd9Sstevel@tonic-gate static int total_rate __P((time_t, bool));
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate **  CONNECTION_RATE_CHECK - updates connection history data
757c478bd9Sstevel@tonic-gate **      and computes connection rate for the given host
767c478bd9Sstevel@tonic-gate **
777c478bd9Sstevel@tonic-gate **    Parameters:
787c478bd9Sstevel@tonic-gate **      hostaddr -- ip address of smtp client
797c478bd9Sstevel@tonic-gate **      e -- envelope
807c478bd9Sstevel@tonic-gate **
817c478bd9Sstevel@tonic-gate **    Returns:
827c478bd9Sstevel@tonic-gate **      true (always)
837c478bd9Sstevel@tonic-gate **
847c478bd9Sstevel@tonic-gate **    Side Effects:
857c478bd9Sstevel@tonic-gate **      updates connection history
867c478bd9Sstevel@tonic-gate **
877c478bd9Sstevel@tonic-gate **    Warnings:
887c478bd9Sstevel@tonic-gate **      For each connection, this call shall be
897c478bd9Sstevel@tonic-gate **      done only once with the value true for the
907c478bd9Sstevel@tonic-gate **      update parameter.
917c478bd9Sstevel@tonic-gate **      Typically, this call is done with the value
927c478bd9Sstevel@tonic-gate **      true by the father, and once again with
937c478bd9Sstevel@tonic-gate **      the value false by the children.
947c478bd9Sstevel@tonic-gate **
957c478bd9Sstevel@tonic-gate */
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate bool
connection_rate_check(hostaddr,e)987c478bd9Sstevel@tonic-gate connection_rate_check(hostaddr, e)
997c478bd9Sstevel@tonic-gate 	SOCKADDR *hostaddr;
1007c478bd9Sstevel@tonic-gate 	ENVELOPE *e;
1017c478bd9Sstevel@tonic-gate {
1027c478bd9Sstevel@tonic-gate 	time_t now;
1037c478bd9Sstevel@tonic-gate 	int totalrate, clientrate;
1047c478bd9Sstevel@tonic-gate 	static int clientconn = 0;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	now = time(NULL);
1077c478bd9Sstevel@tonic-gate #if RATECTL_DEBUG
1087c478bd9Sstevel@tonic-gate 	sm_syslog(LOG_INFO, NOQID, "connection_rate_check entering...");
1097c478bd9Sstevel@tonic-gate #endif /* RATECTL_DEBUG */
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	/* update server connection rate */
1127c478bd9Sstevel@tonic-gate 	totalrate = total_rate(now, e == NULL);
1137c478bd9Sstevel@tonic-gate #if RATECTL_DEBUG
114d4660949Sjbeck 	sm_syslog(LOG_INFO, NOQID, "global connection rate: %d", totalrate);
1157c478bd9Sstevel@tonic-gate #endif /* RATECTL_DEBUG */
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	/* update client connection rate */
1187c478bd9Sstevel@tonic-gate 	clientrate = client_rate(now, hostaddr, e == NULL);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	if (e == NULL)
1217c478bd9Sstevel@tonic-gate 		clientconn = count_open_connections(hostaddr);
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	if (e != NULL)
1247c478bd9Sstevel@tonic-gate 	{
1257c478bd9Sstevel@tonic-gate 		char s[16];
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 		sm_snprintf(s, sizeof(s), "%d", clientrate);
1287c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_TEMP, macid("{client_rate}"), s);
1297c478bd9Sstevel@tonic-gate 		sm_snprintf(s, sizeof(s), "%d", totalrate);
1307c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_TEMP, macid("{total_rate}"), s);
1317c478bd9Sstevel@tonic-gate 		sm_snprintf(s, sizeof(s), "%d", clientconn);
1327c478bd9Sstevel@tonic-gate 		macdefine(&e->e_macro, A_TEMP, macid("{client_connections}"),
1337c478bd9Sstevel@tonic-gate 				s);
1347c478bd9Sstevel@tonic-gate 	}
1357c478bd9Sstevel@tonic-gate 	return true;
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate /*
1397c478bd9Sstevel@tonic-gate **  Data declarations needed to evaluate connection rate
1407c478bd9Sstevel@tonic-gate */
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate static int CollTime = 60;
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate /* this should be a power of 2, otherwise CPMHMASK doesn't work well */
1457c478bd9Sstevel@tonic-gate #ifndef CPMHSIZE
1467c478bd9Sstevel@tonic-gate # define CPMHSIZE	1024
1477c478bd9Sstevel@tonic-gate #endif /* CPMHSIZE */
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate #define CPMHMASK	(CPMHSIZE-1)
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate #ifndef MAX_CT_STEPS
1527c478bd9Sstevel@tonic-gate # define MAX_CT_STEPS	10
1537c478bd9Sstevel@tonic-gate #endif /* MAX_CT_STEPS */
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate /*
1567c478bd9Sstevel@tonic-gate **  time granularity: 10s (that's one "tick")
1577c478bd9Sstevel@tonic-gate **  will be initialised to ConnectionRateWindowSize/CHTSIZE
1587c478bd9Sstevel@tonic-gate **  before being used the first time
1597c478bd9Sstevel@tonic-gate */
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate static int ChtGran = -1;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate #define CHTSIZE		6
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate /* Number of connections for a certain "tick" */
1667c478bd9Sstevel@tonic-gate typedef struct CTime
1677c478bd9Sstevel@tonic-gate {
1687c478bd9Sstevel@tonic-gate 	unsigned long	ct_Ticks;
1697c478bd9Sstevel@tonic-gate 	int		ct_Count;
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate CTime_T;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate typedef struct CHash
1747c478bd9Sstevel@tonic-gate {
1757c478bd9Sstevel@tonic-gate #if NETINET6 && NETINET
1767c478bd9Sstevel@tonic-gate 	union
1777c478bd9Sstevel@tonic-gate 	{
1787c478bd9Sstevel@tonic-gate 		struct in_addr	c4_Addr;
1797c478bd9Sstevel@tonic-gate 		struct in6_addr	c6_Addr;
1807c478bd9Sstevel@tonic-gate 	} cu_Addr;
1817c478bd9Sstevel@tonic-gate # define ch_Addr4	cu_Addr.c4_Addr
1827c478bd9Sstevel@tonic-gate # define ch_Addr6	cu_Addr.c6_Addr
1837c478bd9Sstevel@tonic-gate #else /* NETINET6 && NETINET */
1847c478bd9Sstevel@tonic-gate # if NETINET6
1857c478bd9Sstevel@tonic-gate 	struct in6_addr	ch_Addr;
1867c478bd9Sstevel@tonic-gate #  define ch_Addr6	ch_Addr
1877c478bd9Sstevel@tonic-gate # else /* NETINET6 */
1887c478bd9Sstevel@tonic-gate 	struct in_addr ch_Addr;
1897c478bd9Sstevel@tonic-gate #  define ch_Addr4	ch_Addr
1907c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
1917c478bd9Sstevel@tonic-gate #endif /* NETINET6 && NETINET */
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	int		ch_Family;
1947c478bd9Sstevel@tonic-gate 	time_t		ch_LTime;
1957c478bd9Sstevel@tonic-gate 	unsigned long	ch_colls;
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	/* 6 buckets for ticks: 60s */
1987c478bd9Sstevel@tonic-gate 	CTime_T		ch_Times[CHTSIZE];
1997c478bd9Sstevel@tonic-gate }
2007c478bd9Sstevel@tonic-gate CHash_T;
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate static CHash_T CHashAry[CPMHSIZE];
2037c478bd9Sstevel@tonic-gate static bool CHashAryOK = false;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate /*
2067c478bd9Sstevel@tonic-gate **  CLIENT_RATE - Evaluate connection rate per smtp client
2077c478bd9Sstevel@tonic-gate **
2087c478bd9Sstevel@tonic-gate **	Parameters:
2097c478bd9Sstevel@tonic-gate **		now - current time in secs
2107c478bd9Sstevel@tonic-gate **		saddr - client address
2117c478bd9Sstevel@tonic-gate **		update - update data / check only
2127c478bd9Sstevel@tonic-gate **
2137c478bd9Sstevel@tonic-gate **	Returns:
2147c478bd9Sstevel@tonic-gate **		connection rate (connections / ConnectionRateWindowSize)
2157c478bd9Sstevel@tonic-gate **
2167c478bd9Sstevel@tonic-gate **	Side effects:
2177c478bd9Sstevel@tonic-gate **		update static global data
2187c478bd9Sstevel@tonic-gate **
2197c478bd9Sstevel@tonic-gate */
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate static int
client_rate(now,saddr,update)2227c478bd9Sstevel@tonic-gate client_rate(now, saddr, update)
2237c478bd9Sstevel@tonic-gate 	 time_t now;
2247c478bd9Sstevel@tonic-gate 	 SOCKADDR *saddr;
2257c478bd9Sstevel@tonic-gate 	 bool update;
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	unsigned int hv;
2287c478bd9Sstevel@tonic-gate 	int i;
2297c478bd9Sstevel@tonic-gate 	int cnt;
2307c478bd9Sstevel@tonic-gate 	bool coll;
2317c478bd9Sstevel@tonic-gate 	CHash_T *chBest = NULL;
2327c478bd9Sstevel@tonic-gate 	unsigned int ticks;
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	cnt = 0;
2357c478bd9Sstevel@tonic-gate 	hv = 0xABC3D20F;
2367c478bd9Sstevel@tonic-gate 	if (ChtGran < 0)
2377c478bd9Sstevel@tonic-gate 		ChtGran = ConnectionRateWindowSize / CHTSIZE;
2387c478bd9Sstevel@tonic-gate 	if (ChtGran <= 0)
2397c478bd9Sstevel@tonic-gate 		ChtGran = 10;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	ticks = now / ChtGran;
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	if (!CHashAryOK)
2447c478bd9Sstevel@tonic-gate 	{
2457c478bd9Sstevel@tonic-gate 		memset(CHashAry, 0, sizeof(CHashAry));
2467c478bd9Sstevel@tonic-gate 		CHashAryOK = true;
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	{
2507c478bd9Sstevel@tonic-gate 		char *p;
2517c478bd9Sstevel@tonic-gate 		int addrlen;
2527c478bd9Sstevel@tonic-gate #if HASH_ALG != 1
2537c478bd9Sstevel@tonic-gate 		int c, d;
2547c478bd9Sstevel@tonic-gate #endif /* HASH_ALG != 1 */
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 		switch (saddr->sa.sa_family)
2577c478bd9Sstevel@tonic-gate 		{
2587c478bd9Sstevel@tonic-gate #if NETINET
2597c478bd9Sstevel@tonic-gate 		  case AF_INET:
2607c478bd9Sstevel@tonic-gate 			p = (char *)&saddr->sin.sin_addr;
2617c478bd9Sstevel@tonic-gate 			addrlen = sizeof(struct in_addr);
2627c478bd9Sstevel@tonic-gate 			break;
2637c478bd9Sstevel@tonic-gate #endif /* NETINET */
2647c478bd9Sstevel@tonic-gate #if NETINET6
2657c478bd9Sstevel@tonic-gate 		  case AF_INET6:
2667c478bd9Sstevel@tonic-gate 			p = (char *)&saddr->sin6.sin6_addr;
2677c478bd9Sstevel@tonic-gate 			addrlen = sizeof(struct in6_addr);
2687c478bd9Sstevel@tonic-gate 			break;
2697c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
2707c478bd9Sstevel@tonic-gate 		  default:
2717c478bd9Sstevel@tonic-gate 			/* should not happen */
2727c478bd9Sstevel@tonic-gate 			return -1;
2737c478bd9Sstevel@tonic-gate 		}
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 		/* compute hash value */
2767c478bd9Sstevel@tonic-gate 		for (i = 0; i < addrlen; ++i, ++p)
2777c478bd9Sstevel@tonic-gate #if HASH_ALG == 1
2787c478bd9Sstevel@tonic-gate 			hv = (hv << 5) ^ (hv >> 23) ^ *p;
2797c478bd9Sstevel@tonic-gate 		hv = (hv ^ (hv >> 16));
2807c478bd9Sstevel@tonic-gate #elif HASH_ALG == 2
2817c478bd9Sstevel@tonic-gate 		{
2827c478bd9Sstevel@tonic-gate 			d = *p;
2837c478bd9Sstevel@tonic-gate 			c = d;
2847c478bd9Sstevel@tonic-gate 			c ^= c<<6;
2857c478bd9Sstevel@tonic-gate 			hv += (c<<11) ^ (c>>1);
2867c478bd9Sstevel@tonic-gate 			hv ^= (d<<14) + (d<<7) + (d<<4) + d;
2877c478bd9Sstevel@tonic-gate 		}
2887c478bd9Sstevel@tonic-gate #elif HASH_ALG == 3
2897c478bd9Sstevel@tonic-gate 		{
2907c478bd9Sstevel@tonic-gate 			hv = (hv << 4) + *p;
2917c478bd9Sstevel@tonic-gate 			d = hv & 0xf0000000;
2927c478bd9Sstevel@tonic-gate 			if (d != 0)
2937c478bd9Sstevel@tonic-gate 			{
2947c478bd9Sstevel@tonic-gate 				hv ^= (d >> 24);
2957c478bd9Sstevel@tonic-gate 				hv ^= d;
2967c478bd9Sstevel@tonic-gate 			}
2977c478bd9Sstevel@tonic-gate 		}
2987c478bd9Sstevel@tonic-gate #else /* HASH_ALG == 1 */
2997c478bd9Sstevel@tonic-gate 			hv = ((hv << 1) ^ (*p & 0377)) % cctx->cc_size;
3007c478bd9Sstevel@tonic-gate #endif /* HASH_ALG == 1 */
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	coll = true;
3047c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_CT_STEPS; ++i)
3057c478bd9Sstevel@tonic-gate 	{
3067c478bd9Sstevel@tonic-gate 		CHash_T *ch = &CHashAry[(hv + i) & CPMHMASK];
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate #if NETINET
3097c478bd9Sstevel@tonic-gate 		if (saddr->sa.sa_family == AF_INET &&
3107c478bd9Sstevel@tonic-gate 		    ch->ch_Family == AF_INET &&
3117c478bd9Sstevel@tonic-gate 		    (saddr->sin.sin_addr.s_addr == ch->ch_Addr4.s_addr ||
3127c478bd9Sstevel@tonic-gate 		     ch->ch_Addr4.s_addr == 0))
3137c478bd9Sstevel@tonic-gate 		{
3147c478bd9Sstevel@tonic-gate 			chBest = ch;
3157c478bd9Sstevel@tonic-gate 			coll = false;
3167c478bd9Sstevel@tonic-gate 			break;
3177c478bd9Sstevel@tonic-gate 		}
3187c478bd9Sstevel@tonic-gate #endif /* NETINET */
3197c478bd9Sstevel@tonic-gate #if NETINET6
3207c478bd9Sstevel@tonic-gate 		if (saddr->sa.sa_family == AF_INET6 &&
3217c478bd9Sstevel@tonic-gate 		    ch->ch_Family == AF_INET6 &&
3227c478bd9Sstevel@tonic-gate 		    (IN6_ARE_ADDR_EQUAL(&saddr->sin6.sin6_addr,
3237c478bd9Sstevel@tonic-gate 				       &ch->ch_Addr6) != 0 ||
3247c478bd9Sstevel@tonic-gate 		     IN6_IS_ADDR_UNSPECIFIED(&ch->ch_Addr6)))
3257c478bd9Sstevel@tonic-gate 		{
3267c478bd9Sstevel@tonic-gate 			chBest = ch;
3277c478bd9Sstevel@tonic-gate 			coll = false;
3287c478bd9Sstevel@tonic-gate 			break;
3297c478bd9Sstevel@tonic-gate 		}
3307c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
3317c478bd9Sstevel@tonic-gate 		if (chBest == NULL || ch->ch_LTime == 0 ||
3327c478bd9Sstevel@tonic-gate 		    ch->ch_LTime < chBest->ch_LTime)
3337c478bd9Sstevel@tonic-gate 			chBest = ch;
3347c478bd9Sstevel@tonic-gate 	}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	/* Let's update data... */
3377c478bd9Sstevel@tonic-gate 	if (update)
3387c478bd9Sstevel@tonic-gate 	{
3397c478bd9Sstevel@tonic-gate 		if (coll && (now - chBest->ch_LTime < CollTime))
3407c478bd9Sstevel@tonic-gate 		{
3417c478bd9Sstevel@tonic-gate 			/*
3427c478bd9Sstevel@tonic-gate 			**  increment the number of collisions last
3437c478bd9Sstevel@tonic-gate 			**  CollTime for this client
3447c478bd9Sstevel@tonic-gate 			*/
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 			chBest->ch_colls++;
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 			/*
3497c478bd9Sstevel@tonic-gate 			**  Maybe shall log if collision rate is too high...
3507c478bd9Sstevel@tonic-gate 			**  and take measures to resize tables
3517c478bd9Sstevel@tonic-gate 			**  if this is the case
3527c478bd9Sstevel@tonic-gate 			*/
3537c478bd9Sstevel@tonic-gate 		}
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 		/*
3567c478bd9Sstevel@tonic-gate 		**  If it's not a match, then replace the data.
3577c478bd9Sstevel@tonic-gate 		**  Note: this purges the history of a colliding entry,
3587c478bd9Sstevel@tonic-gate 		**  which may cause "overruns", i.e., if two entries are
3597c478bd9Sstevel@tonic-gate 		**  "cancelling" each other out, then they may exceed
3607c478bd9Sstevel@tonic-gate 		**  the limits that are set. This might be mitigated a bit
3617c478bd9Sstevel@tonic-gate 		**  by the above "best of 5" function however.
3627c478bd9Sstevel@tonic-gate 		**
3637c478bd9Sstevel@tonic-gate 		**  Alternative approach: just use the old data, which may
3647c478bd9Sstevel@tonic-gate 		**  cause false positives however.
3657c478bd9Sstevel@tonic-gate 		**  To activate this, change deactivate following memset call.
3667c478bd9Sstevel@tonic-gate 		*/
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 		if (coll)
3697c478bd9Sstevel@tonic-gate 		{
3707c478bd9Sstevel@tonic-gate #if NETINET
3717c478bd9Sstevel@tonic-gate 			if (saddr->sa.sa_family == AF_INET)
3727c478bd9Sstevel@tonic-gate 			{
3737c478bd9Sstevel@tonic-gate 				chBest->ch_Family = AF_INET;
3747c478bd9Sstevel@tonic-gate 				chBest->ch_Addr4 = saddr->sin.sin_addr;
3757c478bd9Sstevel@tonic-gate 			}
3767c478bd9Sstevel@tonic-gate #endif /* NETINET */
3777c478bd9Sstevel@tonic-gate #if NETINET6
3787c478bd9Sstevel@tonic-gate 			if (saddr->sa.sa_family == AF_INET6)
3797c478bd9Sstevel@tonic-gate 			{
3807c478bd9Sstevel@tonic-gate 				chBest->ch_Family = AF_INET6;
3817c478bd9Sstevel@tonic-gate 				chBest->ch_Addr6 = saddr->sin6.sin6_addr;
3827c478bd9Sstevel@tonic-gate 			}
3837c478bd9Sstevel@tonic-gate #endif /* NETINET6 */
3847c478bd9Sstevel@tonic-gate #if 1
3857c478bd9Sstevel@tonic-gate 			memset(chBest->ch_Times, '\0',
3867c478bd9Sstevel@tonic-gate 			       sizeof(chBest->ch_Times));
3877c478bd9Sstevel@tonic-gate #endif /* 1 */
3887c478bd9Sstevel@tonic-gate 		}
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 		chBest->ch_LTime = now;
3917c478bd9Sstevel@tonic-gate 		{
3927c478bd9Sstevel@tonic-gate 			CTime_T *ct = &chBest->ch_Times[ticks % CHTSIZE];
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 			if (ct->ct_Ticks != ticks)
3957c478bd9Sstevel@tonic-gate 			{
3967c478bd9Sstevel@tonic-gate 				ct->ct_Ticks = ticks;
3977c478bd9Sstevel@tonic-gate 				ct->ct_Count = 0;
3987c478bd9Sstevel@tonic-gate 			}
3997c478bd9Sstevel@tonic-gate 			++ct->ct_Count;
4007c478bd9Sstevel@tonic-gate 		}
4017c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	/* Now let's count connections on the window */
4047c478bd9Sstevel@tonic-gate 	for (i = 0; i < CHTSIZE; ++i)
4057c478bd9Sstevel@tonic-gate 	{
4067c478bd9Sstevel@tonic-gate 		CTime_T *ct = &chBest->ch_Times[i];
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 		if (ct->ct_Ticks <= ticks && ct->ct_Ticks >= ticks - CHTSIZE)
4097c478bd9Sstevel@tonic-gate 			cnt += ct->ct_Count;
4107c478bd9Sstevel@tonic-gate 	}
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate #if RATECTL_DEBUG
4137c478bd9Sstevel@tonic-gate 	sm_syslog(LOG_WARNING, NOQID,
4147c478bd9Sstevel@tonic-gate 		"cln: cnt=(%d), CHTSIZE=(%d), ChtGran=(%d)",
4157c478bd9Sstevel@tonic-gate 		cnt, CHTSIZE, ChtGran);
4167c478bd9Sstevel@tonic-gate #endif /* RATECTL_DEBUG */
4177c478bd9Sstevel@tonic-gate 	return cnt;
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate /*
4217c478bd9Sstevel@tonic-gate **  TOTAL_RATE - Evaluate global connection rate
4227c478bd9Sstevel@tonic-gate **
4237c478bd9Sstevel@tonic-gate **	Parameters:
4247c478bd9Sstevel@tonic-gate **		now - current time in secs
4257c478bd9Sstevel@tonic-gate **		update - update data / check only
4267c478bd9Sstevel@tonic-gate **
4277c478bd9Sstevel@tonic-gate **	Returns:
4287c478bd9Sstevel@tonic-gate **		connection rate (connections / ConnectionRateWindowSize)
4297c478bd9Sstevel@tonic-gate */
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate static CTime_T srv_Times[CHTSIZE];
4327c478bd9Sstevel@tonic-gate static bool srv_Times_OK = false;
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate static int
total_rate(now,update)4357c478bd9Sstevel@tonic-gate total_rate(now, update)
4367c478bd9Sstevel@tonic-gate 	 time_t now;
4377c478bd9Sstevel@tonic-gate 	 bool update;
4387c478bd9Sstevel@tonic-gate {
4397c478bd9Sstevel@tonic-gate 	int i;
4407c478bd9Sstevel@tonic-gate 	int cnt = 0;
4417c478bd9Sstevel@tonic-gate 	CTime_T *ct;
4427c478bd9Sstevel@tonic-gate 	unsigned int ticks;
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	if (ChtGran < 0)
4457c478bd9Sstevel@tonic-gate 		ChtGran = ConnectionRateWindowSize / CHTSIZE;
4467c478bd9Sstevel@tonic-gate 	if (ChtGran == 0)
4477c478bd9Sstevel@tonic-gate 		ChtGran = 10;
4487c478bd9Sstevel@tonic-gate 	ticks = now / ChtGran;
4497c478bd9Sstevel@tonic-gate 	if (!srv_Times_OK)
4507c478bd9Sstevel@tonic-gate 	{
4517c478bd9Sstevel@tonic-gate 		memset(srv_Times, 0, sizeof(srv_Times));
4527c478bd9Sstevel@tonic-gate 		srv_Times_OK = true;
4537c478bd9Sstevel@tonic-gate 	}
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	/* Let's update data */
4567c478bd9Sstevel@tonic-gate 	if (update)
4577c478bd9Sstevel@tonic-gate 	{
4587c478bd9Sstevel@tonic-gate 		ct = &srv_Times[ticks % CHTSIZE];
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 		if (ct->ct_Ticks != ticks)
4617c478bd9Sstevel@tonic-gate 		{
4627c478bd9Sstevel@tonic-gate 			ct->ct_Ticks = ticks;
4637c478bd9Sstevel@tonic-gate 			ct->ct_Count = 0;
4647c478bd9Sstevel@tonic-gate 		}
4657c478bd9Sstevel@tonic-gate 		++ct->ct_Count;
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	/* Let's count connections on the window */
4697c478bd9Sstevel@tonic-gate 	for (i = 0; i < CHTSIZE; ++i)
4707c478bd9Sstevel@tonic-gate 	{
4717c478bd9Sstevel@tonic-gate 		ct = &srv_Times[i];
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 		if (ct->ct_Ticks <= ticks && ct->ct_Ticks >= ticks - CHTSIZE)
4747c478bd9Sstevel@tonic-gate 			cnt += ct->ct_Count;
4757c478bd9Sstevel@tonic-gate 	}
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate #if RATECTL_DEBUG
4787c478bd9Sstevel@tonic-gate 	sm_syslog(LOG_WARNING, NOQID,
4797c478bd9Sstevel@tonic-gate 		"srv: cnt=(%d), CHTSIZE=(%d), ChtGran=(%d)",
4807c478bd9Sstevel@tonic-gate 		 cnt, CHTSIZE, ChtGran);
4817c478bd9Sstevel@tonic-gate #endif /* RATECTL_DEBUG */
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	return cnt;
4847c478bd9Sstevel@tonic-gate }
485