ISC DHCP  4.3.3
A reference DHCPv4 and DHCPv6 implementation
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
class.c
Go to the documentation of this file.
1 /* class.c
2 
3  Handling for client classes. */
4 
5 /*
6  * Copyright (c) 2009,2012-2015 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
8  * Copyright (c) 1998-2003 by Internet Software Consortium
9  *
10  * Permission to use, copy, modify, and distribute this software for any
11  * purpose with or without fee is hereby granted, provided that the above
12  * copyright notice and this permission notice appear in all copies.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  *
22  * Internet Systems Consortium, Inc.
23  * 950 Charter Street
24  * Redwood City, CA 94063
25  * <info@isc.org>
26  * https://www.isc.org/
27  *
28  */
29 
30 #include "dhcpd.h"
31 
33  (struct collection *)0,
34  "default",
35  (struct class *)0,
36 };
37 
40 
42 
43 /* Build the default classification rule tree. */
44 
46 {
47  /* eval ... */
48  default_classification_rules = (struct executable_statement *)0;
49  if (!executable_statement_allocate (&default_classification_rules,
50  MDL))
51  log_fatal ("Can't allocate check of default collection");
52  default_classification_rules -> op = eval_statement;
53 
54  /* check-collection "default" */
55  if (!expression_allocate (&default_classification_rules -> data.eval,
56  MDL))
57  log_fatal ("Can't allocate default check expression");
58  default_classification_rules -> data.eval -> op = expr_check;
59  default_classification_rules -> data.eval -> data.check =
61 }
62 
64  struct packet *packet;
65 {
66  execute_statements (NULL, packet, NULL, NULL, packet->options, NULL,
67  &global_scope, default_classification_rules, NULL);
68 }
69 
71  struct packet *packet;
72  struct lease *lease;
73  struct collection *collection;
74 {
75  struct class *class, *nc;
76  struct data_string data;
77  int matched = 0;
78  int status;
79  int ignorep;
80  int classfound;
81 
82  for (class = collection -> classes; class; class = class -> nic) {
83 #if defined (DEBUG_CLASS_MATCHING)
84  log_info ("checking against class %s...", class -> name);
85 #endif
86  memset (&data, 0, sizeof data);
87 
88  /* If there is a "match if" expression, check it. If
89  we get a match, and there's no subclass expression,
90  it's a match. If we get a match and there is a subclass
91  expression, then we check the submatch. If it's not a
92  match, that's final - we don't check the submatch. */
93 
94  if (class -> expr) {
96  (&ignorep, packet, lease,
97  (struct client_state *)0,
98  packet -> options, (struct option_state *)0,
99  lease ? &lease -> scope : &global_scope,
100  class -> expr));
101  if (status) {
102  if (!class -> submatch) {
103  matched = 1;
104 #if defined (DEBUG_CLASS_MATCHING)
105  log_info ("matches class.");
106 #endif
107  classify (packet, class);
108  continue;
109  }
110  } else
111  continue;
112  }
113 
114  /* Check to see if the client matches an existing subclass.
115  If it doesn't, and this is a spawning class, spawn a new
116  subclass and put the client in it. */
117  if (class -> submatch) {
118  status = (evaluate_data_expression
119  (&data, packet, lease,
120  (struct client_state *)0,
121  packet -> options, (struct option_state *)0,
122  lease ? &lease -> scope : &global_scope,
123  class -> submatch, MDL));
124  if (status && data.len) {
125  nc = (struct class *)0;
126  classfound = class_hash_lookup (&nc, class -> hash,
127  (const char *)data.data, data.len, MDL);
128 
129 #ifdef LDAP_CONFIGURATION
130  if (!classfound && find_subclass_in_ldap (class, &nc, &data))
131  classfound = 1;
132 #endif
133 
134  if (classfound) {
135 #if defined (DEBUG_CLASS_MATCHING)
136  log_info ("matches subclass %s.",
137  print_hex_1 (data.len,
138  data.data, 60));
139 #endif
140  data_string_forget (&data, MDL);
141  classify (packet, nc);
142  matched = 1;
143  class_dereference (&nc, MDL);
144  continue;
145  }
146  if (!class -> spawning) {
147  data_string_forget (&data, MDL);
148  continue;
149  }
150  /* XXX Write out the spawned class? */
151 #if defined (DEBUG_CLASS_MATCHING)
152  log_info ("spawning subclass %s.",
153  print_hex_1 (data.len, data.data, 60));
154 #endif
155  status = class_allocate (&nc, MDL);
156  group_reference (&nc -> group,
157  class -> group, MDL);
158  class_reference (&nc -> superclass,
159  class, MDL);
160  nc -> lease_limit = class -> lease_limit;
161  nc -> dirty = 1;
162  if (nc -> lease_limit) {
163  nc -> billed_leases =
164  (dmalloc
165  (nc -> lease_limit *
166  sizeof (struct lease *),
167  MDL));
168  if (!nc -> billed_leases) {
169  log_error ("no memory for%s",
170  " billing");
172  (&nc -> hash_string,
173  MDL);
174  class_dereference (&nc, MDL);
175  data_string_forget (&data,
176  MDL);
177  continue;
178  }
179  memset (nc -> billed_leases, 0,
180  (nc -> lease_limit *
181  sizeof (struct lease *)));
182  }
183  data_string_copy (&nc -> hash_string, &data,
184  MDL);
185  data_string_forget (&data, MDL);
186  if (!class -> hash)
187  class_new_hash(&class->hash,
189  class_hash_add (class -> hash,
190  (const char *)
191  nc -> hash_string.data,
192  nc -> hash_string.len,
193  nc, MDL);
194  classify (packet, nc);
195  class_dereference (&nc, MDL);
196  }
197  }
198  }
199  return matched;
200 }
201 
202 void classify (packet, class)
203  struct packet *packet;
204  struct class *class;
205 {
206  if (packet -> class_count < PACKET_MAX_CLASSES)
207  class_reference (&packet -> classes [packet -> class_count++],
208  class, MDL);
209  else
210  log_error ("too many classes match %s",
211  print_hw_addr (packet -> raw -> htype,
212  packet -> raw -> hlen,
213  packet -> raw -> chaddr));
214 }
215 
216 
217 isc_result_t unlink_class(struct class **class) {
218  struct collection *lp;
219  struct class *cp, *pp;
220 
221  for (lp = collections; lp; lp = lp -> next) {
222  for (pp = 0, cp = lp -> classes; cp; pp = cp, cp = cp -> nic)
223  if (cp == *class) {
224  if (pp == 0) {
225  lp->classes = cp->nic;
226  } else {
227  pp->nic = cp->nic;
228  }
229  cp->nic = 0;
230  class_dereference(class, MDL);
231 
232  return ISC_R_SUCCESS;
233  }
234  }
235  return ISC_R_NOTFOUND;
236 }
237 
238 
239 isc_result_t find_class (struct class **class, const char *name,
240  const char *file, int line)
241 {
242  struct collection *lp;
243  struct class *cp;
244 
245  for (lp = collections; lp; lp = lp -> next) {
246  for (cp = lp -> classes; cp; cp = cp -> nic)
247  if (cp -> name && !strcmp (name, cp -> name)) {
248  return class_reference (class, cp, file, line);
249  }
250  }
251  return ISC_R_NOTFOUND;
252 }
253 
254 /* Removes the billing class from a lease
255  *
256  * Note that because classes can be created and removed dynamically, it is
257  * possible that the class to which a lease was billed has since been deleted.
258  * To cover the case where the lease is the last reference to a deleted class
259  * we remove the lease reference from the class first, then the class from the
260  * lease. To protect ourselves from the reverse situation, where the class is
261  * the last reference to the lease (unlikely), we create a guard reference to
262  * the lease, then remove it at the end.
263  */
265  struct lease *lease;
266 {
267  int i;
268  struct class* class = lease->billing_class;
269  struct lease* refholder = NULL;
270 
271  /* if there's no billing to remove, nothing to do */
272  if (class == NULL) {
273  return;
274  }
275 
276  /* Find the lease in the list of the class's billed leases */
277  for (i = 0; i < class->lease_limit; i++) {
278  if (class->billed_leases[i] == lease)
279  break;
280  }
281 
282  /* Create guard reference, so class cannot be last reference to lease */
283  lease_reference(&refholder, lease, MDL);
284 
285  /* If the class doesn't have the lease, then something is broken
286  * programmatically. We'll log it but skip the lease dereference. */
287  if (i == class->lease_limit) {
288  log_error ("lease %s unbilled with no billing arrangement.",
289  piaddr(lease->ip_addr));
290  } else {
291  /* Remove the lease from the class */
292  lease_dereference(&class->billed_leases[i], MDL);
293  class->leases_consumed--;
294  }
295 
296  /* Remove the class from the lease */
297  class_dereference(&lease->billing_class, MDL);
298 
299  /* Ditch our guard reference */
300  lease_dereference(&refholder, MDL);
301 }
302 
303 int bill_class (lease, class)
304  struct lease *lease;
305  struct class *class;
306 {
307  int i;
308 
309  if (lease -> billing_class) {
310  log_error ("lease billed with existing billing arrangement.");
311  unbill_class (lease);
312  }
313 
314  if (class -> leases_consumed == class -> lease_limit)
315  return 0;
316 
317  for (i = 0; i < class -> lease_limit; i++)
318  if (!class -> billed_leases [i])
319  break;
320 
321  if (i == class -> lease_limit) {
322  log_error ("class billing consumption disagrees with leases.");
323  return 0;
324  }
325 
326  lease_reference (&class -> billed_leases [i], lease, MDL);
327  class_reference (&lease -> billing_class, class, MDL);
328  class -> leases_consumed++;
329  return 1;
330 }
int executable_statement_allocate(struct executable_statement **ptr, const char *file, int line)
Definition: alloc.c:959
struct class * nic
Definition: dhcpd.h:1060
const char int line
Definition: dhcpd.h:3676
struct binding_scope * global_scope
Definition: tree.c:39
Definition: dhcpd.h:550
unsigned len
Definition: tree.h:80
const char * piaddr(const struct iaddr addr)
Definition: inet.c:581
void unbill_class(struct lease *lease)
Definition: class.c:264
void * dmalloc(unsigned, const char *, int)
Definition: alloc.c:56
struct class * superclass
Definition: dhcpd.h:1061
int expression_allocate(struct expression **cptr, const char *file, int line)
Definition: alloc.c:427
int execute_statements(struct binding_value **result, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *out_options, struct binding_scope **scope, struct executable_statement *statements, struct on_star *on_star)
Definition: execute.c:35
#define MDL
Definition: omapip.h:568
#define print_hex_1(len, data, limit)
Definition: dhcpd.h:2533
class_hash_t * hash
Definition: dhcpd.h:1074
enum executable_statement::statement_op op
int group_reference(struct group **ptr, struct group *bp, const char *file, int line)
Definition: alloc.c:178
void data_string_forget(struct data_string *data, const char *file, int line)
Definition: alloc.c:1340
struct class * billing_class
Definition: dhcpd.h:569
struct data_string hash_string
Definition: dhcpd.h:1075
#define SCLASS_HASH_SIZE
Definition: dhcpd.h:203
int log_error(const char *,...) __attribute__((__format__(__printf__
int check_collection(struct packet *packet, struct lease *lease, struct collection *collection)
Definition: class.c:70
struct executable_statement * default_classification_rules
Definition: class.c:39
void classify(struct packet *packet, struct class *class)
Definition: class.c:202
char * name
Definition: dhcpd.h:1062
void log_fatal(const char *,...) __attribute__((__format__(__printf__
int evaluate_boolean_expression_result(int *ignorep, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct expression *expr)
Definition: tree.c:2769
void classify_client(struct packet *packet)
Definition: class.c:63
struct expression * expr
Definition: dhcpd.h:1078
Definition: dhcpd.h:405
struct expression * submatch
Definition: dhcpd.h:1082
int lease_limit
Definition: dhcpd.h:1065
int int log_info(const char *,...) __attribute__((__format__(__printf__
int evaluate_data_expression(struct data_string *result, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct expression *expr, const char *file, int line)
Definition: tree.c:1115
struct class * classes
Definition: dhcpd.h:1048
union executable_statement::@7 data
struct lease ** billed_leases
Definition: dhcpd.h:1067
isc_result_t find_class(struct class **class, const char *name, const char *file, int line)
Definition: class.c:239
Definition: dhcpd.h:918
int have_billing_classes
Definition: class.c:41
struct collection * collections
Definition: class.c:38
void classification_setup()
Definition: class.c:45
const char * file
Definition: dhcpd.h:3676
Definition: dhcpd.h:1058
const unsigned char * data
Definition: tree.h:79
void data_string_copy(struct data_string *dest, const struct data_string *src, const char *file, int line)
Definition: alloc.c:1324
struct collection default_collection
Definition: class.c:32
isc_result_t unlink_class(struct class **class)
Definition: class.c:217
int dirty
Definition: dhcpd.h:1071
#define PACKET_MAX_CLASSES
Definition: dhcpd.h:446
int spawning
Definition: dhcpd.h:1083
int bill_class(struct lease *lease, struct class *class)
Definition: class.c:303