]> git.ipfire.org Git - thirdparty/dhcp.git/blob - server/class.c
[master] dhcpd (-6) now supports update-static-leases
[thirdparty/dhcp.git] / server / class.c
1 /* class.c
2
3 Handling for client classes. */
4
5 /*
6 * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1998-2003 by Internet Software Consortium
8 *
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/.
12 *
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.
20 *
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * https://www.isc.org/
26 *
27 */
28
29 #include "dhcpd.h"
30
31 struct executable_statement *default_classification_rules;
32
33 int have_billing_classes;
34
35 /* Build the default classification rule tree. */
36
37 void classification_setup ()
38 {
39 /* eval ... */
40 default_classification_rules = (struct executable_statement *)0;
41 if (!executable_statement_allocate (&default_classification_rules,
42 MDL))
43 log_fatal ("Can't allocate check of default collection");
44 default_classification_rules -> op = eval_statement;
45
46 /* check-collection "default" */
47 if (!expression_allocate (&default_classification_rules -> data.eval,
48 MDL))
49 log_fatal ("Can't allocate default check expression");
50 default_classification_rules -> data.eval -> op = expr_check;
51 default_classification_rules -> data.eval -> data.check =
52 &default_collection;
53 }
54
55 void classify_client (packet)
56 struct packet *packet;
57 {
58 execute_statements (NULL, packet, NULL, NULL, packet->options, NULL,
59 &global_scope, default_classification_rules, NULL);
60 }
61
62 int check_collection (packet, lease, collection)
63 struct packet *packet;
64 struct lease *lease;
65 struct collection *collection;
66 {
67 struct class *class, *nc;
68 struct data_string data;
69 int matched = 0;
70 int status;
71 int ignorep;
72 int classfound;
73
74 for (class = collection -> classes; class; class = class -> nic) {
75 #if defined (DEBUG_CLASS_MATCHING)
76 log_info ("checking against class %s...", class -> name);
77 #endif
78 memset (&data, 0, sizeof data);
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,
89 (struct client_state *)0,
90 packet -> options, (struct option_state *)0,
91 lease ? &lease -> scope : &global_scope,
92 class -> expr));
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. */
109 if (class -> submatch) {
110 status = (evaluate_data_expression
111 (&data, packet, lease,
112 (struct client_state *)0,
113 packet -> options, (struct option_state *)0,
114 lease ? &lease -> scope : &global_scope,
115 class -> submatch, MDL));
116 if (status && data.len) {
117 nc = (struct class *)0;
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) {
127 #if defined (DEBUG_CLASS_MATCHING)
128 log_info ("matches subclass %s.",
129 print_hex_1 (data.len,
130 data.data, 60));
131 #endif
132 data_string_forget (&data, MDL);
133 classify (packet, nc);
134 matched = 1;
135 class_dereference (&nc, MDL);
136 continue;
137 }
138 if (!class -> spawning) {
139 data_string_forget (&data, MDL);
140 continue;
141 }
142 /* XXX Write out the spawned class? */
143 #if defined (DEBUG_CLASS_MATCHING)
144 log_info ("spawning subclass %s.",
145 print_hex_1 (data.len, data.data, 60));
146 #endif
147 status = class_allocate (&nc, MDL);
148 group_reference (&nc -> group,
149 class -> group, MDL);
150 class_reference (&nc -> superclass,
151 class, MDL);
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 *),
159 MDL));
160 if (!nc -> billed_leases) {
161 log_error ("no memory for%s",
162 " billing");
163 data_string_forget
164 (&nc -> hash_string,
165 MDL);
166 class_dereference (&nc, MDL);
167 data_string_forget (&data,
168 MDL);
169 continue;
170 }
171 memset (nc -> billed_leases, 0,
172 (nc -> lease_limit *
173 sizeof (struct lease *)));
174 }
175 data_string_copy (&nc -> hash_string, &data,
176 MDL);
177 data_string_forget (&data, MDL);
178 if (!class -> hash)
179 class_new_hash(&class->hash,
180 SCLASS_HASH_SIZE, MDL);
181 class_hash_add (class -> hash,
182 (const char *)
183 nc -> hash_string.data,
184 nc -> hash_string.len,
185 nc, MDL);
186 classify (packet, nc);
187 class_dereference (&nc, MDL);
188 }
189 }
190 }
191 return matched;
192 }
193
194 void classify (packet, class)
195 struct packet *packet;
196 struct class *class;
197 {
198 if (packet -> class_count < PACKET_MAX_CLASSES)
199 class_reference (&packet -> classes [packet -> class_count++],
200 class, MDL);
201 else
202 log_error ("too many classes match %s",
203 print_hw_addr (packet -> raw -> htype,
204 packet -> raw -> hlen,
205 packet -> raw -> chaddr));
206 }
207
208
209 isc_result_t unlink_class(struct class **class) {
210 struct collection *lp;
211 struct class *cp, *pp;
212
213 for (lp = collections; lp; lp = lp -> next) {
214 for (pp = 0, cp = lp -> classes; cp; pp = cp, cp = cp -> nic)
215 if (cp == *class) {
216 if (pp == 0) {
217 lp->classes = cp->nic;
218 } else {
219 pp->nic = cp->nic;
220 }
221 cp->nic = 0;
222 class_dereference(class, MDL);
223
224 return ISC_R_SUCCESS;
225 }
226 }
227 return ISC_R_NOTFOUND;
228 }
229
230
231 isc_result_t find_class (struct class **class, const char *name,
232 const char *file, int line)
233 {
234 struct collection *lp;
235 struct class *cp;
236
237 for (lp = collections; lp; lp = lp -> next) {
238 for (cp = lp -> classes; cp; cp = cp -> nic)
239 if (cp -> name && !strcmp (name, cp -> name)) {
240 return class_reference (class, cp, file, line);
241 }
242 }
243 return ISC_R_NOTFOUND;
244 }
245
246 /* Removes the billing class from a lease
247 *
248 * Note that because classes can be created and removed dynamically, it is
249 * possible that the class to which a lease was billed has since been deleted.
250 * To cover the case where the lease is the last reference to a deleted class
251 * we remove the lease reference from the class first, then the class from the
252 * lease. To protect ourselves from the reverse situation, where the class is
253 * the last reference to the lease (unlikely), we create a guard reference to
254 * the lease, then remove it at the end.
255 */
256 void unbill_class (lease)
257 struct lease *lease;
258 {
259 int i;
260 struct class* class = lease->billing_class;
261 struct lease* refholder = NULL;
262
263 /* if there's no billing to remove, nothing to do */
264 if (class == NULL) {
265 return;
266 }
267
268 /* Find the lease in the list of the class's billed leases */
269 for (i = 0; i < class->lease_limit; i++) {
270 if (class->billed_leases[i] == lease)
271 break;
272 }
273
274 /* Create guard reference, so class cannot be last reference to lease */
275 lease_reference(&refholder, lease, MDL);
276
277 /* If the class doesn't have the lease, then something is broken
278 * programmatically. We'll log it but skip the lease dereference. */
279 if (i == class->lease_limit) {
280 log_error ("lease %s unbilled with no billing arrangement.",
281 piaddr(lease->ip_addr));
282 } else {
283 /* Remove the lease from the class */
284 lease_dereference(&class->billed_leases[i], MDL);
285 class->leases_consumed--;
286 }
287
288 /* Remove the class from the lease */
289 class_dereference(&lease->billing_class, MDL);
290
291 /* Ditch our guard reference */
292 lease_dereference(&refholder, MDL);
293 }
294
295 int bill_class (lease, class)
296 struct lease *lease;
297 struct class *class;
298 {
299 int i;
300
301 if (lease -> billing_class) {
302 log_error ("lease billed with existing billing arrangement.");
303 unbill_class (lease);
304 }
305
306 if (class -> leases_consumed == class -> lease_limit)
307 return 0;
308
309 for (i = 0; i < class -> lease_limit; i++)
310 if (!class -> billed_leases [i])
311 break;
312
313 if (i == class -> lease_limit) {
314 log_error ("class billing consumption disagrees with leases.");
315 return 0;
316 }
317
318 lease_reference (&class -> billed_leases [i], lease, MDL);
319 class_reference (&lease -> billing_class, class, MDL);
320 class -> leases_consumed++;
321 return 1;
322 }