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