3 Handling for client classes. */
6 * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1998-2003 by Internet Software Consortium
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/.
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.
21 * Internet Systems Consortium, Inc.
23 * Redwood City, CA 94063
25 * https://www.isc.org/
31 struct executable_statement
*default_classification_rules
;
33 int have_billing_classes
;
35 /* Build the default classification rule tree. */
37 void classification_setup ()
40 default_classification_rules
= (struct executable_statement
*)0;
41 if (!executable_statement_allocate (&default_classification_rules
,
43 log_fatal ("Can't allocate check of default collection");
44 default_classification_rules
-> op
= eval_statement
;
46 /* check-collection "default" */
47 if (!expression_allocate (&default_classification_rules
-> data
.eval
,
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
=
55 void classify_client (packet
)
56 struct packet
*packet
;
58 execute_statements (NULL
, packet
, NULL
, NULL
, packet
->options
, NULL
,
59 &global_scope
, default_classification_rules
, NULL
);
62 int check_collection (packet
, lease
, collection
)
63 struct packet
*packet
;
65 struct collection
*collection
;
67 struct class *class, *nc
;
68 struct data_string data
;
74 for (class = collection
-> classes
; class; class = class -> nic
) {
75 #if defined (DEBUG_CLASS_MATCHING)
76 log_info ("checking against class %s...", class -> name
);
78 memset (&data
, 0, sizeof data
);
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. */
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
,
94 if (!class -> submatch
) {
96 #if defined (DEBUG_CLASS_MATCHING)
97 log_info ("matches class.");
99 classify (packet
, class);
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
);
121 #ifdef LDAP_CONFIGURATION
122 if (!classfound
&& find_subclass_in_ldap (class, &nc
, &data
))
127 #if defined (DEBUG_CLASS_MATCHING)
128 log_info ("matches subclass %s.",
129 print_hex_1 (data
.len
,
132 data_string_forget (&data
, MDL
);
133 classify (packet
, nc
);
135 class_dereference (&nc
, MDL
);
138 if (!class -> spawning
) {
139 data_string_forget (&data
, MDL
);
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));
147 status
= class_allocate (&nc
, MDL
);
148 group_reference (&nc
-> group
,
149 class -> group
, MDL
);
150 class_reference (&nc
-> superclass
,
152 nc
-> lease_limit
= class -> lease_limit
;
154 if (nc
-> lease_limit
) {
155 nc
-> billed_leases
=
158 sizeof (struct lease
*),
160 if (!nc
-> billed_leases
) {
161 log_error ("no memory for%s",
166 class_dereference (&nc
, MDL
);
167 data_string_forget (&data
,
171 memset (nc
-> billed_leases
, 0,
173 sizeof (struct lease
*)));
175 data_string_copy (&nc
-> hash_string
, &data
,
177 data_string_forget (&data
, MDL
);
179 class_new_hash(&class->hash
,
180 SCLASS_HASH_SIZE
, MDL
);
181 class_hash_add (class -> hash
,
183 nc
-> hash_string
.data
,
184 nc
-> hash_string
.len
,
186 classify (packet
, nc
);
187 class_dereference (&nc
, MDL
);
194 void classify (packet
, class)
195 struct packet
*packet
;
198 if (packet
-> class_count
< PACKET_MAX_CLASSES
)
199 class_reference (&packet
-> classes
[packet
-> class_count
++],
202 log_error ("too many classes match %s",
203 print_hw_addr (packet
-> raw
-> htype
,
204 packet
-> raw
-> hlen
,
205 packet
-> raw
-> chaddr
));
209 isc_result_t
unlink_class(struct class **class) {
210 struct collection
*lp
;
211 struct class *cp
, *pp
;
213 for (lp
= collections
; lp
; lp
= lp
-> next
) {
214 for (pp
= 0, cp
= lp
-> classes
; cp
; pp
= cp
, cp
= cp
-> nic
)
217 lp
->classes
= cp
->nic
;
222 class_dereference(class, MDL
);
224 return ISC_R_SUCCESS
;
227 return ISC_R_NOTFOUND
;
231 isc_result_t
find_class (struct class **class, const char *name
,
232 const char *file
, int line
)
234 struct collection
*lp
;
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
);
243 return ISC_R_NOTFOUND
;
246 /* Removes the billing class from a lease
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.
256 void unbill_class (lease
)
260 struct class* class = lease
->billing_class
;
261 struct lease
* refholder
= NULL
;
263 /* if there's no billing to remove, nothing to do */
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
)
274 /* Create guard reference, so class cannot be last reference to lease */
275 lease_reference(&refholder
, lease
, MDL
);
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
));
283 /* Remove the lease from the class */
284 lease_dereference(&class->billed_leases
[i
], MDL
);
285 class->leases_consumed
--;
288 /* Remove the class from the lease */
289 class_dereference(&lease
->billing_class
, MDL
);
291 /* Ditch our guard reference */
292 lease_dereference(&refholder
, MDL
);
295 int bill_class (lease
, class)
301 if (lease
-> billing_class
) {
302 log_error ("lease billed with existing billing arrangement.");
303 unbill_class (lease
);
306 if (class -> leases_consumed
== class -> lease_limit
)
309 for (i
= 0; i
< class -> lease_limit
; i
++)
310 if (!class -> billed_leases
[i
])
313 if (i
== class -> lease_limit
) {
314 log_error ("class billing consumption disagrees with leases.");
318 lease_reference (&class -> billed_leases
[i
], lease
, MDL
);
319 class_reference (&lease
-> billing_class
, class, MDL
);
320 class -> leases_consumed
++;