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