2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-22 18:07:25 +00:00
isc-dhcp/server/class.c

308 lines
8.4 KiB
C
Raw Normal View History

1998-04-19 23:24:48 +00:00
/* class.c
Handling for client classes. */
/*
* Copyright (c) 2009,2012-2013 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 2004,2007 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1998-2003 by Internet Software Consortium
1998-04-19 23:24:48 +00:00
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
1998-04-19 23:24:48 +00:00
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1998-04-19 23:24:48 +00:00
*
* Internet Systems Consortium, Inc.
* 950 Charter Street
* Redwood City, CA 94063
* <info@isc.org>
* https://www.isc.org/
2000-03-17 04:00:32 +00:00
*
* This software has been written for Internet Systems Consortium
2000-03-17 04:00:32 +00:00
* by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
* To learn more about Internet Systems Consortium, see
* ``https://www.isc.org/''. To learn more about Vixie Enterprises,
2000-03-17 04:00:32 +00:00
* see ``http://www.vix.com''. To learn more about Nominum, Inc., see
* ``http://www.nominum.com''.
1998-04-19 23:24:48 +00:00
*/
#include "dhcpd.h"
struct collection default_collection = {
(struct collection *)0,
"default",
(struct class *)0,
};
struct collection *collections = &default_collection;
struct executable_statement *default_classification_rules;
1998-04-19 23:24:48 +00:00
1998-11-11 07:58:35 +00:00
int have_billing_classes;
1998-04-19 23:24:48 +00:00
/* Build the default classification rule tree. */
void classification_setup ()
{
/* eval ... */
default_classification_rules = (struct executable_statement *)0;
if (!executable_statement_allocate (&default_classification_rules,
MDL))
log_fatal ("Can't allocate check of default collection");
default_classification_rules -> op = eval_statement;
1998-04-19 23:24:48 +00:00
/* check-collection "default" */
if (!expression_allocate (&default_classification_rules -> data.eval,
MDL))
log_fatal ("Can't allocate default check expression");
default_classification_rules -> data.eval -> op = expr_check;
default_classification_rules -> data.eval -> data.check =
&default_collection;
1998-04-19 23:24:48 +00:00
}
void classify_client (packet)
struct packet *packet;
{
execute_statements (NULL, packet, NULL, NULL, packet->options, NULL,
&global_scope, default_classification_rules, NULL);
1998-04-19 23:24:48 +00:00
}
int check_collection (packet, lease, collection)
1998-04-19 23:24:48 +00:00
struct packet *packet;
struct lease *lease;
1998-04-19 23:24:48 +00:00
struct collection *collection;
{
struct class *class, *nc;
struct data_string data;
int matched = 0;
1998-11-06 00:16:22 +00:00
int status;
int ignorep;
int classfound;
1998-04-19 23:24:48 +00:00
for (class = collection -> classes; class; class = class -> nic) {
#if defined (DEBUG_CLASS_MATCHING)
log_info ("checking against class %s...", class -> name);
#endif
1998-11-11 07:58:35 +00:00
memset (&data, 0, sizeof data);
/* If there is a "match if" expression, check it. If
we get a match, and there's no subclass expression,
it's a match. If we get a match and there is a subclass
expression, then we check the submatch. If it's not a
match, that's final - we don't check the submatch. */
if (class -> expr) {
status = (evaluate_boolean_expression_result
(&ignorep, packet, lease,
(struct client_state *)0,
packet -> options, (struct option_state *)0,
lease ? &lease -> scope : &global_scope,
class -> expr));
if (status) {
if (!class -> submatch) {
matched = 1;
#if defined (DEBUG_CLASS_MATCHING)
log_info ("matches class.");
#endif
classify (packet, class);
continue;
}
} else
continue;
}
/* Check to see if the client matches an existing subclass.
If it doesn't, and this is a spawning class, spawn a new
subclass and put the client in it. */
if (class -> submatch) {
status = (evaluate_data_expression
(&data, packet, lease,
(struct client_state *)0,
packet -> options, (struct option_state *)0,
lease ? &lease -> scope : &global_scope,
class -> submatch, MDL));
2000-09-20 09:03:59 +00:00
if (status && data.len) {
nc = (struct class *)0;
classfound = class_hash_lookup (&nc, class -> hash,
(const char *)data.data, data.len, MDL);
#ifdef LDAP_CONFIGURATION
if (!classfound && find_subclass_in_ldap (class, &nc, &data))
classfound = 1;
#endif
if (classfound) {
#if defined (DEBUG_CLASS_MATCHING)
log_info ("matches subclass %s.",
1998-11-11 07:58:35 +00:00
print_hex_1 (data.len,
data.data, 60));
#endif
data_string_forget (&data, MDL);
1998-11-11 07:58:35 +00:00
classify (packet, nc);
matched = 1;
class_dereference (&nc, MDL);
1998-11-11 07:58:35 +00:00
continue;
}
if (!class -> spawning) {
data_string_forget (&data, MDL);
continue;
}
/* XXX Write out the spawned class? */
1998-11-11 07:58:35 +00:00
#if defined (DEBUG_CLASS_MATCHING)
log_info ("spawning subclass %s.",
1998-11-09 02:46:19 +00:00
print_hex_1 (data.len, data.data, 60));
#endif
status = class_allocate (&nc, MDL);
group_reference (&nc -> group,
class -> group, MDL);
class_reference (&nc -> superclass,
class, MDL);
1998-11-11 07:58:35 +00:00
nc -> lease_limit = class -> lease_limit;
nc -> dirty = 1;
if (nc -> lease_limit) {
nc -> billed_leases =
(dmalloc
(nc -> lease_limit *
sizeof (struct lease *),
MDL));
1998-11-11 07:58:35 +00:00
if (!nc -> billed_leases) {
log_error ("no memory for%s",
" billing");
1998-11-11 07:58:35 +00:00
data_string_forget
(&nc -> hash_string,
MDL);
class_dereference (&nc, MDL);
data_string_forget (&data,
MDL);
1998-11-11 07:58:35 +00:00
continue;
}
memset (nc -> billed_leases, 0,
(nc -> lease_limit *
sizeof (struct lease *)));
1998-11-11 07:58:35 +00:00
}
data_string_copy (&nc -> hash_string, &data,
MDL);
data_string_forget (&data, MDL);
1998-11-11 07:58:35 +00:00
if (!class -> hash)
class_new_hash(&class->hash,
SCLASS_HASH_SIZE, MDL);
class_hash_add (class -> hash,
(const char *)
nc -> hash_string.data,
nc -> hash_string.len,
nc, MDL);
1998-11-11 07:58:35 +00:00
classify (packet, nc);
class_dereference (&nc, MDL);
1998-04-19 23:24:48 +00:00
}
}
}
return matched;
}
void classify (packet, class)
struct packet *packet;
struct class *class;
{
if (packet -> class_count < PACKET_MAX_CLASSES)
class_reference (&packet -> classes [packet -> class_count++],
class, MDL);
1998-04-19 23:24:48 +00:00
else
log_error ("too many classes match %s",
1998-04-19 23:24:48 +00:00
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr));
}
2001-06-22 16:47:20 +00:00
isc_result_t unlink_class(struct class **class) {
struct collection *lp;
struct class *cp, *pp;
for (lp = collections; lp; lp = lp -> next) {
for (pp = 0, cp = lp -> classes; cp; pp = cp, cp = cp -> nic)
if (cp == *class) {
if (pp == 0) {
lp->classes = cp->nic;
} else {
pp->nic = cp->nic;
}
cp->nic = 0;
class_dereference(class, MDL);
return ISC_R_SUCCESS;
}
}
return ISC_R_NOTFOUND;
}
isc_result_t find_class (struct class **class, const char *name,
const char *file, int line)
{
struct collection *lp;
struct class *cp;
for (lp = collections; lp; lp = lp -> next) {
for (cp = lp -> classes; cp; cp = cp -> nic)
if (cp -> name && !strcmp (name, cp -> name)) {
return class_reference (class, cp, file, line);
}
}
return ISC_R_NOTFOUND;
}
1998-11-11 07:58:35 +00:00
int unbill_class (lease, class)
struct lease *lease;
struct class *class;
{
int i;
for (i = 0; i < class -> lease_limit; i++)
if (class -> billed_leases [i] == lease)
break;
if (i == class -> lease_limit) {
log_error ("lease %s unbilled with no billing arrangement.",
1998-11-11 07:58:35 +00:00
piaddr (lease -> ip_addr));
return 0;
}
class_dereference (&lease -> billing_class, MDL);
lease_dereference (&class -> billed_leases [i], MDL);
1998-11-11 07:58:35 +00:00
class -> leases_consumed--;
return 1;
}
int bill_class (lease, class)
struct lease *lease;
struct class *class;
{
int i;
if (lease -> billing_class) {
log_error ("lease billed with existing billing arrangement.");
unbill_class (lease, lease -> billing_class);
}
1998-11-11 07:58:35 +00:00
if (class -> leases_consumed == class -> lease_limit)
return 0;
for (i = 0; i < class -> lease_limit; i++)
if (!class -> billed_leases [i])
break;
if (i == class -> lease_limit) {
log_error ("class billing consumption disagrees with leases.");
1998-11-11 07:58:35 +00:00
return 0;
}
lease_reference (&class -> billed_leases [i], lease, MDL);
class_reference (&lease -> billing_class, class, MDL);
1998-11-11 07:58:35 +00:00
class -> leases_consumed++;
return 1;
}