1998-04-19 23:24:48 +00:00
|
|
|
/* class.c
|
|
|
|
|
|
|
|
Handling for client classes. */
|
|
|
|
|
|
|
|
/*
|
1999-03-16 05:50:46 +00:00
|
|
|
* Copyright (c) 1996-1999 Internet Software Consortium.
|
|
|
|
* Use is subject to license terms which appear in the file named
|
|
|
|
* ISC-LICENSE that should have accompanied this file when you
|
|
|
|
* received it. If a file named ISC-LICENSE did not accompany this
|
|
|
|
* file, or you are not sure the one you have is correct, you may
|
|
|
|
* obtain an applicable copy of the license at:
|
1998-04-19 23:24:48 +00:00
|
|
|
*
|
1999-03-16 05:50:46 +00:00
|
|
|
* http://www.isc.org/isc-license-1.0.html.
|
1998-04-19 23:24:48 +00:00
|
|
|
*
|
1999-03-16 05:50:46 +00:00
|
|
|
* This file is part of the ISC DHCP distribution. The documentation
|
|
|
|
* associated with this file is listed in the file DOCUMENTATION,
|
|
|
|
* included in the top-level directory of this release.
|
1998-04-19 23:24:48 +00:00
|
|
|
*
|
1999-03-16 05:50:46 +00:00
|
|
|
* Support and other services are available for ISC products - see
|
|
|
|
* http://www.isc.org for more information.
|
1998-04-19 23:24:48 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
static char copyright[] =
|
1999-10-21 03:09:13 +00:00
|
|
|
"$Id: class.c,v 1.15 1999/10/21 03:09:13 mellon Exp $ Copyright (c) 1998 The Internet Software Consortium. All rights reserved.\n";
|
1998-04-19 23:24:48 +00:00
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
#include "dhcpd.h"
|
|
|
|
|
|
|
|
struct collection default_collection = {
|
|
|
|
(struct collection *)0,
|
|
|
|
"default",
|
|
|
|
(struct class *)0,
|
|
|
|
};
|
|
|
|
|
1998-04-20 18:03:33 +00:00
|
|
|
struct collection *collections = &default_collection;
|
1998-06-25 03:42:18 +00:00
|
|
|
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 ()
|
|
|
|
{
|
1998-06-25 03:42:18 +00:00
|
|
|
struct executable_statement *rules;
|
1998-04-19 23:24:48 +00:00
|
|
|
|
|
|
|
/* eval ... */
|
1999-07-31 18:09:51 +00:00
|
|
|
rules = (struct executable_statement *)0;
|
|
|
|
if (!executable_statement_allocate (&rules,
|
|
|
|
"default collection check rule"))
|
1999-02-24 17:56:53 +00:00
|
|
|
log_fatal ("Can't allocate check of default collection");
|
1998-06-25 03:42:18 +00:00
|
|
|
rules -> op = eval_statement;
|
1998-04-19 23:24:48 +00:00
|
|
|
|
1999-07-31 18:09:51 +00:00
|
|
|
/* check-collection "default" */
|
|
|
|
if (!expression_allocate (&rules -> data.eval,
|
|
|
|
"default check expression"))
|
|
|
|
log_fatal ("Can't allocate default check expression");
|
|
|
|
rules -> data.eval -> op = expr_check;
|
|
|
|
rules -> data.eval -> data.check = &default_collection;
|
|
|
|
|
1998-04-20 18:03:33 +00:00
|
|
|
default_classification_rules = rules;
|
1998-04-19 23:24:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void classify_client (packet)
|
|
|
|
struct packet *packet;
|
|
|
|
{
|
1999-07-02 20:58:48 +00:00
|
|
|
execute_statements (packet, (struct lease *)0, packet -> options,
|
1998-11-06 00:16:22 +00:00
|
|
|
(struct option_state *)0,
|
1998-06-25 03:42:18 +00:00
|
|
|
default_classification_rules);
|
1998-04-19 23:24:48 +00:00
|
|
|
}
|
|
|
|
|
1999-07-02 20:58:48 +00:00
|
|
|
int check_collection (packet, lease, collection)
|
1998-04-19 23:24:48 +00:00
|
|
|
struct packet *packet;
|
1999-07-02 20:58:48 +00:00
|
|
|
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;
|
1999-10-21 03:09:13 +00:00
|
|
|
int ignorep;
|
1998-04-19 23:24:48 +00:00
|
|
|
|
|
|
|
for (class = collection -> classes; class; class = class -> nic) {
|
1998-11-06 03:25:45 +00:00
|
|
|
#if defined (DEBUG_CLASS_MATCHING)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("checking against class %s...", class -> name);
|
1998-11-06 03:25:45 +00:00
|
|
|
#endif
|
1998-11-11 07:58:35 +00:00
|
|
|
memset (&data, 0, sizeof data);
|
|
|
|
/* If a class is for billing, don't put the client in the
|
|
|
|
class if we've already billed it to a different class. */
|
1999-03-16 00:56:02 +00:00
|
|
|
if (class -> submatch) {
|
1999-07-31 18:09:51 +00:00
|
|
|
status = (evaluate_data_expression
|
|
|
|
(&data, packet, lease,
|
|
|
|
packet -> options, (struct option_state *)0,
|
|
|
|
class -> submatch));
|
1998-11-11 07:58:35 +00:00
|
|
|
if (status) {
|
|
|
|
if ((nc = ((struct class *)
|
|
|
|
hash_lookup (class -> hash,
|
|
|
|
data.data,
|
|
|
|
data.len)))) {
|
1998-11-06 03:25:45 +00:00
|
|
|
#if defined (DEBUG_CLASS_MATCHING)
|
1999-02-24 17:56:53 +00:00
|
|
|
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, "check_collection");
|
|
|
|
classify (packet, nc);
|
|
|
|
matched = 1;
|
|
|
|
continue;
|
|
|
|
}
|
1999-03-16 00:56:02 +00:00
|
|
|
if (!class -> spawning)
|
|
|
|
continue;
|
1998-11-11 07:58:35 +00:00
|
|
|
#if defined (DEBUG_CLASS_MATCHING)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("spawning subclass %s.",
|
1998-11-09 02:46:19 +00:00
|
|
|
print_hex_1 (data.len, data.data, 60));
|
1998-11-06 03:25:45 +00:00
|
|
|
#endif
|
1998-11-11 07:58:35 +00:00
|
|
|
nc = (struct class *)
|
|
|
|
dmalloc (sizeof (struct class),
|
|
|
|
"class spawn");
|
|
|
|
memset (nc, 0, sizeof *nc);
|
|
|
|
nc -> group = class -> group;
|
|
|
|
nc -> superclass = class;
|
|
|
|
nc -> lease_limit = class -> lease_limit;
|
|
|
|
nc -> dirty = 1;
|
|
|
|
if (nc -> lease_limit) {
|
|
|
|
nc -> billed_leases =
|
|
|
|
(dmalloc
|
|
|
|
(nc -> lease_limit *
|
|
|
|
sizeof (struct lease *),
|
|
|
|
"check_collection"));
|
|
|
|
if (!nc -> billed_leases) {
|
1999-04-05 16:34:33 +00:00
|
|
|
log_error ("no memory for%s",
|
|
|
|
" billing");
|
1998-11-11 07:58:35 +00:00
|
|
|
data_string_forget
|
|
|
|
(&nc -> hash_string,
|
|
|
|
"check_collection");
|
|
|
|
dfree (nc, "check_collection");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
memset (nc -> billed_leases, 0,
|
|
|
|
(nc -> lease_limit *
|
|
|
|
sizeof nc -> billed_leases));
|
|
|
|
}
|
|
|
|
data_string_copy (&nc -> hash_string, &data,
|
|
|
|
"check_collection");
|
|
|
|
data_string_forget (&data, "check_collection");
|
|
|
|
if (!class -> hash)
|
|
|
|
class -> hash = new_hash ();
|
|
|
|
add_hash (class -> hash,
|
|
|
|
nc -> hash_string.data,
|
|
|
|
nc -> hash_string.len,
|
|
|
|
(unsigned char *)nc);
|
|
|
|
classify (packet, nc);
|
1998-04-19 23:24:48 +00:00
|
|
|
}
|
1998-11-11 07:58:35 +00:00
|
|
|
data_string_forget (&data, "check_collection");
|
1998-04-19 23:24:48 +00:00
|
|
|
}
|
1998-11-11 07:58:35 +00:00
|
|
|
|
1998-11-06 03:25:45 +00:00
|
|
|
status = (evaluate_boolean_expression_result
|
1999-10-21 03:09:13 +00:00
|
|
|
(&ignorep, packet, lease,
|
1999-07-31 18:09:51 +00:00
|
|
|
packet -> options, (struct option_state *)0,
|
|
|
|
class -> expr));
|
1998-11-09 02:46:19 +00:00
|
|
|
if (status) {
|
1998-11-06 03:25:45 +00:00
|
|
|
matched = 1;
|
|
|
|
#if defined (DEBUG_CLASS_MATCHING)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("matches class.");
|
1998-11-06 03:25:45 +00:00
|
|
|
#endif
|
1998-11-06 00:16:22 +00:00
|
|
|
classify (packet, class);
|
1998-11-11 07:58:35 +00:00
|
|
|
}
|
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)
|
|
|
|
packet -> classes [packet -> class_count++] = class;
|
|
|
|
else
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("too many groups for %s",
|
1998-04-19 23:24:48 +00:00
|
|
|
print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
packet -> raw -> chaddr));
|
|
|
|
}
|
|
|
|
|
1998-06-25 03:42:18 +00:00
|
|
|
struct class *find_class (name)
|
1999-10-07 06:36:35 +00:00
|
|
|
const char *name;
|
1998-06-25 03:42:18 +00:00
|
|
|
{
|
|
|
|
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 cp;
|
|
|
|
}
|
|
|
|
return (struct class *)0;
|
|
|
|
}
|
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) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("lease %s unbilled with no billing arrangement.",
|
1998-11-11 07:58:35 +00:00
|
|
|
piaddr (lease -> ip_addr));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
lease -> billing_class = (struct class *)0;
|
|
|
|
class -> billed_leases [i] = (struct lease *)0;
|
|
|
|
class -> leases_consumed--;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bill_class (lease, class)
|
|
|
|
struct lease *lease;
|
|
|
|
struct class *class;
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
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) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("class billing consumption disagrees with leases.");
|
1998-11-11 07:58:35 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
class -> billed_leases [i] = lease;
|
|
|
|
lease -> billing_class = class;
|
|
|
|
class -> leases_consumed++;
|
|
|
|
return 1;
|
|
|
|
}
|