]>
Commit | Line | Data |
---|---|---|
07378a2a TL |
1 | /* class.c |
2 | ||
3 | Handling for client classes. */ | |
4 | ||
5 | /* | |
7512d88b | 6 | * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC") |
98311e4b | 7 | * Copyright (c) 1998-2003 by Internet Software Consortium |
07378a2a | 8 | * |
7512d88b TM |
9 | * This Source Code Form is subject to the terms of the Mozilla Public |
10 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |
11 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
07378a2a | 12 | * |
98311e4b DH |
13 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES |
14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR | |
16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | |
19 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
07378a2a | 20 | * |
98311e4b DH |
21 | * Internet Systems Consortium, Inc. |
22 | * 950 Charter Street | |
23 | * Redwood City, CA 94063 | |
24 | * <info@isc.org> | |
2c85ac9b | 25 | * https://www.isc.org/ |
49733f31 | 26 | * |
07378a2a TL |
27 | */ |
28 | ||
07378a2a TL |
29 | #include "dhcpd.h" |
30 | ||
adb7ed1a | 31 | struct executable_statement *default_classification_rules; |
07378a2a | 32 | |
ee7b5624 TL |
33 | int have_billing_classes; |
34 | ||
07378a2a TL |
35 | /* Build the default classification rule tree. */ |
36 | ||
37 | void classification_setup () | |
38 | { | |
07378a2a | 39 | /* eval ... */ |
d758ad8c TL |
40 | default_classification_rules = (struct executable_statement *)0; |
41 | if (!executable_statement_allocate (&default_classification_rules, | |
42 | MDL)) | |
8ae2d595 | 43 | log_fatal ("Can't allocate check of default collection"); |
d758ad8c | 44 | default_classification_rules -> op = eval_statement; |
07378a2a | 45 | |
dce08243 | 46 | /* check-collection "default" */ |
d758ad8c TL |
47 | if (!expression_allocate (&default_classification_rules -> data.eval, |
48 | MDL)) | |
dce08243 | 49 | log_fatal ("Can't allocate default check expression"); |
d758ad8c TL |
50 | default_classification_rules -> data.eval -> op = expr_check; |
51 | default_classification_rules -> data.eval -> data.check = | |
52 | &default_collection; | |
07378a2a TL |
53 | } |
54 | ||
55 | void classify_client (packet) | |
56 | struct packet *packet; | |
57 | { | |
a7341359 SR |
58 | execute_statements (NULL, packet, NULL, NULL, packet->options, NULL, |
59 | &global_scope, default_classification_rules, NULL); | |
07378a2a TL |
60 | } |
61 | ||
da38df14 | 62 | int check_collection (packet, lease, collection) |
07378a2a | 63 | struct packet *packet; |
da38df14 | 64 | struct lease *lease; |
07378a2a TL |
65 | struct collection *collection; |
66 | { | |
67 | struct class *class, *nc; | |
68 | struct data_string data; | |
69 | int matched = 0; | |
4af075a2 | 70 | int status; |
63f8b323 | 71 | int ignorep; |
33692791 | 72 | int classfound; |
07378a2a TL |
73 | |
74 | for (class = collection -> classes; class; class = class -> nic) { | |
74a2049e | 75 | #if defined (DEBUG_CLASS_MATCHING) |
8ae2d595 | 76 | log_info ("checking against class %s...", class -> name); |
74a2049e | 77 | #endif |
ee7b5624 | 78 | memset (&data, 0, sizeof data); |
56120203 TL |
79 | |
80 | /* If there is a "match if" expression, check it. If | |
81 | we get a match, and there's no subclass expression, | |
82 | it's a match. If we get a match and there is a subclass | |
83 | expression, then we check the submatch. If it's not a | |
84 | match, that's final - we don't check the submatch. */ | |
85 | ||
86 | if (class -> expr) { | |
87 | status = (evaluate_boolean_expression_result | |
88 | (&ignorep, packet, lease, | |
9e383163 | 89 | (struct client_state *)0, |
56120203 | 90 | packet -> options, (struct option_state *)0, |
eaa84150 TL |
91 | lease ? &lease -> scope : &global_scope, |
92 | class -> expr)); | |
56120203 TL |
93 | if (status) { |
94 | if (!class -> submatch) { | |
95 | matched = 1; | |
96 | #if defined (DEBUG_CLASS_MATCHING) | |
97 | log_info ("matches class."); | |
98 | #endif | |
99 | classify (packet, class); | |
100 | continue; | |
101 | } | |
102 | } else | |
103 | continue; | |
104 | } | |
105 | ||
106 | /* Check to see if the client matches an existing subclass. | |
107 | If it doesn't, and this is a spawning class, spawn a new | |
108 | subclass and put the client in it. */ | |
8b500185 | 109 | if (class -> submatch) { |
dce08243 TL |
110 | status = (evaluate_data_expression |
111 | (&data, packet, lease, | |
9e383163 | 112 | (struct client_state *)0, |
dce08243 | 113 | packet -> options, (struct option_state *)0, |
5b5fcc81 | 114 | lease ? &lease -> scope : &global_scope, |
d758ad8c | 115 | class -> submatch, MDL)); |
b767664e | 116 | if (status && data.len) { |
20916cae | 117 | nc = (struct class *)0; |
33692791 DH |
118 | classfound = class_hash_lookup (&nc, class -> hash, |
119 | (const char *)data.data, data.len, MDL); | |
120 | ||
121 | #ifdef LDAP_CONFIGURATION | |
122 | if (!classfound && find_subclass_in_ldap (class, &nc, &data)) | |
123 | classfound = 1; | |
124 | #endif | |
125 | ||
126 | if (classfound) { | |
74a2049e | 127 | #if defined (DEBUG_CLASS_MATCHING) |
8ae2d595 | 128 | log_info ("matches subclass %s.", |
ee7b5624 TL |
129 | print_hex_1 (data.len, |
130 | data.data, 60)); | |
131 | #endif | |
12c9957e | 132 | data_string_forget (&data, MDL); |
ee7b5624 TL |
133 | classify (packet, nc); |
134 | matched = 1; | |
a19e8a45 | 135 | class_dereference (&nc, MDL); |
ee7b5624 TL |
136 | continue; |
137 | } | |
12c9957e TL |
138 | if (!class -> spawning) { |
139 | data_string_forget (&data, MDL); | |
8b500185 | 140 | continue; |
12c9957e | 141 | } |
fea20b09 | 142 | /* XXX Write out the spawned class? */ |
ee7b5624 | 143 | #if defined (DEBUG_CLASS_MATCHING) |
8ae2d595 | 144 | log_info ("spawning subclass %s.", |
64e1dc1d | 145 | print_hex_1 (data.len, data.data, 60)); |
74a2049e | 146 | #endif |
a19e8a45 TL |
147 | status = class_allocate (&nc, MDL); |
148 | group_reference (&nc -> group, | |
149 | class -> group, MDL); | |
150 | class_reference (&nc -> superclass, | |
151 | class, MDL); | |
ee7b5624 TL |
152 | nc -> lease_limit = class -> lease_limit; |
153 | nc -> dirty = 1; | |
154 | if (nc -> lease_limit) { | |
155 | nc -> billed_leases = | |
156 | (dmalloc | |
157 | (nc -> lease_limit * | |
158 | sizeof (struct lease *), | |
12c9957e | 159 | MDL)); |
ee7b5624 | 160 | if (!nc -> billed_leases) { |
7e6f3635 TL |
161 | log_error ("no memory for%s", |
162 | " billing"); | |
ee7b5624 TL |
163 | data_string_forget |
164 | (&nc -> hash_string, | |
12c9957e | 165 | MDL); |
a19e8a45 | 166 | class_dereference (&nc, MDL); |
12c9957e TL |
167 | data_string_forget (&data, |
168 | MDL); | |
ee7b5624 TL |
169 | continue; |
170 | } | |
171 | memset (nc -> billed_leases, 0, | |
172 | (nc -> lease_limit * | |
0f750c4f | 173 | sizeof (struct lease *))); |
ee7b5624 TL |
174 | } |
175 | data_string_copy (&nc -> hash_string, &data, | |
12c9957e | 176 | MDL); |
ee7b5624 | 177 | if (!class -> hash) |
f7fdb216 DH |
178 | class_new_hash(&class->hash, |
179 | SCLASS_HASH_SIZE, MDL); | |
20916cae TL |
180 | class_hash_add (class -> hash, |
181 | (const char *) | |
182 | nc -> hash_string.data, | |
183 | nc -> hash_string.len, | |
184 | nc, MDL); | |
ee7b5624 | 185 | classify (packet, nc); |
d758ad8c | 186 | class_dereference (&nc, MDL); |
07378a2a | 187 | } |
0cd94b5e TM |
188 | |
189 | data_string_forget (&data, MDL); | |
07378a2a | 190 | } |
07378a2a TL |
191 | } |
192 | return matched; | |
193 | } | |
194 | ||
195 | void classify (packet, class) | |
196 | struct packet *packet; | |
197 | struct class *class; | |
198 | { | |
199 | if (packet -> class_count < PACKET_MAX_CLASSES) | |
20916cae TL |
200 | class_reference (&packet -> classes [packet -> class_count++], |
201 | class, MDL); | |
07378a2a | 202 | else |
d758ad8c | 203 | log_error ("too many classes match %s", |
07378a2a TL |
204 | print_hw_addr (packet -> raw -> htype, |
205 | packet -> raw -> hlen, | |
206 | packet -> raw -> chaddr)); | |
207 | } | |
208 | ||
899d754f JB |
209 | |
210 | isc_result_t unlink_class(struct class **class) { | |
211 | struct collection *lp; | |
212 | struct class *cp, *pp; | |
213 | ||
214 | for (lp = collections; lp; lp = lp -> next) { | |
215 | for (pp = 0, cp = lp -> classes; cp; pp = cp, cp = cp -> nic) | |
216 | if (cp == *class) { | |
217 | if (pp == 0) { | |
218 | lp->classes = cp->nic; | |
219 | } else { | |
220 | pp->nic = cp->nic; | |
221 | } | |
222 | cp->nic = 0; | |
223 | class_dereference(class, MDL); | |
224 | ||
225 | return ISC_R_SUCCESS; | |
226 | } | |
227 | } | |
228 | return ISC_R_NOTFOUND; | |
229 | } | |
230 | ||
6a39bcf0 | 231 | |
20916cae TL |
232 | isc_result_t find_class (struct class **class, const char *name, |
233 | const char *file, int line) | |
adb7ed1a TL |
234 | { |
235 | struct collection *lp; | |
236 | struct class *cp; | |
237 | ||
238 | for (lp = collections; lp; lp = lp -> next) { | |
239 | for (cp = lp -> classes; cp; cp = cp -> nic) | |
20916cae TL |
240 | if (cp -> name && !strcmp (name, cp -> name)) { |
241 | return class_reference (class, cp, file, line); | |
242 | } | |
adb7ed1a | 243 | } |
20916cae | 244 | return ISC_R_NOTFOUND; |
adb7ed1a | 245 | } |
ee7b5624 | 246 | |
6a39bcf0 TM |
247 | /* Removes the billing class from a lease |
248 | * | |
249 | * Note that because classes can be created and removed dynamically, it is | |
250 | * possible that the class to which a lease was billed has since been deleted. | |
251 | * To cover the case where the lease is the last reference to a deleted class | |
252 | * we remove the lease reference from the class first, then the class from the | |
253 | * lease. To protect ourselves from the reverse situation, where the class is | |
254 | * the last reference to the lease (unlikely), we create a guard reference to | |
255 | * the lease, then remove it at the end. | |
256 | */ | |
257 | void unbill_class (lease) | |
ee7b5624 | 258 | struct lease *lease; |
ee7b5624 TL |
259 | { |
260 | int i; | |
6a39bcf0 TM |
261 | struct class* class = lease->billing_class; |
262 | struct lease* refholder = NULL; | |
ee7b5624 | 263 | |
6a39bcf0 TM |
264 | /* if there's no billing to remove, nothing to do */ |
265 | if (class == NULL) { | |
266 | return; | |
267 | } | |
268 | ||
269 | /* Find the lease in the list of the class's billed leases */ | |
270 | for (i = 0; i < class->lease_limit; i++) { | |
271 | if (class->billed_leases[i] == lease) | |
ee7b5624 | 272 | break; |
6a39bcf0 TM |
273 | } |
274 | ||
275 | /* Create guard reference, so class cannot be last reference to lease */ | |
276 | lease_reference(&refholder, lease, MDL); | |
277 | ||
278 | /* If the class doesn't have the lease, then something is broken | |
279 | * programmatically. We'll log it but skip the lease dereference. */ | |
280 | if (i == class->lease_limit) { | |
8ae2d595 | 281 | log_error ("lease %s unbilled with no billing arrangement.", |
6a39bcf0 TM |
282 | piaddr(lease->ip_addr)); |
283 | } else { | |
284 | /* Remove the lease from the class */ | |
285 | lease_dereference(&class->billed_leases[i], MDL); | |
286 | class->leases_consumed--; | |
ee7b5624 | 287 | } |
6a39bcf0 TM |
288 | |
289 | /* Remove the class from the lease */ | |
290 | class_dereference(&lease->billing_class, MDL); | |
291 | ||
292 | /* Ditch our guard reference */ | |
293 | lease_dereference(&refholder, MDL); | |
ee7b5624 TL |
294 | } |
295 | ||
296 | int bill_class (lease, class) | |
297 | struct lease *lease; | |
298 | struct class *class; | |
299 | { | |
300 | int i; | |
301 | ||
bf7a9284 TL |
302 | if (lease -> billing_class) { |
303 | log_error ("lease billed with existing billing arrangement."); | |
6a39bcf0 | 304 | unbill_class (lease); |
bf7a9284 TL |
305 | } |
306 | ||
ee7b5624 TL |
307 | if (class -> leases_consumed == class -> lease_limit) |
308 | return 0; | |
309 | ||
310 | for (i = 0; i < class -> lease_limit; i++) | |
311 | if (!class -> billed_leases [i]) | |
312 | break; | |
313 | ||
314 | if (i == class -> lease_limit) { | |
8ae2d595 | 315 | log_error ("class billing consumption disagrees with leases."); |
ee7b5624 TL |
316 | return 0; |
317 | } | |
318 | ||
20916cae TL |
319 | lease_reference (&class -> billed_leases [i], lease, MDL); |
320 | class_reference (&lease -> billing_class, class, MDL); | |
ee7b5624 TL |
321 | class -> leases_consumed++; |
322 | return 1; | |
323 | } |