1 /*
2  *   IRC - Internet Relay Chat, ircd/class.c
3  *   Copyright (C) 1990 Darren Reed
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 1, or (at your option)
8  *   any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 #ifndef lint
21 static const volatile char rcsid[] = "@(#)$Id: class.c,v 1.28 2008/06/22 16:09:07 chopin Exp $";
22 #endif
23 
24 #include "os.h"
25 #include "s_defines.h"
26 #define CLASS_C
27 #include "s_externs.h"
28 #undef CLASS_C
29 #ifdef ENABLE_CIDR_LIMITS
30 #include "patricia_ext.h"
31 #endif
32 
33 #define BAD_CONF_CLASS		-1
34 #define BAD_PING		-2
35 #define BAD_CLIENT_CLASS	-3
36 
37 aClass	*classes;
38 
get_conf_class(aConfItem * aconf)39 int	get_conf_class(aConfItem *aconf)
40 {
41 	if ((aconf) && Class(aconf))
42 		return (ConfClass(aconf));
43 
44 	Debug((DEBUG_DEBUG,"No Class For %s",
45 	      (aconf) ? aconf->name : "*No Conf*"));
46 
47 	return (BAD_CONF_CLASS);
48 
49 }
50 
get_conf_ping(aConfItem * aconf)51 static	int	get_conf_ping(aConfItem *aconf)
52 {
53 	if ((aconf) && Class(aconf))
54 		return (ConfPingFreq(aconf));
55 
56 	Debug((DEBUG_DEBUG,"No Ping For %s",
57 	      (aconf) ? aconf->name : "*No Conf*"));
58 
59 	return (BAD_PING);
60 }
61 
62 
63 
get_client_class(aClient * acptr)64 int	get_client_class(aClient *acptr)
65 {
66 	Reg	Link	*tmp;
67 	Reg	aClass	*cl;
68 	int	retc = BAD_CLIENT_CLASS;
69 
70 	if (acptr && !IsMe(acptr)  && (acptr->confs))
71 		for (tmp = acptr->confs; tmp; tmp = tmp->next)
72 		    {
73 			if (!tmp->value.aconf ||
74 			    !(cl = tmp->value.aconf->class))
75 				continue;
76 			retc = Class(cl);
77 			break;
78 		    }
79 
80 	Debug((DEBUG_DEBUG,"Returning Class %d For %s",retc,acptr->name));
81 
82 	return (retc);
83 }
84 
get_client_ping(aClient * acptr)85 int	get_client_ping(aClient *acptr)
86 {
87 	int	ping = 0, ping2;
88 	aConfItem	*aconf;
89 	Link	*link;
90 
91 	link = acptr->confs;
92 
93 	if (link)
94 		while (link)
95 		    {
96 			aconf = link->value.aconf;
97 			if (aconf->status & (CONF_CLIENT|CONF_CONNECT_SERVER|
98 					     CONF_NOCONNECT_SERVER|
99 					     CONF_ZCONNECT_SERVER))
100 			    {
101 				ping2 = get_conf_ping(aconf);
102 				if ((ping2 != BAD_PING) && ((ping > ping2) ||
103 				    !ping))
104 					ping = ping2;
105 			     }
106 			link = link->next;
107 		    }
108 	else
109 	    {
110 		ping = PINGFREQUENCY;
111 		Debug((DEBUG_DEBUG,"No Attached Confs"));
112 	    }
113 	if (ping <= 0)
114 		ping = PINGFREQUENCY;
115 	Debug((DEBUG_DEBUG,"Client %s Ping %d", acptr->name, ping));
116 	return (ping);
117 }
118 
get_con_freq(aClass * clptr)119 int	get_con_freq(aClass *clptr)
120 {
121 	if (clptr)
122 		return (MAX(60, ConFreq(clptr)));
123 	else
124 		return (CONNECTFREQUENCY);
125 }
126 
127 /*
128  * When adding a class, check to see if it is already present first.
129  * if so, then update the information for that class, rather than create
130  * a new entry for it and later delete the old entry.
131  * if no present entry is found, then create a new one and add it in
132  * immeadiately after the first one (class 0).
133  */
add_class(int class,int ping,int confreq,int maxli,int sendq,int bsendq,int hlocal,int uhlocal,int hglobal,int uhglobal,char * cidrlen_s)134 void	add_class(int class, int ping, int confreq, int maxli, int sendq,
135 		int bsendq, int hlocal, int uhlocal, int hglobal, int uhglobal
136 #ifdef ENABLE_CIDR_LIMITS
137 		, char *cidrlen_s
138 #endif
139       )
140 {
141 	aClass *t, *p;
142 #ifdef ENABLE_CIDR_LIMITS
143 	char *tmp;
144 	int cidrlen = 0, cidramount = 0;
145 
146 	if(cidrlen_s)
147 	{
148 		if((tmp = index(cidrlen_s, '/')))
149 		{
150 			*tmp++ = '\0';
151 
152 			cidramount = atoi(cidrlen_s);
153 			cidrlen = atoi(tmp);
154 		}
155 	}
156 #endif
157 
158 	t = find_class(class);
159 	if ((t == classes) && (class != 0))
160 	    {
161 		p = (aClass *)make_class();
162 		NextClass(p) = NextClass(t);
163 		NextClass(t) = p;
164 		MaxSendq(p) = QUEUELEN;
165 #ifdef ENABLE_CIDR_LIMITS
166 		CidrLen(p) = 0;
167 		p->ip_limits = NULL;
168 #endif
169 		istat.is_class++;
170 	    }
171 	else
172 		p = t;
173 	Debug((DEBUG_DEBUG,
174 "Add Class %d: p %x t %x - cf: %d pf: %d ml: %d sq: %d.%d ml: %d.%d mg: %d.%d",
175 		class, p, t, confreq, ping, maxli, sendq, bsendq, hlocal, uhlocal,
176 	       hglobal, uhglobal));
177 	Class(p) = class;
178 	ConFreq(p) = confreq;
179 	PingFreq(p) = ping;
180 	MaxLinks(p) = maxli;
181 	if (sendq)
182 		MaxSendq(p) = sendq;
183 	MaxBSendq(p) = bsendq ? bsendq : 0;
184 	MaxHLocal(p) = hlocal;
185 	MaxUHLocal(p) = uhlocal;
186 	MaxHGlobal(p) = hglobal;
187 	MaxUHGlobal(p) = uhglobal;
188 
189 #ifdef ENABLE_CIDR_LIMITS
190 	if (cidrlen > 0 && CidrLen(p) == 0 && p->ip_limits == NULL)
191 	{
192 		CidrLen(p) = cidrlen;
193 #  ifdef INET6
194 		p->ip_limits = (struct _patricia_tree_t *) patricia_new(128);
195 #  else
196 		p->ip_limits = (struct _patricia_tree_t *) patricia_new(32);
197 #  endif
198 	}
199 	if (CidrLen(p) != cidrlen)
200 	{
201 		/* Hmpf, sendto_somewhere maybe to warn? --B. */
202 		Debug((DEBUG_NOTICE,
203 			"Cannot change cidrlen on the fly (class %d)",
204 			Class(p)));
205 	}
206 	if (CidrLen(p) > 0)
207 		MaxCidrAmount(p) = cidramount;
208 #endif
209 	if (p != t)
210 		Links(p) = 0;
211 }
212 
find_class(int cclass)213 aClass	*find_class(int cclass)
214 {
215 	aClass *cltmp;
216 
217 	for (cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp))
218 		if (Class(cltmp) == cclass)
219 			return cltmp;
220 	return classes;
221 }
222 
check_class(void)223 void	check_class(void)
224 {
225 	Reg	aClass	*cltmp, *cltmp2;
226 
227 	Debug((DEBUG_DEBUG, "Class check:"));
228 
229 	for (cltmp2 = cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp2))
230 	    {
231 		Debug((DEBUG_DEBUG,
232 			"Class %d : CF: %d PF: %d ML: %d LI: %d SQ: %ld",
233 			Class(cltmp), ConFreq(cltmp), PingFreq(cltmp),
234 			MaxLinks(cltmp), Links(cltmp), MaxSendq(cltmp)));
235 		if (MaxLinks(cltmp) < 0)
236 		    {
237 			NextClass(cltmp2) = NextClass(cltmp);
238 			if (Links(cltmp) <= 0)
239 			{
240 				free_class(cltmp);
241 				istat.is_class--;
242 			}
243 		    }
244 		else
245 			cltmp2 = cltmp;
246 	    }
247 }
248 
initclass(void)249 void	initclass(void)
250 {
251 	classes = (aClass *)make_class();
252 	istat.is_class++;
253 
254 	Class(FirstClass()) = 0;
255 	ConFreq(FirstClass()) = CONNECTFREQUENCY;
256 	PingFreq(FirstClass()) = PINGFREQUENCY;
257 	MaxLinks(FirstClass()) = MAXIMUM_LINKS;
258 	MaxSendq(FirstClass()) = QUEUELEN;
259 	MaxBSendq(FirstClass()) = 0;
260 	Links(FirstClass()) = 0;
261 	NextClass(FirstClass()) = NULL;
262 	MaxHLocal(FirstClass()) = 1;
263 	MaxUHLocal(FirstClass()) = 1;
264 	MaxHGlobal(FirstClass()) = 1;
265 	MaxUHGlobal(FirstClass()) = 1;
266 #ifdef ENABLE_CIDR_LIMITS
267 	CidrLen(FirstClass()) = 0;
268 	FirstClass()->ip_limits = NULL;
269 #endif
270 }
271 
report_classes(aClient * sptr,char * to)272 void	report_classes(aClient *sptr, char *to)
273 {
274 	Reg	aClass	*cltmp;
275 	char	tmp[64] = "";
276 
277 	for (cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp))
278 	{
279 #ifdef ENABLE_CIDR_LIMITS
280 		if (MaxCidrAmount(cltmp) > 0 && CidrLen(cltmp) > 0)
281 			/* leading space is important */
282 			snprintf(tmp, sizeof(tmp), " %d/%d",
283 				MaxCidrAmount(cltmp), CidrLen(cltmp));
284 		else
285 			tmp[0] = '\0';
286 #endif
287 		sendto_one(sptr, replies[RPL_STATSYLINE], ME, BadTo(to), 'Y',
288 			Class(cltmp), PingFreq(cltmp), ConFreq(cltmp),
289 			MaxLinks(cltmp), MaxSendq(cltmp), MaxBSendq(cltmp),
290 			MaxHLocal(cltmp), MaxUHLocal(cltmp),
291 			MaxHGlobal(cltmp), MaxUHGlobal(cltmp), Links(cltmp), tmp);
292 	}
293 }
294 
get_sendq(aClient * cptr,int bursting)295 int	get_sendq(aClient *cptr, int bursting)
296 {
297 	Reg	int	sendq = QUEUELEN;
298 	Reg	Link	*tmp;
299 	Reg	aClass	*cl;
300 
301 	if (cptr->serv && cptr->serv->nline)
302 		sendq = bursting && MaxBSendq(cptr->serv->nline->class) ?
303 			MaxBSendq(cptr->serv->nline->class) :
304 			MaxSendq(cptr->serv->nline->class);
305 	else if (cptr && !IsMe(cptr)  && (cptr->confs))
306 		for (tmp = cptr->confs; tmp; tmp = tmp->next)
307 		    {
308 			if (!tmp->value.aconf ||
309 			    !(cl = tmp->value.aconf->class))
310 				continue;
311 			sendq = bursting && MaxBSendq(cl) ?
312 				MaxBSendq(cl) : MaxSendq(cl);
313 			break;
314 		    }
315 	return sendq;
316 }
317 
318