1 /* $NetBSD: class.c,v 1.1.1.3 2014/07/12 11:58:04 spz Exp $ */
2 /* class.c
3
4 Handling for client classes. */
5
6 /*
7 * Copyright (c) 2009,2012-2014 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 1998-2003 by Internet Software Consortium
10 *
11 * Permission to use, copy, modify, and distribute this software for any
12 * purpose with or without fee is hereby granted, provided that the above
13 * copyright notice and this permission notice appear in all copies.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Internet Systems Consortium, Inc.
24 * 950 Charter Street
25 * Redwood City, CA 94063
26 * <info@isc.org>
27 * https://www.isc.org/
28 *
29 */
30
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: class.c,v 1.1.1.3 2014/07/12 11:58:04 spz Exp $");
33
34 #include "dhcpd.h"
35
36 struct collection default_collection = {
37 (struct collection *)0,
38 "default",
39 (struct class *)0,
40 };
41
42 struct collection *collections = &default_collection;
43 struct executable_statement *default_classification_rules;
44
45 int have_billing_classes;
46
47 /* Build the default classification rule tree. */
48
classification_setup()49 void classification_setup ()
50 {
51 /* eval ... */
52 default_classification_rules = (struct executable_statement *)0;
53 if (!executable_statement_allocate (&default_classification_rules,
54 MDL))
55 log_fatal ("Can't allocate check of default collection");
56 default_classification_rules -> op = eval_statement;
57
58 /* check-collection "default" */
59 if (!expression_allocate (&default_classification_rules -> data.eval,
60 MDL))
61 log_fatal ("Can't allocate default check expression");
62 default_classification_rules -> data.eval -> op = expr_check;
63 default_classification_rules -> data.eval -> data.check =
64 &default_collection;
65 }
66
classify_client(packet)67 void classify_client (packet)
68 struct packet *packet;
69 {
70 execute_statements (NULL, packet, NULL, NULL, packet->options, NULL,
71 &global_scope, default_classification_rules, NULL);
72 }
73
check_collection(packet,lease,collection)74 int check_collection (packet, lease, collection)
75 struct packet *packet;
76 struct lease *lease;
77 struct collection *collection;
78 {
79 struct class *class, *nc;
80 struct data_string data;
81 int matched = 0;
82 int status;
83 int ignorep;
84 int classfound;
85
86 for (class = collection -> classes; class; class = class -> nic) {
87 #if defined (DEBUG_CLASS_MATCHING)
88 log_info ("checking against class %s...", class -> name);
89 #endif
90 memset (&data, 0, sizeof data);
91
92 /* If there is a "match if" expression, check it. If
93 we get a match, and there's no subclass expression,
94 it's a match. If we get a match and there is a subclass
95 expression, then we check the submatch. If it's not a
96 match, that's final - we don't check the submatch. */
97
98 if (class -> expr) {
99 status = (evaluate_boolean_expression_result
100 (&ignorep, packet, lease,
101 (struct client_state *)0,
102 packet -> options, (struct option_state *)0,
103 lease ? &lease -> scope : &global_scope,
104 class -> expr));
105 if (status) {
106 if (!class -> submatch) {
107 matched = 1;
108 #if defined (DEBUG_CLASS_MATCHING)
109 log_info ("matches class.");
110 #endif
111 classify (packet, class);
112 continue;
113 }
114 } else
115 continue;
116 }
117
118 /* Check to see if the client matches an existing subclass.
119 If it doesn't, and this is a spawning class, spawn a new
120 subclass and put the client in it. */
121 if (class -> submatch) {
122 status = (evaluate_data_expression
123 (&data, packet, lease,
124 (struct client_state *)0,
125 packet -> options, (struct option_state *)0,
126 lease ? &lease -> scope : &global_scope,
127 class -> submatch, MDL));
128 if (status && data.len) {
129 nc = (struct class *)0;
130 classfound = class_hash_lookup (&nc, class -> hash,
131 (const char *)data.data, data.len, MDL);
132
133 #ifdef LDAP_CONFIGURATION
134 if (!classfound && find_subclass_in_ldap (class, &nc, &data))
135 classfound = 1;
136 #endif
137
138 if (classfound) {
139 #if defined (DEBUG_CLASS_MATCHING)
140 log_info ("matches subclass %s.",
141 print_hex_1 (data.len,
142 data.data, 60));
143 #endif
144 data_string_forget (&data, MDL);
145 classify (packet, nc);
146 matched = 1;
147 class_dereference (&nc, MDL);
148 continue;
149 }
150 if (!class -> spawning) {
151 data_string_forget (&data, MDL);
152 continue;
153 }
154 /* XXX Write out the spawned class? */
155 #if defined (DEBUG_CLASS_MATCHING)
156 log_info ("spawning subclass %s.",
157 print_hex_1 (data.len, data.data, 60));
158 #endif
159 status = class_allocate (&nc, MDL);
160 group_reference (&nc -> group,
161 class -> group, MDL);
162 class_reference (&nc -> superclass,
163 class, MDL);
164 nc -> lease_limit = class -> lease_limit;
165 nc -> dirty = 1;
166 if (nc -> lease_limit) {
167 nc -> billed_leases =
168 (dmalloc
169 (nc -> lease_limit *
170 sizeof (struct lease *),
171 MDL));
172 if (!nc -> billed_leases) {
173 log_error ("no memory for%s",
174 " billing");
175 data_string_forget
176 (&nc -> hash_string,
177 MDL);
178 class_dereference (&nc, MDL);
179 data_string_forget (&data,
180 MDL);
181 continue;
182 }
183 memset (nc -> billed_leases, 0,
184 (nc -> lease_limit *
185 sizeof (struct lease *)));
186 }
187 data_string_copy (&nc -> hash_string, &data,
188 MDL);
189 data_string_forget (&data, MDL);
190 if (!class -> hash)
191 class_new_hash(&class->hash,
192 SCLASS_HASH_SIZE, MDL);
193 class_hash_add (class -> hash,
194 (const char *)
195 nc -> hash_string.data,
196 nc -> hash_string.len,
197 nc, MDL);
198 classify (packet, nc);
199 class_dereference (&nc, MDL);
200 }
201 }
202 }
203 return matched;
204 }
205
classify(packet,class)206 void classify (packet, class)
207 struct packet *packet;
208 struct class *class;
209 {
210 if (packet -> class_count < PACKET_MAX_CLASSES)
211 class_reference (&packet -> classes [packet -> class_count++],
212 class, MDL);
213 else
214 log_error ("too many classes match %s",
215 print_hw_addr (packet -> raw -> htype,
216 packet -> raw -> hlen,
217 packet -> raw -> chaddr));
218 }
219
220
unlink_class(struct class ** class)221 isc_result_t unlink_class(struct class **class) {
222 struct collection *lp;
223 struct class *cp, *pp;
224
225 for (lp = collections; lp; lp = lp -> next) {
226 for (pp = 0, cp = lp -> classes; cp; pp = cp, cp = cp -> nic)
227 if (cp == *class) {
228 if (pp == 0) {
229 lp->classes = cp->nic;
230 } else {
231 pp->nic = cp->nic;
232 }
233 cp->nic = 0;
234 class_dereference(class, MDL);
235
236 return ISC_R_SUCCESS;
237 }
238 }
239 return ISC_R_NOTFOUND;
240 }
241
242
find_class(struct class ** class,const char * name,const char * file,int line)243 isc_result_t find_class (struct class **class, const char *name,
244 const char *file, int line)
245 {
246 struct collection *lp;
247 struct class *cp;
248
249 for (lp = collections; lp; lp = lp -> next) {
250 for (cp = lp -> classes; cp; cp = cp -> nic)
251 if (cp -> name && !strcmp (name, cp -> name)) {
252 return class_reference (class, cp, file, line);
253 }
254 }
255 return ISC_R_NOTFOUND;
256 }
257
unbill_class(lease,class)258 int unbill_class (lease, class)
259 struct lease *lease;
260 struct class *class;
261 {
262 int i;
263
264 for (i = 0; i < class -> lease_limit; i++)
265 if (class -> billed_leases [i] == lease)
266 break;
267 if (i == class -> lease_limit) {
268 log_error ("lease %s unbilled with no billing arrangement.",
269 piaddr (lease -> ip_addr));
270 return 0;
271 }
272 class_dereference (&lease -> billing_class, MDL);
273 lease_dereference (&class -> billed_leases [i], MDL);
274 class -> leases_consumed--;
275 return 1;
276 }
277
bill_class(lease,class)278 int bill_class (lease, class)
279 struct lease *lease;
280 struct class *class;
281 {
282 int i;
283
284 if (lease -> billing_class) {
285 log_error ("lease billed with existing billing arrangement.");
286 unbill_class (lease, lease -> billing_class);
287 }
288
289 if (class -> leases_consumed == class -> lease_limit)
290 return 0;
291
292 for (i = 0; i < class -> lease_limit; i++)
293 if (!class -> billed_leases [i])
294 break;
295
296 if (i == class -> lease_limit) {
297 log_error ("class billing consumption disagrees with leases.");
298 return 0;
299 }
300
301 lease_reference (&class -> billed_leases [i], lease, MDL);
302 class_reference (&lease -> billing_class, class, MDL);
303 class -> leases_consumed++;
304 return 1;
305 }
306