server/class.c

Go to the documentation of this file.
00001 /* class.c
00002 
00003    Handling for client classes. */
00004 
00005 /*
00006  * Copyright (c) 2009,2012-2014 by Internet Systems Consortium, Inc. ("ISC")
00007  * Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
00008  * Copyright (c) 1998-2003 by Internet Software Consortium
00009  *
00010  * Permission to use, copy, modify, and distribute this software for any
00011  * purpose with or without fee is hereby granted, provided that the above
00012  * copyright notice and this permission notice appear in all copies.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00015  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00016  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00017  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00018  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00019  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00020  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00021  *
00022  *   Internet Systems Consortium, Inc.
00023  *   950 Charter Street
00024  *   Redwood City, CA 94063
00025  *   <info@isc.org>
00026  *   https://www.isc.org/
00027  *
00028  */
00029 
00030 #include "dhcpd.h"
00031 
00032 struct collection default_collection = {
00033         (struct collection *)0,
00034         "default",
00035         (struct class *)0,
00036 };
00037 
00038 struct collection *collections = &default_collection;
00039 struct executable_statement *default_classification_rules;
00040 
00041 int have_billing_classes;
00042 
00043 /* Build the default classification rule tree. */
00044 
00045 void classification_setup ()
00046 {
00047         /* eval ... */
00048         default_classification_rules = (struct executable_statement *)0;
00049         if (!executable_statement_allocate (&default_classification_rules,
00050                                             MDL))
00051                 log_fatal ("Can't allocate check of default collection");
00052         default_classification_rules -> op = eval_statement;
00053 
00054         /* check-collection "default" */
00055         if (!expression_allocate (&default_classification_rules -> data.eval,
00056                                   MDL))
00057                 log_fatal ("Can't allocate default check expression");
00058         default_classification_rules -> data.eval -> op = expr_check;
00059         default_classification_rules -> data.eval -> data.check =
00060                 &default_collection;
00061 }
00062 
00063 void classify_client (packet)
00064         struct packet *packet;
00065 {
00066         execute_statements (NULL, packet, NULL, NULL, packet->options, NULL,
00067                             &global_scope, default_classification_rules, NULL);
00068 }
00069 
00070 int check_collection (packet, lease, collection)
00071         struct packet *packet;
00072         struct lease *lease;
00073         struct collection *collection;
00074 {
00075         struct class *class, *nc;
00076         struct data_string data;
00077         int matched = 0;
00078         int status;
00079         int ignorep;
00080         int classfound;
00081 
00082         for (class = collection -> classes; class; class = class -> nic) {
00083 #if defined (DEBUG_CLASS_MATCHING)
00084                 log_info ("checking against class %s...", class -> name);
00085 #endif
00086                 memset (&data, 0, sizeof data);
00087 
00088                 /* If there is a "match if" expression, check it.   If
00089                    we get a match, and there's no subclass expression,
00090                    it's a match.   If we get a match and there is a subclass
00091                    expression, then we check the submatch.   If it's not a
00092                    match, that's final - we don't check the submatch. */
00093 
00094                 if (class -> expr) {
00095                         status = (evaluate_boolean_expression_result
00096                                   (&ignorep, packet, lease,
00097                                    (struct client_state *)0,
00098                                    packet -> options, (struct option_state *)0,
00099                                    lease ? &lease -> scope : &global_scope,
00100                                    class -> expr));
00101                         if (status) {
00102                                 if (!class -> submatch) {
00103                                         matched = 1;
00104 #if defined (DEBUG_CLASS_MATCHING)
00105                                         log_info ("matches class.");
00106 #endif
00107                                         classify (packet, class);
00108                                         continue;
00109                                 }
00110                         } else
00111                                 continue;
00112                 }
00113 
00114                 /* Check to see if the client matches an existing subclass.
00115                    If it doesn't, and this is a spawning class, spawn a new
00116                    subclass and put the client in it. */
00117                 if (class -> submatch) {
00118                         status = (evaluate_data_expression
00119                                   (&data, packet, lease,
00120                                    (struct client_state *)0,
00121                                    packet -> options, (struct option_state *)0,
00122                                    lease ? &lease -> scope : &global_scope,
00123                                    class -> submatch, MDL));
00124                         if (status && data.len) {
00125                                 nc = (struct class *)0;
00126                                 classfound = class_hash_lookup (&nc, class -> hash,
00127                                         (const char *)data.data, data.len, MDL);
00128 
00129 #ifdef LDAP_CONFIGURATION
00130                                 if (!classfound && find_subclass_in_ldap (class, &nc, &data))
00131                                         classfound = 1;
00132 #endif
00133 
00134                                 if (classfound) {
00135 #if defined (DEBUG_CLASS_MATCHING)
00136                                         log_info ("matches subclass %s.",
00137                                               print_hex_1 (data.len,
00138                                                            data.data, 60));
00139 #endif
00140                                         data_string_forget (&data, MDL);
00141                                         classify (packet, nc);
00142                                         matched = 1;
00143                                         class_dereference (&nc, MDL);
00144                                         continue;
00145                                 }
00146                                 if (!class -> spawning) {
00147                                         data_string_forget (&data, MDL);
00148                                         continue;
00149                                 }
00150                                 /* XXX Write out the spawned class? */
00151 #if defined (DEBUG_CLASS_MATCHING)
00152                                 log_info ("spawning subclass %s.",
00153                                       print_hex_1 (data.len, data.data, 60));
00154 #endif
00155                                 status = class_allocate (&nc, MDL);
00156                                 group_reference (&nc -> group,
00157                                                  class -> group, MDL);
00158                                 class_reference (&nc -> superclass,
00159                                                  class, MDL);
00160                                 nc -> lease_limit = class -> lease_limit;
00161                                 nc -> dirty = 1;
00162                                 if (nc -> lease_limit) {
00163                                         nc -> billed_leases =
00164                                                 (dmalloc
00165                                                  (nc -> lease_limit *
00166                                                   sizeof (struct lease *),
00167                                                   MDL));
00168                                         if (!nc -> billed_leases) {
00169                                                 log_error ("no memory for%s",
00170                                                            " billing");
00171                                                 data_string_forget
00172                                                         (&nc -> hash_string,
00173                                                          MDL);
00174                                                 class_dereference (&nc, MDL);
00175                                                 data_string_forget (&data,
00176                                                                     MDL);
00177                                                 continue;
00178                                         }
00179                                         memset (nc -> billed_leases, 0,
00180                                                 (nc -> lease_limit *
00181                                                  sizeof (struct lease *)));
00182                                 }
00183                                 data_string_copy (&nc -> hash_string, &data,
00184                                                   MDL);
00185                                 data_string_forget (&data, MDL);
00186                                 if (!class -> hash)
00187                                     class_new_hash(&class->hash,
00188                                                    SCLASS_HASH_SIZE, MDL);
00189                                 class_hash_add (class -> hash,
00190                                                 (const char *)
00191                                                 nc -> hash_string.data,
00192                                                 nc -> hash_string.len,
00193                                                 nc, MDL);
00194                                 classify (packet, nc);
00195                                 class_dereference (&nc, MDL);
00196                         }
00197                 }
00198         }
00199         return matched;
00200 }
00201 
00202 void classify (packet, class)
00203         struct packet *packet;
00204         struct class *class;
00205 {
00206         if (packet -> class_count < PACKET_MAX_CLASSES)
00207                 class_reference (&packet -> classes [packet -> class_count++],
00208                                  class, MDL);
00209         else
00210                 log_error ("too many classes match %s",
00211                       print_hw_addr (packet -> raw -> htype,
00212                                      packet -> raw -> hlen,
00213                                      packet -> raw -> chaddr));
00214 }
00215 
00216 
00217 isc_result_t unlink_class(struct class **class) {
00218         struct collection *lp;
00219         struct class *cp, *pp;
00220 
00221         for (lp = collections; lp; lp = lp -> next) {
00222                 for (pp = 0, cp = lp -> classes; cp; pp = cp, cp = cp -> nic)
00223                         if (cp == *class) {
00224                                 if (pp == 0) {
00225                                         lp->classes = cp->nic;
00226                                 } else {
00227                                         pp->nic = cp->nic;
00228                                 }
00229                                 cp->nic = 0;
00230                                 class_dereference(class, MDL);
00231 
00232                                 return ISC_R_SUCCESS;
00233                         }
00234         }
00235         return ISC_R_NOTFOUND;
00236 }
00237 
00238         
00239 isc_result_t find_class (struct class **class, const char *name,
00240                          const char *file, int line)
00241 {
00242         struct collection *lp;
00243         struct class *cp;
00244 
00245         for (lp = collections; lp; lp = lp -> next) {
00246                 for (cp = lp -> classes; cp; cp = cp -> nic)
00247                         if (cp -> name && !strcmp (name, cp -> name)) {
00248                                 return class_reference (class, cp, file, line);
00249                         }
00250         }
00251         return ISC_R_NOTFOUND;
00252 }
00253 
00254 int unbill_class (lease, class)
00255         struct lease *lease;
00256         struct class *class;
00257 {
00258         int i;
00259 
00260         for (i = 0; i < class -> lease_limit; i++)
00261                 if (class -> billed_leases [i] == lease)
00262                         break;
00263         if (i == class -> lease_limit) {
00264                 log_error ("lease %s unbilled with no billing arrangement.",
00265                       piaddr (lease -> ip_addr));
00266                 return 0;
00267         }
00268         class_dereference (&lease -> billing_class, MDL);
00269         lease_dereference (&class -> billed_leases [i], MDL);
00270         class -> leases_consumed--;
00271         return 1;
00272 }
00273 
00274 int bill_class (lease, class)
00275         struct lease *lease;
00276         struct class *class;
00277 {
00278         int i;
00279 
00280         if (lease -> billing_class) {
00281                 log_error ("lease billed with existing billing arrangement.");
00282                 unbill_class (lease, lease -> billing_class);
00283         }
00284 
00285         if (class -> leases_consumed == class -> lease_limit)
00286                 return 0;
00287 
00288         for (i = 0; i < class -> lease_limit; i++)
00289                 if (!class -> billed_leases [i])
00290                         break;
00291 
00292         if (i == class -> lease_limit) {
00293                 log_error ("class billing consumption disagrees with leases.");
00294                 return 0;
00295         }
00296 
00297         lease_reference (&class -> billed_leases [i], lease, MDL);
00298         class_reference (&lease -> billing_class, class, MDL);
00299         class -> leases_consumed++;
00300         return 1;
00301 }

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1