2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-29 05:17:57 +00:00

Rework DHCP lease state handling to be compatible with failover protocol.

This commit is contained in:
Ted Lemon 2000-06-02 21:27:21 +00:00
parent 7bb809483c
commit 007e3ee4df
15 changed files with 1317 additions and 883 deletions

View File

@ -43,7 +43,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: clparse.c,v 1.44 2000/05/16 23:01:57 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: clparse.c,v 1.45 2000/06/02 21:26:55 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -291,7 +291,7 @@ void parse_client_statement (cfile, ip, config)
return; return;
} }
config -> auth_policy = policy; config -> auth_policy = policy;
} else if (token != BOOTP) { } else if (token != TOKEN_BOOTP) {
if (policy != P_PREFER && if (policy != P_PREFER &&
policy != P_IGNORE && policy != P_IGNORE &&
policy != P_ACCEPT) { policy != P_ACCEPT) {
@ -919,7 +919,7 @@ void parse_client_lease_declaration (cfile, lease, ipp, clientp)
parse_warn (cfile, "unknown key %s", val); parse_warn (cfile, "unknown key %s", val);
parse_semi (cfile); parse_semi (cfile);
break; break;
case BOOTP: case TOKEN_BOOTP:
lease -> is_bootp = 1; lease -> is_bootp = 1;
break; break;

View File

@ -41,7 +41,7 @@
#ifndef lint #ifndef lint
static char ocopyright[] = static char ocopyright[] =
"$Id: dhclient.c,v 1.104 2000/05/30 21:43:42 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 Internet Software Consortium. All rights reserved.\n"; "$Id: dhclient.c,v 1.105 2000/06/02 21:26:57 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -779,7 +779,7 @@ void bind_lease (client)
} }
/* Write out the new lease. */ /* Write out the new lease. */
write_client_lease (client, client -> new, 0); write_client_lease (client, client -> new, 0, 0);
/* Replace the old active lease with the new one. */ /* Replace the old active lease with the new one. */
if (client -> active) if (client -> active)
@ -1561,18 +1561,50 @@ void send_release (cpp)
struct client_state *client = cpp; struct client_state *client = cpp;
int result; int result;
struct sockaddr_in destination;
struct in_addr from;
memcpy (&from, client -> active -> address.iabuf,
sizeof from);
memcpy (&destination.sin_addr.s_addr,
client -> destination.iabuf,
sizeof destination.sin_addr.s_addr);
destination.sin_port = remote_port;
destination.sin_family = AF_INET;
#ifdef HAVE_SA_LEN
destination.sin_len = sizeof destination;
#endif
/* Set the lease to end now, so that we don't accidentally
reuse it if we restart before the old expiry time. */
client -> active -> expiry =
client -> active -> renewal =
client -> active -> rebind = cur_time;
if (!write_client_lease (client, client -> active, 1, 1)) {
log_error ("Can't release lease: lease write failed.");
return;
}
log_info ("DHCPRELEASE on %s to %s port %d", log_info ("DHCPRELEASE on %s to %s port %d",
client -> name ? client -> name : client -> interface -> name, client -> name ? client -> name : client -> interface -> name,
inet_ntoa (sockaddr_broadcast.sin_addr), inet_ntoa (destination.sin_addr),
ntohs (sockaddr_broadcast.sin_port)); ntohs (destination.sin_port));
/* Send out a packet. */ if (fallback_interface)
result = send_packet (client -> interface, (struct packet *)0, result = send_packet (fallback_interface,
&client -> packet, (struct packet *)0,
client -> packet_length, &client -> packet,
inaddr_any, &sockaddr_broadcast, client -> packet_length,
(struct hardware *)0); from, &destination,
(struct hardware *)0);
else
/* Send out a packet. */
result = send_packet (client -> interface, (struct packet *)0,
&client -> packet,
client -> packet_length,
from, &destination,
(struct hardware *)0);
} }
void make_client_options (client, lease, type, sid, rip, prl, op) void make_client_options (client, lease, type, sid, rip, prl, op)
@ -1926,11 +1958,11 @@ void rewrite_client_leases ()
for (ip = interfaces; ip; ip = ip -> next) { for (ip = interfaces; ip; ip = ip -> next) {
for (client = ip -> client; client; client = client -> next) { for (client = ip -> client; client; client = client -> next) {
for (lp = client -> leases; lp; lp = lp -> next) { for (lp = client -> leases; lp; lp = lp -> next) {
write_client_lease (client, lp, 1); write_client_lease (client, lp, 1, 0);
} }
if (client -> active) if (client -> active)
write_client_lease (client, write_client_lease (client,
client -> active, 1); client -> active, 1, 0);
} }
} }
@ -1939,20 +1971,21 @@ void rewrite_client_leases ()
for (ip = dummy_interfaces; ip; ip = ip -> next) { for (ip = dummy_interfaces; ip; ip = ip -> next) {
for (client = ip -> client; client; client = client -> next) { for (client = ip -> client; client; client = client -> next) {
for (lp = client -> leases; lp; lp = lp -> next) { for (lp = client -> leases; lp; lp = lp -> next) {
write_client_lease (client, lp, 1); write_client_lease (client, lp, 1, 0);
} }
if (client -> active) if (client -> active)
write_client_lease (client, write_client_lease (client,
client -> active, 1); client -> active, 1, 0);
} }
} }
fflush (leaseFile); fflush (leaseFile);
} }
void write_client_lease (client, lease, rewrite) int write_client_lease (client, lease, rewrite, makesure)
struct client_state *client; struct client_state *client;
struct client_lease *lease; struct client_lease *lease;
int rewrite; int rewrite;
int makesure;
{ {
int i; int i;
struct tm *t; struct tm *t;
@ -1960,6 +1993,7 @@ void write_client_lease (client, lease, rewrite)
struct option_cache *oc; struct option_cache *oc;
struct data_string ds; struct data_string ds;
pair *hash; pair *hash;
int errors = 0;
if (!rewrite) { if (!rewrite) {
if (leases_written++ > 20) { if (leases_written++ > 20) {
@ -1971,7 +2005,7 @@ void write_client_lease (client, lease, rewrite)
/* If the lease came from the config file, we don't need to stash /* If the lease came from the config file, we don't need to stash
a copy in the lease database. */ a copy in the lease database. */
if (lease -> is_static) if (lease -> is_static)
return; return 1;
if (!leaseFile) { /* XXX */ if (!leaseFile) { /* XXX */
leaseFile = fopen (path_dhclient_db, "w"); leaseFile = fopen (path_dhclient_db, "w");
@ -1979,6 +2013,7 @@ void write_client_lease (client, lease, rewrite)
log_fatal ("can't create %s: %m", path_dhclient_db); log_fatal ("can't create %s: %m", path_dhclient_db);
} }
errno = 0;
fprintf (leaseFile, "lease {\n"); fprintf (leaseFile, "lease {\n");
if (lease -> is_bootp) if (lease -> is_bootp)
fprintf (leaseFile, " bootp;\n"); fprintf (leaseFile, " bootp;\n");
@ -1997,6 +2032,10 @@ void write_client_lease (client, lease, rewrite)
if (lease -> medium) if (lease -> medium)
fprintf (leaseFile, " medium \"%s\";\n", fprintf (leaseFile, " medium \"%s\";\n",
lease -> medium -> string); lease -> medium -> string);
if (errno != 0) {
errors++;
errno = 0;
}
memset (&ds, 0, sizeof ds); memset (&ds, 0, sizeof ds);
@ -2018,6 +2057,10 @@ void write_client_lease (client, lease, rewrite)
(oc -> option -> code, (oc -> option -> code,
ds.data, ds.len, 1, 1)); ds.data, ds.len, 1, 1));
data_string_forget (&ds, MDL); data_string_forget (&ds, MDL);
if (errno != 0) {
errors++;
errno = 0;
}
} }
} }
} }
@ -2045,6 +2088,17 @@ void write_client_lease (client, lease, rewrite)
t -> tm_hour, t -> tm_min, t -> tm_sec); t -> tm_hour, t -> tm_min, t -> tm_sec);
fprintf (leaseFile, "}\n"); fprintf (leaseFile, "}\n");
fflush (leaseFile); fflush (leaseFile);
if (errno != 0) {
errors++;
errno = 0;
}
if (!errors && makesure) {
if (fsync (fileno (leaseFile)) < 0) {
log_info ("write_client_lease: %m");
return 0;
}
}
return errors ? 0 : 1;
} }
/* Variables holding name of script and file pointer for writing to /* Variables holding name of script and file pointer for writing to
@ -2357,6 +2411,9 @@ void client_location_changed ()
void do_release(client) void do_release(client)
struct client_state *client; struct client_state *client;
{ {
struct data_string ds;
struct option_cache *oc;
/* make_request doesn't initialize xid because it normally comes /* make_request doesn't initialize xid because it normally comes
from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
so pick an xid now. */ so pick an xid now. */
@ -2367,7 +2424,25 @@ void do_release(client)
/* Make a DHCPRELEASE packet, and set appropriate per-interface /* Make a DHCPRELEASE packet, and set appropriate per-interface
flags. */ flags. */
make_release (client, client -> active); make_release (client, client -> active);
client -> destination = iaddr_broadcast;
memset (&ds, 0, sizeof ds);
oc = lookup_option (&dhcp_universe,
client -> active -> options,
DHO_DHCP_SERVER_IDENTIFIER);
if (oc &&
evaluate_option_cache (&ds, (struct packet *)0,
(struct lease *)0,
(struct option_state *)0,
client -> active -> options,
&global_scope, oc, MDL)) {
if (ds.len > 3) {
memcpy (client -> destination.iabuf,
ds.data, 4);
client -> destination.len = 4;
} else
client -> destination = iaddr_broadcast;
} else
client -> destination = iaddr_broadcast;
client -> first_sending = cur_time; client -> first_sending = cur_time;
client -> interval = client -> config -> initial_interval; client -> interval = client -> config -> initial_interval;
@ -2376,13 +2451,8 @@ void do_release(client)
/* Send out the first and only DHCPRELEASE packet. */ /* Send out the first and only DHCPRELEASE packet. */
send_release (client); send_release (client);
}
/* remove the timeouts for this client */ /* Do the client script RELEASE operation. */
cancel_timeout (NULL, client);
/* if there was no lease, nothing to "do" */
if (client -> active) {
script_init (client, script_init (client,
"RELEASE", (struct string_list *)0); "RELEASE", (struct string_list *)0);
if (client -> alias) if (client -> alias)
@ -2390,6 +2460,9 @@ void do_release(client)
client -> alias); client -> alias);
script_go (client); script_go (client);
} }
/* remove the timeouts for this client */
cancel_timeout (0, client);
} }
int dhclient_interface_shutdown_hook (struct interface_info *interface) int dhclient_interface_shutdown_hook (struct interface_info *interface)

View File

@ -43,7 +43,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: conflex.c,v 1.75 2000/05/16 23:02:11 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: conflex.c,v 1.76 2000/06/02 21:27:01 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -503,7 +503,7 @@ static enum dhcp_token intern (atom, dfv)
if (!strcasecmp (atom + 1, "lgorithm")) if (!strcasecmp (atom + 1, "lgorithm"))
return ALGORITHM; return ALGORITHM;
if (!strcasecmp (atom + 1, "bandoned")) if (!strcasecmp (atom + 1, "bandoned"))
return ABANDONED; return TOKEN_ABANDONED;
if (!strcasecmp (atom + 1, "dd")) if (!strcasecmp (atom + 1, "dd"))
return TOKEN_ADD; return TOKEN_ADD;
if (!strcasecmp (atom + 1, "ll")) if (!strcasecmp (atom + 1, "ll"))
@ -514,14 +514,20 @@ static enum dhcp_token intern (atom, dfv)
return ARRAY; return ARRAY;
if (!strcasecmp (atom + 1, "ddress")) if (!strcasecmp (atom + 1, "ddress"))
return ADDRESS; return ADDRESS;
if (!strcasecmp (atom + 1, "ctive"))
return TOKEN_ACTIVE;
break; break;
case 'b': case 'b':
if (!strcasecmp (atom + 1, "ackup"))
return TOKEN_BACKUP;
if (!strcasecmp (atom + 1, "ootp"))
return TOKEN_BOOTP;
if (!strcasecmp (atom + 1, "inding"))
return BINDING;
if (!strcasecmp (atom + 1, "inary-to-ascii")) if (!strcasecmp (atom + 1, "inary-to-ascii"))
return BINARY_TO_ASCII; return BINARY_TO_ASCII;
if (!strcasecmp (atom + 1, "ackoff-cutoff")) if (!strcasecmp (atom + 1, "ackoff-cutoff"))
return BACKOFF_CUTOFF; return BACKOFF_CUTOFF;
if (!strcasecmp (atom + 1, "ootp"))
return BOOTP;
if (!strcasecmp (atom + 1, "ooting")) if (!strcasecmp (atom + 1, "ooting"))
return BOOTING; return BOOTING;
if (!strcasecmp (atom + 1, "oot-unknown-clients")) if (!strcasecmp (atom + 1, "oot-unknown-clients"))
@ -575,7 +581,7 @@ static enum dhcp_token intern (atom, dfv)
if (!strcasecmp (atom + 1, "eny")) if (!strcasecmp (atom + 1, "eny"))
return DENY; return DENY;
if (!strcasecmp (atom + 1, "eleted")) if (!strcasecmp (atom + 1, "eleted"))
return DELETED; return TOKEN_DELETED;
if (!strcasecmp (atom + 1, "elete")) if (!strcasecmp (atom + 1, "elete"))
return TOKEN_DELETE; return TOKEN_DELETE;
if (!strncasecmp (atom + 1, "efault", 6)) { if (!strncasecmp (atom + 1, "efault", 6)) {
@ -619,6 +625,8 @@ static enum dhcp_token intern (atom, dfv)
return EXPIRY; return EXPIRY;
if (!strcasecmp (atom + 2, "pire")) if (!strcasecmp (atom + 2, "pire"))
return EXPIRE; return EXPIRE;
if (!strcasecmp (atom + 2, "pired"))
return TOKEN_EXPIRED;
} }
if (!strcasecmp (atom + 1, "ncode-int")) if (!strcasecmp (atom + 1, "ncode-int"))
return ENCODE_INT; return ENCODE_INT;
@ -649,6 +657,8 @@ static enum dhcp_token intern (atom, dfv)
return FUNCTION; return FUNCTION;
if (!strcasecmp (atom + 1, "ailover")) if (!strcasecmp (atom + 1, "ailover"))
return FAILOVER; return FAILOVER;
if (!strcasecmp (atom + 1, "ree"))
return TOKEN_FREE;
break; break;
case 'g': case 'g':
if (!strcasecmp (atom + 1, "iaddr")) if (!strcasecmp (atom + 1, "iaddr"))
@ -779,6 +789,8 @@ static enum dhcp_token intern (atom, dfv)
return NS_NXRRSET; return NS_NXRRSET;
if (!strcasecmp (atom + 1, "ull")) if (!strcasecmp (atom + 1, "ull"))
return TOKEN_NULL; return TOKEN_NULL;
if (!strcasecmp (atom + 1, "ext"))
return TOKEN_NEXT;
break; break;
case 'o': case 'o':
if (!strcasecmp (atom + 1, "r")) if (!strcasecmp (atom + 1, "r"))
@ -850,6 +862,12 @@ static enum dhcp_token intern (atom, dfv)
return RELEASE; return RELEASE;
if (!strcasecmp (atom + 1, "efused")) if (!strcasecmp (atom + 1, "efused"))
return NS_REFUSED; return NS_REFUSED;
if (!strcasecmp (atom + 1, "eleased"))
return TOKEN_RELEASED;
if (!strcasecmp (atom + 1, "eset"))
return TOKEN_RESET;
if (!strcasecmp (atom + 1, "eserved"))
return TOKEN_RESERVED;
break; break;
case 's': case 's':
if (!strcasecmp (atom + 1, "tate")) if (!strcasecmp (atom + 1, "tate"))

View File

@ -238,12 +238,10 @@ struct hardware {
struct lease { struct lease {
OMAPI_OBJECT_PREAMBLE; OMAPI_OBJECT_PREAMBLE;
struct lease *next; struct lease *next;
struct lease *prev;
struct lease *n_uid, *n_hw; struct lease *n_uid, *n_hw;
struct lease *waitq_next;
struct iaddr ip_addr; struct iaddr ip_addr;
TIME starts, ends, timestamp; TIME starts, ends, timestamp, sort_time;
unsigned char *uid; unsigned char *uid;
unsigned uid_len; unsigned uid_len;
unsigned uid_max; unsigned uid_max;
@ -261,19 +259,17 @@ struct lease {
struct executable_statement *on_commit; struct executable_statement *on_commit;
struct executable_statement *on_release; struct executable_statement *on_release;
int flags; u_int16_t flags;
# define STATIC_LEASE 1 # define STATIC_LEASE 1
# define BOOTP_LEASE 2
# define PERSISTENT_FLAGS (0) # define PERSISTENT_FLAGS (0)
# define MS_NULL_TERMINATION 8 # define MS_NULL_TERMINATION 8
# define ABANDONED_LEASE 16 # define ON_UPDATE_QUEUE 16
# define PEER_IS_OWNER 32 # define ON_ACK_QUEUE 32
# define ON_UPDATE_QUEUE 64 # define EPHEMERAL_FLAGS (MS_NULL_TERMINATION | \
# define ON_ACK_QUEUE 128
# define EPHEMERAL_FLAGS (BOOTP_LEASE | MS_NULL_TERMINATION | \
ABANDONED_LEASE | PEER_IS_OWNER | \
ON_ACK_QUEUE | ON_UPDATE_QUEUE) ON_ACK_QUEUE | ON_UPDATE_QUEUE)
binding_state_t binding_state; /* See failover.h, FTS_*. */
binding_state_t next_binding_state; /* See failover.h, FTS_*. */
struct lease_state *state; struct lease_state *state;
TIME tstp; /* Time sent to partner. */ TIME tstp; /* Time sent to partner. */
@ -500,14 +496,16 @@ struct pool {
struct shared_network *shared_network; struct shared_network *shared_network;
struct permit *permit_list; struct permit *permit_list;
struct permit *prohibit_list; struct permit *prohibit_list;
struct lease *leases; struct lease *active;
struct lease *insertion_point; struct lease *expired;
struct lease *last_lease; struct lease *free;
struct lease *next_expiry; struct lease *backup;
struct lease *abandoned;
TIME next_event_time;
#if defined (FAILOVER_PROTOCOL) #if defined (FAILOVER_PROTOCOL)
int lease_count; int lease_count;
int local_leases; int free_leases;
int peer_leases; int backup_leases;
dhcp_failover_state_t *failover_peer; dhcp_failover_state_t *failover_peer;
#endif #endif
}; };
@ -1550,6 +1548,8 @@ extern u_int32_t fto_allowed [];
extern int ft_sizes []; extern int ft_sizes [];
extern const char *dhcp_flink_state_names []; extern const char *dhcp_flink_state_names [];
#endif #endif
extern const char *binding_state_names [];
extern struct universe agent_universe; extern struct universe agent_universe;
extern struct option agent_options [256]; extern struct option agent_options [256];
extern struct universe server_universe; extern struct universe server_universe;
@ -1617,8 +1617,8 @@ void make_release PROTO ((struct client_state *, struct client_lease *));
void destroy_client_lease PROTO ((struct client_lease *)); void destroy_client_lease PROTO ((struct client_lease *));
void rewrite_client_leases PROTO ((void)); void rewrite_client_leases PROTO ((void));
void write_client_lease PROTO ((struct client_state *, int write_client_lease PROTO ((struct client_state *,
struct client_lease *, int)); struct client_lease *, int, int));
char *dhcp_option_ev_name PROTO ((struct option *)); char *dhcp_option_ev_name PROTO ((struct option *));
void script_init PROTO ((struct client_state *, const char *, void script_init PROTO ((struct client_state *, const char *,
@ -2115,7 +2115,8 @@ void new_shared_network_interface PROTO ((struct parse *,
int subnet_inner_than PROTO ((struct subnet *, struct subnet *, int)); int subnet_inner_than PROTO ((struct subnet *, struct subnet *, int));
void enter_subnet PROTO ((struct subnet *)); void enter_subnet PROTO ((struct subnet *));
void enter_lease PROTO ((struct lease *)); void enter_lease PROTO ((struct lease *));
int supersede_lease PROTO ((struct lease *, struct lease *, int, int)); int supersede_lease PROTO ((struct lease *, struct lease *, int, int, int));
void process_state_transition (struct lease *);
int lease_copy PROTO ((struct lease **, struct lease *, const char *, int)); int lease_copy PROTO ((struct lease **, struct lease *, const char *, int));
void release_lease PROTO ((struct lease *, struct packet *)); void release_lease PROTO ((struct lease *, struct packet *));
void abandon_lease PROTO ((struct lease *, const char *)); void abandon_lease PROTO ((struct lease *, const char *));
@ -2205,7 +2206,7 @@ int dhcp_failover_pool_rebalance (dhcp_failover_state_t *);
int dhcp_failover_pool_check (struct pool *); int dhcp_failover_pool_check (struct pool *);
int dhcp_failover_state_pool_check (dhcp_failover_state_t *); int dhcp_failover_state_pool_check (dhcp_failover_state_t *);
isc_result_t dhcp_failover_send_updates (dhcp_failover_state_t *); isc_result_t dhcp_failover_send_updates (dhcp_failover_state_t *);
int dhcp_failover_queue_update (struct lease *); int dhcp_failover_queue_update (struct lease *, int);
void dhcp_failover_ack_queue_remove (dhcp_failover_state_t *, struct lease *); void dhcp_failover_ack_queue_remove (dhcp_failover_state_t *, struct lease *);
isc_result_t dhcp_failover_state_set_value PROTO ((omapi_object_t *, isc_result_t dhcp_failover_state_set_value PROTO ((omapi_object_t *,
omapi_object_t *, omapi_object_t *,
@ -2243,7 +2244,9 @@ failover_option_t *dhcp_failover_make_option PROTO ((unsigned, char *,
isc_result_t dhcp_failover_put_message (dhcp_failover_link_t *, isc_result_t dhcp_failover_put_message (dhcp_failover_link_t *,
omapi_object_t *, int, ...); omapi_object_t *, int, ...);
isc_result_t dhcp_failover_send_connect PROTO ((omapi_object_t *)); isc_result_t dhcp_failover_send_connect PROTO ((omapi_object_t *));
isc_result_t dhcp_failover_send_connectack PROTO ((omapi_object_t *, int)); isc_result_t dhcp_failover_send_connectack PROTO ((omapi_object_t *,
dhcp_failover_state_t *,
int, const char *));
isc_result_t dhcp_failover_send_disconnect PROTO ((omapi_object_t *, isc_result_t dhcp_failover_send_disconnect PROTO ((omapi_object_t *,
int, const char *)); int, const char *));
isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *, isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *,
@ -2260,6 +2263,11 @@ isc_result_t dhcp_failover_process_bind_ack (dhcp_failover_state_t *,
void failover_print PROTO ((char *, unsigned *, unsigned, const char *)); void failover_print PROTO ((char *, unsigned *, unsigned, const char *));
void update_partner PROTO ((struct lease *)); void update_partner PROTO ((struct lease *));
int load_balance_mine (struct packet *, dhcp_failover_state_t *); int load_balance_mine (struct packet *, dhcp_failover_state_t *);
binding_state_t binding_state_transition_check (struct lease *,
dhcp_failover_state_t *,
binding_state_t);
int lease_mine_to_extend (struct lease *);
OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_state, dhcp_failover_state_t, OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_state, dhcp_failover_state_t,
dhcp_type_failover_state) dhcp_type_failover_state)
OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_listener, dhcp_failover_listener_t, OMAPI_OBJECT_ALLOC_DECL (dhcp_failover_listener, dhcp_failover_listener_t,

View File

@ -114,7 +114,6 @@ enum dhcp_token {
EXPIRE = 308, EXPIRE = 308,
UNKNOWN_CLIENTS = 309, UNKNOWN_CLIENTS = 309,
ALLOW = 310, ALLOW = 310,
BOOTP = 311,
DENY = 312, DENY = 312,
BOOTING = 313, BOOTING = 313,
DEFAULT = 314, DEFAULT = 314,
@ -122,7 +121,7 @@ enum dhcp_token {
MEDIUM = 316, MEDIUM = 316,
ALIAS = 317, ALIAS = 317,
REBOOT = 318, REBOOT = 318,
ABANDONED = 319, TOKEN_ABANDONED = 319,
BACKOFF_CUTOFF = 320, BACKOFF_CUTOFF = 320,
INITIAL_INTERVAL = 321, INITIAL_INTERVAL = 321,
NAMESERVER = 322, NAMESERVER = 322,
@ -216,7 +215,7 @@ enum dhcp_token {
STATIC = 414, STATIC = 414,
NEVER = 415, NEVER = 415,
INFINITE = 416, INFINITE = 416,
DELETED = 417, TOKEN_DELETED = 417,
UPDATED_DNS_RR = 418, UPDATED_DNS_RR = 418,
DNS_DELETE = 419, DNS_DELETE = 419,
DUPLICATES = 420, DUPLICATES = 420,
@ -268,7 +267,17 @@ enum dhcp_token {
STATE = 466, STATE = 466,
UNKNOWN_STATE = 567, UNKNOWN_STATE = 567,
CLTT = 568, CLTT = 568,
INCLUDE = 569 INCLUDE = 569,
BINDING = 570,
TOKEN_FREE = 571,
TOKEN_ACTIVE = 572,
TOKEN_EXPIRED = 573,
TOKEN_RELEASED = 574,
TOKEN_RESET = 575,
TOKEN_BACKUP = 576,
TOKEN_RESERVED = 577,
TOKEN_BOOTP = 578,
TOKEN_NEXT = 579,
}; };
#define is_identifier(x) ((x) >= FIRST_TOKEN && \ #define is_identifier(x) ((x) >= FIRST_TOKEN && \

View File

@ -157,13 +157,17 @@ typedef struct {
#define FTR_UNKNOWN 254 #define FTR_UNKNOWN 254
/* Lease states: */ /* Lease states: */
#define FTS_FREE 1 typedef enum {
#define FTS_ACTIVE 2 FTS_FREE = 1,
#define FTS_EXPIRED 3 FTS_ACTIVE = 2,
#define FTS_RELEASED 4 FTS_EXPIRED = 3,
#define FTS_ABANDONED 5 FTS_RELEASED = 4,
#define FTS_RESET 6 FTS_ABANDONED = 5,
#define FTS_BACKUP 7 FTS_RESET = 6,
FTS_BACKUP = 7,
FTS_RESERVED = 8,
FTS_BOOTP = 9
} binding_state_t;
#define DHCP_FAILOVER_MAX_MESSAGE_SIZE 2048 #define DHCP_FAILOVER_MAX_MESSAGE_SIZE 2048

View File

@ -43,7 +43,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: confpars.c,v 1.112 2000/05/18 20:21:43 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: confpars.c,v 1.113 2000/06/02 21:27:11 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -711,6 +711,10 @@ void parse_failover_peer (cfile, group, type)
case SECONDARY: case SECONDARY:
peer -> i_am = secondary; peer -> i_am = secondary;
if (peer -> hba)
parse_warn (cfile,
"secondary may not define %s",
"load balance settings.");
break; break;
case PEER: case PEER:
@ -783,6 +787,10 @@ void parse_failover_peer (cfile, group, type)
case HBA: case HBA:
hba_len = 32; hba_len = 32;
if (peer -> i_am == secondary)
parse_warn (cfile,
"secondary may not define %s",
"load balance settings.");
if (!parse_numeric_aggregate (cfile, hba, &hba_len, if (!parse_numeric_aggregate (cfile, hba, &hba_len,
COLON, 16, 8)) { COLON, 16, 8)) {
skip_to_rbrace (cfile, 1); skip_to_rbrace (cfile, 1);
@ -806,6 +814,10 @@ void parse_failover_peer (cfile, group, type)
case SPLIT: case SPLIT:
token = next_token (&val, cfile); token = next_token (&val, cfile);
if (peer -> i_am == secondary)
parse_warn (cfile,
"secondary may not define %s",
"load balance settings.");
if (token != NUMBER) { if (token != NUMBER) {
parse_warn (cfile, "expecting number"); parse_warn (cfile, "expecting number");
badsplit: badsplit:
@ -868,6 +880,11 @@ void parse_failover_peer (cfile, group, type)
} }
} while (token != RBRACE); } while (token != RBRACE);
if (peer -> i_am == primary && !peer -> hba) {
parse_warn (cfile,
"primary failover server must have hba or split.");
}
if (type == SHARED_NET_DECL) { if (type == SHARED_NET_DECL) {
group -> shared_network -> failover_peer = peer; group -> shared_network -> failover_peer = peer;
} }
@ -1175,7 +1192,7 @@ void parse_pool_statement (cfile, group, type)
case DYNAMIC: case DYNAMIC:
permit -> type = permit_dynamic_bootp_clients; permit -> type = permit_dynamic_bootp_clients;
if (next_token (&val, cfile) != BOOTP) { if (next_token (&val, cfile) != TOKEN_BOOTP) {
parse_warn (cfile, parse_warn (cfile,
"expecting \"bootp\""); "expecting \"bootp\"");
skip_to_semi (cfile); skip_to_semi (cfile);
@ -1385,7 +1402,7 @@ void parse_host_declaration (cfile, group)
} }
/* If the host declaration was created by the server, /* If the host declaration was created by the server,
remember to save it. */ remember to save it. */
if (token == DELETED) { if (token == TOKEN_DELETED) {
deleted = 1; deleted = 1;
token = next_token (&val, cfile); token = next_token (&val, cfile);
if (!parse_semi (cfile)) if (!parse_semi (cfile))
@ -2071,7 +2088,7 @@ void parse_group_declaration (cfile, group)
token = next_token (&val, cfile); token = next_token (&val, cfile);
parse_warn (cfile, "unexpected end of file"); parse_warn (cfile, "unexpected end of file");
break; break;
} else if (token == DELETED) { } else if (token == TOKEN_DELETED) {
token = next_token (&val, cfile); token = next_token (&val, cfile);
parse_semi (cfile); parse_semi (cfile);
deletedp = 1; deletedp = 1;
@ -2215,6 +2232,7 @@ int parse_lease_declaration (struct lease **lp, struct parse *cfile)
int noequal, newbinding; int noequal, newbinding;
struct binding *binding; struct binding *binding;
isc_result_t status; isc_result_t status;
binding_state_t *statep;
lease = (struct lease *)0; lease = (struct lease *)0;
status = lease_allocate (&lease, MDL); status = lease_allocate (&lease, MDL);
@ -2351,34 +2369,76 @@ int parse_lease_declaration (struct lease **lp, struct parse *cfile)
break; break;
case DYNAMIC_BOOTP: case DYNAMIC_BOOTP:
seenbit = 128; seenbit = 256;
lease -> flags |= BOOTP_LEASE; lease -> binding_state = FTS_BOOTP;
lease -> next_binding_state = FTS_BOOTP;
parse_semi (cfile); parse_semi (cfile);
break; break;
case PEER: case TOKEN_ABANDONED:
token = next_token (&val, cfile); seenbit = 256;
if (token != IS) { lease -> binding_state = FTS_ABANDONED;
parse_warn (cfile, "expecting \"is\"."); lease -> next_binding_state = FTS_ABANDONED;
skip_to_rbrace (cfile, 1);
lease_dereference (&lease, MDL);
return 0;
}
token = next_token (&val, cfile);
if (token != OWNER) {
parse_warn (cfile, "expecting \"owner\".");
skip_to_rbrace (cfile, 1);
lease_dereference (&lease, MDL);
return 0;
}
seenbit = 262144;
lease -> flags |= PEER_IS_OWNER;
parse_semi (cfile); parse_semi (cfile);
break; break;
case ABANDONED: case TOKEN_NEXT:
seenbit = 128;
statep = &lease -> next_binding_state;
goto do_binding_state;
case BINDING:
seenbit = 256; seenbit = 256;
lease -> flags |= ABANDONED_LEASE; statep = &lease -> binding_state;
do_binding_state:
token = next_token (&val, cfile);
if (token != STATE) {
parse_warn (cfile, "expecting 'state'");
skip_to_semi (cfile);
break;
}
token = next_token (&val, cfile);
switch (token) {
case TOKEN_ABANDONED:
*statep = FTS_ABANDONED;
break;
case TOKEN_FREE:
*statep = FTS_FREE;
break;
case TOKEN_ACTIVE:
*statep = FTS_ACTIVE;
break;
case TOKEN_EXPIRED:
*statep = FTS_EXPIRED;
break;
case TOKEN_RELEASED:
*statep = FTS_RELEASED;
break;
case TOKEN_RESET:
*statep = FTS_RESET;
break;
case TOKEN_BACKUP:
*statep = FTS_BACKUP;
break;
case TOKEN_RESERVED:
*statep = FTS_RESERVED;
break;
case TOKEN_BOOTP:
*statep = FTS_BOOTP;
break;
default:
parse_warn (cfile,
"%s: expecting a binding state.",
val);
skip_to_semi (cfile);
break;
}
/* If no next binding state is specified, it's
the same as the current state. */
if (!(seenmask & 128) && seenbit == 256)
lease -> next_binding_state =
lease -> binding_state;
parse_semi (cfile); parse_semi (cfile);
break; break;
@ -2817,7 +2877,7 @@ int parse_allow_deny (oc, cfile, flag)
token = next_token (&val, cfile); token = next_token (&val, cfile);
switch (token) { switch (token) {
case BOOTP: case TOKEN_BOOTP:
status = option_cache (oc, (struct data_string *)0, data, status = option_cache (oc, (struct data_string *)0, data,
&server_options [SV_ALLOW_BOOTP]); &server_options [SV_ALLOW_BOOTP]);
break; break;

View File

@ -43,7 +43,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: db.c,v 1.50 2000/05/16 23:03:39 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: db.c,v 1.51 2000/06/02 21:27:12 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -143,13 +143,19 @@ int write_lease (lease)
} }
} }
if (lease -> flags & PEER_IS_OWNER) { fprintf (db_file, "\n binding state %s;",
errno = 0; ((lease -> binding_state > 0 &&
fprintf (db_file, "\n peer is owner;"); lease -> binding_state <= FTS_BOOTP)
if (errno) { ? binding_state_names [lease -> binding_state - 1]
++errors; : "abandoned"));
}
} if (lease -> binding_state != lease -> next_binding_state)
fprintf (db_file, "\n next binding state %s;",
((lease -> next_binding_state > 0 &&
lease -> next_binding_state <= FTS_BOOTP)
? (binding_state_names
[lease -> next_binding_state - 1])
: "abandoned"));
/* If this lease is billed to a class and is still valid, /* If this lease is billed to a class and is still valid,
write it out. */ write it out. */
@ -190,20 +196,6 @@ int write_lease (lease)
putc (';', db_file); putc (';', db_file);
} }
} }
if (lease -> flags & BOOTP_LEASE) {
errno = 0;
fprintf (db_file, "\n dynamic-bootp;");
if (errno) {
++errors;
}
}
if (lease -> flags & ABANDONED_LEASE) {
errno = 0;
fprintf (db_file, "\n abandoned;");
if (errno) {
++errors;
}
}
for (b = lease -> scope.bindings; b; b = b -> next) { for (b = lease -> scope.bindings; b; b = b -> next) {
if (!b -> value) if (!b -> value)
continue; continue;

View File

@ -43,7 +43,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: dhcp.c,v 1.150 2000/05/17 16:04:25 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: dhcp.c,v 1.151 2000/06/02 21:27:13 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -138,15 +138,10 @@ void dhcpdiscover (packet, ms_nulltp)
: packet -> interface -> name); : packet -> interface -> name);
#if defined (FAILOVER_PROTOCOL) #if defined (FAILOVER_PROTOCOL)
if (lease && lease -> pool && if (lease && !lease_mine_to_extend (lease)) {
lease -> pool -> failover_peer) { log_info ("%s: letting peer %s answer", msgbuf,
peer = lease -> pool -> failover_peer; lease -> pool -> failover_peer -> name);
if ((lease -> flags & PEER_IS_OWNER) && goto out;
peer -> my_state == normal) {
log_info ("%s: letting peer %s respond.",
msgbuf, peer -> name);
goto out;
}
} }
#endif #endif
@ -191,7 +186,7 @@ void dhcpdiscover (packet, ms_nulltp)
if (allocatedp && lease && lease -> pool && if (allocatedp && lease && lease -> pool &&
lease -> pool -> failover_peer) { lease -> pool -> failover_peer) {
peer = lease -> pool -> failover_peer; peer = lease -> pool -> failover_peer;
if (peer -> hba && peer -> my_state == normal) { if (peer -> my_state == normal) {
if (!load_balance_mine (packet, peer)) { if (!load_balance_mine (packet, peer)) {
log_debug ("%s: load balance to peer %s", log_debug ("%s: load balance to peer %s",
msgbuf, peer -> name); msgbuf, peer -> name);
@ -256,6 +251,7 @@ void dhcprequest (packet, ms_nulltp)
find_lease (&lease, packet, find_lease (&lease, packet,
subnet -> shared_network, &ours, MDL); subnet -> shared_network, &ours, MDL);
if (lease && lease -> client_hostname && if (lease && lease -> client_hostname &&
db_printable (lease -> client_hostname)) db_printable (lease -> client_hostname))
s = lease -> client_hostname; s = lease -> client_hostname;
@ -278,6 +274,14 @@ void dhcprequest (packet, ms_nulltp)
? inet_ntoa (packet -> raw -> giaddr) ? inet_ntoa (packet -> raw -> giaddr)
: packet -> interface -> name); : packet -> interface -> name);
#if defined (FAILOVER_PROTOCOL)
if (lease && !lease_mine_to_extend (lease)) {
log_info ("%s: letting peer %s answer", msgbuf,
lease -> pool -> failover_peer -> name);
goto out;
}
#endif
/* If a client on a given network REQUESTs a lease on an /* If a client on a given network REQUESTs a lease on an
address on a different network, NAK it. If the Requested address on a different network, NAK it. If the Requested
Address option was used, the protocol says that it must Address option was used, the protocol says that it must
@ -360,7 +364,7 @@ void dhcprequest (packet, ms_nulltp)
} }
} }
#if defined (FAILOVER_PROTOCOL) #if defined (FAILOVER_PROTOCOL) && 0 /* XXX this isn't the same as above! */
/* If we found a lease, but it belongs to a failover peer, and /* If we found a lease, but it belongs to a failover peer, and
the client is in the SELECTING state, ignore the request - the client is in the SELECTING state, ignore the request -
it's not ours. */ it's not ours. */
@ -420,6 +424,7 @@ void dhcprelease (packet, ms_nulltp)
struct option_cache *oc; struct option_cache *oc;
struct data_string data; struct data_string data;
char *s; char *s;
char msgbuf [1024]; /* XXX */
/* DHCPRELEASE must not specify address in requested-address /* DHCPRELEASE must not specify address in requested-address
option, but old protocol specs weren't explicit about this, option, but old protocol specs weren't explicit about this,
@ -469,27 +474,44 @@ void dhcprelease (packet, ms_nulltp)
s = (char *)0; s = (char *)0;
/* Say what we're doing... */ /* Say what we're doing... */
log_info ("DHCPRELEASE of %s from %s %s%s%svia %s (%sfound)", sprintf (msgbuf,
inet_ntoa (packet -> raw -> ciaddr), "DHCPRELEASE of %s from %s %s%s%svia %s (%sfound)",
(packet -> raw -> htype inet_ntoa (packet -> raw -> ciaddr),
? print_hw_addr (packet -> raw -> htype, (packet -> raw -> htype
packet -> raw -> hlen, ? print_hw_addr (packet -> raw -> htype,
packet -> raw -> chaddr) packet -> raw -> hlen,
: (lease packet -> raw -> chaddr)
? print_hex_1 (lease -> uid_len, lease -> uid, : (lease
lease -> uid_len) ? print_hex_1 (lease -> uid_len, lease -> uid,
: "<no identifier>")), lease -> uid_len)
s ? "(" : "", s ? s : "", s ? ") " : "", : "<no identifier>")),
packet -> raw -> giaddr.s_addr s ? "(" : "", s ? s : "", s ? ") " : "",
? inet_ntoa (packet -> raw -> giaddr) packet -> raw -> giaddr.s_addr
: packet -> interface -> name, ? inet_ntoa (packet -> raw -> giaddr)
lease ? "" : "not "); : packet -> interface -> name,
lease ? "" : "not ");
#if defined (FAILOVER_PROTOCOL)
if (lease && !lease_mine_to_extend (lease)) {
/* DHCPRELEASE messages are unicast, so if the client
sent the DHCPRELEASE to us, it's not going to send it
to the peer. Not sure why this would happen, and
if it does happen I think we still have to change the
lease state.
XXX See what it says in the draft about this. */
log_info ("%s: peer %s holds lease",
msgbuf, lease -> pool -> failover_peer -> name);
}
#endif
/* If we found a lease, release it. */ /* If we found a lease, release it. */
if (lease && lease -> ends > cur_time) { if (lease && lease -> ends > cur_time) {
release_lease (lease, packet); release_lease (lease, packet);
lease_dereference (&lease, MDL); log_info ("%s", msgbuf);
} }
out:
if (lease)
lease_dereference (&lease, MDL);
} }
void dhcpdecline (packet, ms_nulltp) void dhcpdecline (packet, ms_nulltp)
@ -505,6 +527,7 @@ void dhcpdecline (packet, ms_nulltp)
int i; int i;
const char *status; const char *status;
char *s; char *s;
char msgbuf [1024]; /* XXX */
/* DHCPDECLINE must specify address. */ /* DHCPDECLINE must specify address. */
if (!(oc = lookup_option (&dhcp_universe, packet -> options, if (!(oc = lookup_option (&dhcp_universe, packet -> options,
@ -522,6 +545,36 @@ void dhcpdecline (packet, ms_nulltp)
data_string_forget (&data, MDL); data_string_forget (&data, MDL);
find_lease_by_ip_addr (&lease, cip, MDL); find_lease_by_ip_addr (&lease, cip, MDL);
if (lease && lease -> client_hostname &&
db_printable (lease -> client_hostname))
s = lease -> client_hostname;
else
s = (char *)0;
sprintf (msgbuf, "DHCPDECLINE of %s from %s %s%s%svia %s",
piaddr (cip),
(packet -> raw -> htype
? print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr)
: (lease
? print_hex_1 (lease -> uid_len, lease -> uid,
lease -> uid_len)
: "<no identifier>")),
s ? "(" : "", s ? s : "", s ? ") " : "",
packet -> raw -> giaddr.s_addr
? inet_ntoa (packet -> raw -> giaddr)
: packet -> interface -> name);
#if defined (FAILOVER_PROTOCOL)
if (lease && !lease_mine_to_extend (lease)) {
if (!ignorep)
log_info ("%s: peer %s holds lease", msgbuf,
lease -> pool -> failover_peer -> name);
goto out;
}
#endif
option_state_allocate (&options, MDL); option_state_allocate (&options, MDL);
/* Execute statements in scope starting with the subnet scope. */ /* Execute statements in scope starting with the subnet scope. */
@ -549,38 +602,18 @@ void dhcpdecline (packet, ms_nulltp)
/* If we found a lease, mark it as unusable and complain. */ /* If we found a lease, mark it as unusable and complain. */
if (lease) { if (lease) {
abandon_lease (lease, "declined."); abandon_lease (lease, "declined.");
status = ""; status = "abandoned";
} }
status = " (not found)"; status = "not found";
} else } else
status = " (ignored)"; status = "ignored";
if (!ignorep) { if (!ignorep)
char *s; log_info ("%s: %s", msgbuf, status);
if (lease && lease -> client_hostname &&
db_printable (lease -> client_hostname))
s = lease -> client_hostname;
else
s = (char *)0;
log_info ("DHCPDECLINE of %s from %s %s%s%svia %s %s",
piaddr (cip),
(packet -> raw -> htype
? print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr)
: (lease
? print_hex_1 (lease -> uid_len, lease -> uid,
lease -> uid_len)
: "<no identifier>")),
s ? "(" : "", s ? s : "", s ? ") " : "",
packet -> raw -> giaddr.s_addr
? inet_ntoa (packet -> raw -> giaddr)
: packet -> interface -> name,
status);
}
option_state_dereference (&options, MDL); out:
if (options)
option_state_dereference (&options, MDL);
if (lease) if (lease)
lease_dereference (&lease, MDL); lease_dereference (&lease, MDL);
} }
@ -1358,7 +1391,8 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
/* Try to find a matching host declaration for this lease. */ /* Try to find a matching host declaration for this lease. */
if (!lease -> host) { if (!lease -> host) {
struct host_decl *hp; struct host_decl *hp = (struct host_decl *)0;
struct host_decl *h;
/* Try to find a host_decl that matches the client /* Try to find a host_decl that matches the client
identifier or hardware address on the packet, and identifier or hardware address on the packet, and
@ -1371,26 +1405,26 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
evaluate_option_cache (&d1, packet, lease, evaluate_option_cache (&d1, packet, lease,
packet -> options, state -> options, packet -> options, state -> options,
&lease -> scope, oc, MDL)) { &lease -> scope, oc, MDL)) {
struct host_decl *h;
hp = (struct host_decl *)0;
find_hosts_by_uid (&hp, d1.data, d1.len, MDL); find_hosts_by_uid (&hp, d1.data, d1.len, MDL);
data_string_forget (&d1, MDL); data_string_forget (&d1, MDL);
if (!hp) if (hp)
find_hosts_by_haddr (&hp, host_reference (&lease -> host, hp, MDL);
packet -> raw -> htype, }
packet -> raw -> chaddr, if (!hp) {
packet -> raw -> hlen, find_hosts_by_haddr (&hp,
MDL); packet -> raw -> htype,
packet -> raw -> chaddr,
packet -> raw -> hlen,
MDL);
for (h = hp; h; h = h -> n_ipaddr) { for (h = hp; h; h = h -> n_ipaddr) {
if (!h -> fixed_addr) if (!h -> fixed_addr)
break; break;
} }
if (h) if (h)
host_reference (&lease -> host, hp, MDL); host_reference (&lease -> host, hp, MDL);
if (hp) }
host_dereference (&hp, MDL); if (hp)
} else host_dereference (&hp, MDL);
lease -> host = (struct host_decl *)0;
} }
/* Drop the request if it's not allowed for this client. By /* Drop the request if it's not allowed for this client. By
@ -1640,6 +1674,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
lt -> ends = when; lt -> ends = when;
else else
lt -> ends = state -> offered_expiry; lt -> ends = state -> offered_expiry;
lt -> next_binding_state = FTS_ACTIVE;
} else { } else {
lease_time = MAX_TIME - cur_time; lease_time = MAX_TIME - cur_time;
@ -1669,7 +1704,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
} }
lt -> ends = state -> offered_expiry = cur_time + lease_time; lt -> ends = state -> offered_expiry = cur_time + lease_time;
lt -> flags = BOOTP_LEASE; lt -> next_binding_state = FTS_BOOTP;
} }
lt -> timestamp = cur_time; lt -> timestamp = cur_time;
@ -1752,29 +1787,13 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
it) either. */ it) either. */
if (!(supersede_lease (lease, lt, !offer || offer == DHCPACK, if (!(supersede_lease (lease, lt, !offer || offer == DHCPACK,
offer == DHCPACK) offer == DHCPACK, offer == DHCPACK)
|| (offer && offer != DHCPACK))) { || (offer && offer != DHCPACK))) {
log_info ("%s: database update failed", msg); log_info ("%s: database update failed", msg);
free_lease_state (state, MDL); free_lease_state (state, MDL);
static_lease_dereference (lease, MDL); static_lease_dereference (lease, MDL);
lease_dereference (&lt, MDL); lease_dereference (&lt, MDL);
return; return;
} else {
/* If this is a DHCPOFFER transaction, supersede_lease
will not add the timer for the expire event to the
queue. This is because DHCPOFFERS are not commited,
and supersede_lease only adds commited leases to the
timer queue. So if supersede_lease set this lease
as the next one to expire for the pool we need to
put it on the timer queue ourself. */
/* XXX need to think about this. */
if (offer == DHCPOFFER && lease -> pool &&
lease -> pool -> next_expiry == lease)
add_timeout (lease -> ends, pool_timer,
lease -> pool,
(tvref_t)omapi_object_reference,
(tvunref_t)
omapi_object_dereference);
} }
} }
lease_dereference (&lt, MDL); lease_dereference (&lt, MDL);
@ -2637,7 +2656,6 @@ int find_lease (struct lease **lp,
/* Toss ip_lease if it hasn't yet expired and doesn't belong to the /* Toss ip_lease if it hasn't yet expired and doesn't belong to the
client. */ client. */
if (ip_lease && if (ip_lease &&
ip_lease -> ends >= cur_time &&
((ip_lease -> uid && ((ip_lease -> uid &&
(!have_client_identifier || (!have_client_identifier ||
ip_lease -> uid_len != client_identifier.len || ip_lease -> uid_len != client_identifier.len ||
@ -2649,25 +2667,43 @@ int find_lease (struct lease **lp,
memcmp (&ip_lease -> hardware_addr.hbuf [1], memcmp (&ip_lease -> hardware_addr.hbuf [1],
packet -> raw -> chaddr, packet -> raw -> chaddr,
(unsigned)(ip_lease -> hardware_addr.hlen - 1)))))) { (unsigned)(ip_lease -> hardware_addr.hlen - 1)))))) {
/* If we're not doing failover, the only state in which
we can allocate this lease to the client is FTS_FREE.
If we are doing failover, and this lease is part of a
failover pool, then if we're the primary, state has to be
FTS_FREE; if we're the secondary, state has to be
FTS_BACKUP. */
if ((ip_lease -> binding_state != FTS_FREE &&
ip_lease -> binding_state != FTS_BACKUP)
#if defined (FAILOVER_PROTOCOL)
||
(ip_lease -> pool -> failover_peer &&
((ip_lease -> binding_state == FTS_FREE &&
ip_lease -> pool -> failover_peer -> i_am == secondary)
||
(ip_lease -> binding_state == FTS_BACKUP &&
ip_lease -> pool -> failover_peer -> i_am == primary)))
#endif
) {
#if defined (DEBUG_FIND_LEASE) #if defined (DEBUG_FIND_LEASE)
if (ip_lease)
log_info ("rejecting lease for requested address."); log_info ("rejecting lease for requested address.");
#endif #endif
lease_dereference (&ip_lease, MDL); lease_dereference (&ip_lease, MDL);
}
} }
/* If for some reason the client has more than one lease /* If for some reason the client has more than one lease
on the subnet that matches its uid, pick the one that on the subnet that matches its uid, pick the one that
it asked for and (if we can) free the other. */ it asked for and (if we can) free the other. */
if (ip_lease && if (ip_lease &&
ip_lease -> ends >= cur_time && ip_lease -> binding_state == FTS_ACTIVE &&
ip_lease -> uid && ip_lease != uid_lease) { ip_lease -> uid && ip_lease != uid_lease) {
if (have_client_identifier && if (have_client_identifier &&
(ip_lease -> uid_len == client_identifier.len) && (ip_lease -> uid_len == client_identifier.len) &&
!memcmp (client_identifier.data, !memcmp (client_identifier.data,
ip_lease -> uid, ip_lease -> uid_len)) { ip_lease -> uid, ip_lease -> uid_len)) {
if (uid_lease) { if (uid_lease) {
if (uid_lease -> ends > cur_time) { if (uid_lease -> binding_state == FTS_ACTIVE) {
log_error ("client %s has duplicate%s on %s", log_error ("client %s has duplicate%s on %s",
(print_hw_addr (print_hw_addr
(packet -> raw -> htype, (packet -> raw -> htype,
@ -2722,17 +2758,6 @@ int find_lease (struct lease **lp,
if (packet -> packet_type == DHCPREQUEST && fixed_lease && ip_lease) if (packet -> packet_type == DHCPREQUEST && fixed_lease && ip_lease)
goto db_conflict; goto db_conflict;
/* Make sure the client is permitted to use the requested lease. */
if (ip_lease &&
((ip_lease -> pool -> prohibit_list &&
permitted (packet, ip_lease -> pool -> prohibit_list)) ||
(ip_lease -> pool -> permit_list &&
!permitted (packet, ip_lease -> pool -> permit_list)))) {
if (!packet -> raw -> ciaddr.s_addr)
release_lease (ip_lease, packet);
lease_dereference (&ip_lease, MDL);
}
/* Toss extra pointers to the same lease... */ /* Toss extra pointers to the same lease... */
if (hw_lease && hw_lease == uid_lease) { if (hw_lease && hw_lease == uid_lease) {
#if defined (DEBUG_FIND_LEASE) #if defined (DEBUG_FIND_LEASE)
@ -2753,6 +2778,37 @@ int find_lease (struct lease **lp,
#endif #endif
} }
/* Make sure the client is permitted to use the requested lease. */
if (ip_lease &&
((ip_lease -> pool -> prohibit_list &&
permitted (packet, ip_lease -> pool -> prohibit_list)) ||
(ip_lease -> pool -> permit_list &&
!permitted (packet, ip_lease -> pool -> permit_list)))) {
if (!packet -> raw -> ciaddr.s_addr)
release_lease (ip_lease, packet);
lease_dereference (&ip_lease, MDL);
}
if (uid_lease &&
((uid_lease -> pool -> prohibit_list &&
permitted (packet, uid_lease -> pool -> prohibit_list)) ||
(uid_lease -> pool -> permit_list &&
!permitted (packet, uid_lease -> pool -> permit_list)))) {
if (!packet -> raw -> ciaddr.s_addr)
release_lease (uid_lease, packet);
lease_dereference (&uid_lease, MDL);
}
if (hw_lease &&
((hw_lease -> pool -> prohibit_list &&
permitted (packet, hw_lease -> pool -> prohibit_list)) ||
(hw_lease -> pool -> permit_list &&
!permitted (packet, hw_lease -> pool -> permit_list)))) {
if (!packet -> raw -> ciaddr.s_addr)
release_lease (hw_lease, packet);
lease_dereference (&hw_lease, MDL);
}
/* If we've already eliminated the lease, it wasn't there to /* If we've already eliminated the lease, it wasn't there to
begin with. If we have come up with a matching lease, begin with. If we have come up with a matching lease,
set the message to bad network in case we have to throw it out. */ set the message to bad network in case we have to throw it out. */
@ -2862,12 +2918,13 @@ int find_lease (struct lease **lp,
requested, we assume that previous bugginess on the part requested, we assume that previous bugginess on the part
of the client, or a server database loss, caused the lease to of the client, or a server database loss, caused the lease to
be abandoned, so we reclaim it and let the client have it. */ be abandoned, so we reclaim it and let the client have it. */
if (lease && (lease -> flags & ABANDONED_LEASE) && lease == ip_lease && if (lease &&
(lease -> binding_state == FTS_ABANDONED) &&
lease == ip_lease &&
packet -> packet_type == DHCPREQUEST) { packet -> packet_type == DHCPREQUEST) {
log_error ("Reclaiming REQUESTed abandoned IP address %s.", log_error ("Reclaiming REQUESTed abandoned IP address %s.",
piaddr (lease -> ip_addr)); piaddr (lease -> ip_addr));
lease -> flags &= ~ABANDONED_LEASE; } else if (lease && (lease -> binding_state == FTS_ABANDONED)) {
} else if (lease && (lease -> flags & ABANDONED_LEASE)) {
/* Otherwise, if it's not the one the client requested, we do not /* Otherwise, if it's not the one the client requested, we do not
return it - instead, we claim it's ours, causing a DHCPNAK to be return it - instead, we claim it's ours, causing a DHCPNAK to be
sent if this lookup is for a DHCPREQUEST, and force the client sent if this lookup is for a DHCPREQUEST, and force the client
@ -2941,6 +2998,7 @@ int mockup_lease (struct lease **lp, struct packet *packet,
lease -> hardware_addr = hp -> interface; lease -> hardware_addr = hp -> interface;
lease -> starts = lease -> timestamp = lease -> ends = MIN_TIME; lease -> starts = lease -> timestamp = lease -> ends = MIN_TIME;
lease -> flags = STATIC_LEASE; lease -> flags = STATIC_LEASE;
lease -> binding_state = FTS_FREE;
lease_reference (lp, lease, MDL); lease_reference (lp, lease, MDL);
lease_dereference (&lease, MDL); lease_dereference (&lease, MDL);
return 1; return 1;
@ -2986,6 +3044,7 @@ int allocate_lease (struct lease **lp, struct packet *packet,
struct pool *pool, int *peer_has_leases) struct pool *pool, int *peer_has_leases)
{ {
struct lease *lease = (struct lease *)0; struct lease *lease = (struct lease *)0;
struct lease **lq;
struct permit *permit; struct permit *permit;
if (!pool) if (!pool)
@ -2998,31 +3057,39 @@ int allocate_lease (struct lease **lp, struct packet *packet,
return allocate_lease (lp, packet, pool -> next, return allocate_lease (lp, packet, pool -> next,
peer_has_leases); peer_has_leases);
lease = pool -> last_lease;
#if defined (FAILOVER_PROTOCOL) #if defined (FAILOVER_PROTOCOL)
/* Peer_has_leases just says that we found at least one free lease. /* Peer_has_leases just says that we found at least one free lease.
If no free lease is returned, the caller can deduce that this If no free lease is returned, the caller can deduce that this
means the peer is hogging all the free leases, so we can print means the peer is hogging all the free leases, so we can print
a better error message. */ a better error message. */
if (lease)
*peer_has_leases = 1;
/* XXX Do we need code here to ignore PEER_IS_OWNER and just check /* XXX Do we need code here to ignore PEER_IS_OWNER and just check
XXX tstp if we're in, e.g., PARTNER_DOWN? Where do we deal with XXX tstp if we're in, e.g., PARTNER_DOWN? Where do we deal with
XXX CONFLICT_DETECTED, et al? */ XXX CONFLICT_DETECTED, et al? */
/* XXX This should be handled by the lease binding "state machine" -
XXX that is, when we get here, if a lease could be allocated, it
XXX will have the correct binding state so that the following code
XXX will result in its being allocated. */
/* Skip to the most expired lease in the pool that is not owned by a /* Skip to the most expired lease in the pool that is not owned by a
failover peer. */ failover peer. */
if (lease -> pool && lease -> pool -> failover_peer) { if (pool -> failover_peer) {
while (lease && if (pool -> failover_peer -> i_am == primary) {
(lease -> flags & PEER_IS_OWNER) && if (pool -> backup)
(lease -> ends <= *peer_has_leases = 1;
cur_time + lease -> pool -> failover_peer -> mclt)) lease = pool -> free;
lease = lease -> prev; if (!lease)
/* We didn't find an unexpired lease that we own? */ lease = pool -> abandoned;
if (lease && lease -> flags & PEER_IS_OWNER) } else {
lease = (struct lease *)0; if (pool -> free)
*peer_has_leases = 1;
lease = pool -> backup;
}
} }
#else
if (pool -> free)
lease = pool -> free;
else
lease = pool -> abandoned;
#endif #endif
/* If there are no leases in the pool that have /* If there are no leases in the pool that have
@ -3035,7 +3102,7 @@ int allocate_lease (struct lease **lp, struct packet *packet,
better, take it. */ better, take it. */
/* XXX what if there are non-abandoned leases that are younger /* XXX what if there are non-abandoned leases that are younger
XXX than this? Shouldn't we hunt for those here? */ XXX than this? Shouldn't we hunt for those here? */
if ((lease -> flags & ABANDONED_LEASE)) { if (lease -> binding_state == FTS_ABANDONED) {
/* If we already have a non-abandoned lease that we didn't /* If we already have a non-abandoned lease that we didn't
love, but that's okay, don't reclaim the abandoned lease. */ love, but that's okay, don't reclaim the abandoned lease. */
if (*lp) if (*lp)
@ -3045,7 +3112,6 @@ int allocate_lease (struct lease **lp, struct packet *packet,
pool -> next, peer_has_leases)) { pool -> next, peer_has_leases)) {
log_error ("Reclaiming abandoned IP address %s.", log_error ("Reclaiming abandoned IP address %s.",
piaddr (lease -> ip_addr)); piaddr (lease -> ip_addr));
lease -> flags &= ~ABANDONED_LEASE;
lease_reference (lp, lease, MDL); lease_reference (lp, lease, MDL);
} }
return 1; return 1;

View File

@ -1272,18 +1272,21 @@ override the use of the name in the host declaration.
\fBnot authoritative;\fR \fBnot authoritative;\fR
.PP .PP
The DHCP server will normally assume that the configuration The DHCP server will normally assume that the configuration
information about a given network segment is known to be correct and information about a given network segment is not known to be correct
is authoritative. So if a client requests an IP address on a given and is not authoritative. This is so that if a naive user installs a
network segment that the server knows is not valid for that segment, DHCP server not fully understanding how to configure it, it does not
the server will respond with a DHCPNAK message, causing the client to send spurious DHCPNAK messages to clients that have obtained addresses
forget its IP address and try to get a new one. from a legitimate DHCP server on the network.
.PP .PP
If a DHCP server is being configured by somebody who is not the Network administrators setting up authoritative DHCP servers for their
network administrator and who therefore does not wish to assert this networks should always write \fBauthoritative;\fR at the top of their
level of authority, then the statement "not authoritative" should be configuration file to indicate that the DHCP server \fIshould\fR send
written in the appropriate scope in the configuration file. DHCPNAK messages to misconfigured clients. If this is not done,
clients will be unable to get a correct IP address after changing
subnets until their old lease has expired, which could take quite a
long time.
.PP .PP
Usually, writing \fBnot authoritative;\fR at the top level of the file Usually, writing \fBauthoritative;\fR at the top level of the file
should be sufficient. However, if a DHCP server is to be set up so should be sufficient. However, if a DHCP server is to be set up so
that it is aware of some networks for which it is authoritative and that it is aware of some networks for which it is authoritative and
some networks for which it is not, it may be more appropriate to some networks for which it is not, it may be more appropriate to

View File

@ -1478,39 +1478,39 @@ dhcpd.conf(5) dhcpd.conf(5)
nnoott aauutthhoorriittaattiivvee;; nnoott aauutthhoorriittaattiivvee;;
The DHCP server will normally assume that the configura­ The DHCP server will normally assume that the configura­
tion information about a given network segment is known to tion information about a given network segment is not
be correct and is authoritative. So if a client requests known to be correct and is not authoritative. This is so
an IP address on a given network segment that the server that if a naive user installs a DHCP server not fully
knows is not valid for that segment, the server will understanding how to configure it, it does not send spuri­
respond with a DHCPNAK message, causing the client to for­ ous DHCPNAK messages to clients that have obtained
get its IP address and try to get a new one. addresses from a legitimate DHCP server on the network.
If a DHCP server is being configured by somebody who is Network administrators setting up authoritative DHCP
not the network administrator and who therefore does not servers for their networks should always write aauutthhoorriittaa­­
wish to assert this level of authority, then the statement ttiivvee;; at the top of their configuration file to indicate
"not authoritative" should be written in the appropriate that the DHCP server _s_h_o_u_l_d send DHCPNAK messages to mis­
scope in the configuration file. configured clients. If this is not done, clients will be
unable to get a correct IP address after changing subnets
until their old lease has expired, which could take quite
a long time.
Usually, writing nnoott aauutthhoorriittaattiivvee;; at the top level of Usually, writing aauutthhoorriittaattiivvee;; at the top level of the
the file should be sufficient. However, if a DHCP server file should be sufficient. However, if a DHCP server is
is to be set up so that it is aware of some networks for to be set up so that it is aware of some networks for
which it is authoritative and some networks for which it which it is authoritative and some networks for which it
is not, it may be more appropriate to declare authority on is not, it may be more appropriate to declare authority on
a per-network-segment basis. a per-network-segment basis.
Note that the most specific scope for which the concept of Note that the most specific scope for which the concept of
authority makes any sense is the physical network segment authority makes any sense is the physical network segment
- either a shared-network statement or a subnet statement - either a shared-network statement or a subnet statement
that is not contained within a shared-network statement. that is not contained within a shared-network statement.
It is not meaningful to specify that the server is author­ It is not meaningful to specify that the server is author­
itative for some subnets within a shared network, but not itative for some subnets within a shared network, but not
authoritative for others, nor is it meaningful to specify authoritative for others, nor is it meaningful to specify
that the server is authoritative for some host declara­ that the server is authoritative for some host declara­
tions and not others. tions and not others.
TThhee _a_l_w_a_y_s_-_r_e_p_l_y_-_r_f_c_1_0_4_8 ssttaatteemmeenntt
23 23
@ -1522,36 +1522,38 @@ dhcpd.conf(5) dhcpd.conf(5)
dhcpd.conf(5) dhcpd.conf(5) dhcpd.conf(5) dhcpd.conf(5)
TThhee _a_l_w_a_y_s_-_r_e_p_l_y_-_r_f_c_1_0_4_8 ssttaatteemmeenntt
aallwwaayyss--rreeppllyy--rrffcc11004488 _f_l_a_g;; aallwwaayyss--rreeppllyy--rrffcc11004488 _f_l_a_g;;
Some BOOTP clients expect RFC1048-style responses, but do Some BOOTP clients expect RFC1048-style responses, but do
not follow RFC1048 when sending their requests. You can not follow RFC1048 when sending their requests. You can
tell that a client is having this problem if it is not tell that a client is having this problem if it is not
getting the options you have configured for it and if you getting the options you have configured for it and if you
see in the server log the message "(non-rfc1048)" printed see in the server log the message "(non-rfc1048)" printed
with each BOOTREQUEST that is logged. with each BOOTREQUEST that is logged.
If you want to send rfc1048 options to such a client, you If you want to send rfc1048 options to such a client, you
can set the aallwwaayyss--rreeppllyy--rrffcc11004488 option in that client's can set the aallwwaayyss--rreeppllyy--rrffcc11004488 option in that client's
host declaration, and the DHCP server will respond with an host declaration, and the DHCP server will respond with an
RFC-1048-style vendor options field. This flag can be RFC-1048-style vendor options field. This flag can be
set in any scope, and will affect all clients covered by set in any scope, and will affect all clients covered by
that scope. that scope.
TThhee _a_l_w_a_y_s_-_b_r_o_a_d_c_a_s_t ssttaatteemmeenntt TThhee _a_l_w_a_y_s_-_b_r_o_a_d_c_a_s_t ssttaatteemmeenntt
aallwwaayyss--bbrrooaaddccaasstt _f_l_a_g;; aallwwaayyss--bbrrooaaddccaasstt _f_l_a_g;;
The DHCP and BOOTP protocols both require DHCP and BOOTP The DHCP and BOOTP protocols both require DHCP and BOOTP
clients to set the broadcast bit in the flags field of the clients to set the broadcast bit in the flags field of the
BOOTP message header. Unfortunately, some DHCP and BOOTP BOOTP message header. Unfortunately, some DHCP and BOOTP
clients do not do this, and therefore may not receive clients do not do this, and therefore may not receive
responses from the DHCP server. The DHCP server can be responses from the DHCP server. The DHCP server can be
made to always broadcast its responses to clients by set­ made to always broadcast its responses to clients by set­
ting this flag to 'on' for the relevant scope. To avoid ting this flag to 'on' for the relevant scope. To avoid
creating excess broadcast traffic on your network, we rec­ creating excess broadcast traffic on your network, we rec­
ommend that you restrict the use of this option to as few ommend that you restrict the use of this option to as few
clients as possible. For example, the Microsoft DHCP clients as possible. For example, the Microsoft DHCP
client is known not to have this problem, as are the Open­ client is known not to have this problem, as are the Open­
Transport and ISC DHCP clients. Transport and ISC DHCP clients.
@ -1560,13 +1562,13 @@ dhcpd.conf(5) dhcpd.conf(5)
oonnee--lleeaassee--ppeerr--cclliieenntt _f_l_a_g;; oonnee--lleeaassee--ppeerr--cclliieenntt _f_l_a_g;;
If this flag is enabled, whenever a client sends a DHCPRE­ If this flag is enabled, whenever a client sends a DHCPRE­
QUEST for a particular lease, the server will automati­ QUEST for a particular lease, the server will automati­
cally free any other leases the client holds. This pre­ cally free any other leases the client holds. This pre­
sumes that when the client sends a DHCPREQUEST, it has sumes that when the client sends a DHCPREQUEST, it has
forgotten any lease not mentioned in the DHCPREQUEST - forgotten any lease not mentioned in the DHCPREQUEST -
i.e., the client has only a single network interface _a_n_d i.e., the client has only a single network interface _a_n_d
it does not remember leases it's holding on networks to it does not remember leases it's holding on networks to
which it is not currently attached. Neither of these which it is not currently attached. Neither of these
assumptions are guaranteed or provable, so we urge caution assumptions are guaranteed or provable, so we urge caution
in the use of this statement. in the use of this statement.
@ -1574,8 +1576,6 @@ dhcpd.conf(5) dhcpd.conf(5)
uussee--lleeaassee--aaddddrr--ffoorr--ddeeffaauulltt--rroouuttee _f_l_a_g;; uussee--lleeaassee--aaddddrr--ffoorr--ddeeffaauulltt--rroouuttee _f_l_a_g;;
If the _u_s_e_-_l_e_a_s_e_-_a_d_d_r_-_f_o_r_-_d_e_f_a_u_l_t_-_r_o_u_t_e parameter is true
in a given scope, then instead of sending the value
@ -1588,36 +1588,38 @@ dhcpd.conf(5) dhcpd.conf(5)
dhcpd.conf(5) dhcpd.conf(5) dhcpd.conf(5) dhcpd.conf(5)
specified in the routers option (or sending no value at If the _u_s_e_-_l_e_a_s_e_-_a_d_d_r_-_f_o_r_-_d_e_f_a_u_l_t_-_r_o_u_t_e parameter is true
all), the IP address of the lease being assigned is sent in a given scope, then instead of sending the value speci­
to the client. This supposedly causes Win95 machines to fied in the routers option (or sending no value at all),
ARP for all IP addresses, which can be helpful if your the IP address of the lease being assigned is sent to the
router is configured for proxy ARP. client. This supposedly causes Win95 machines to ARP for
all IP addresses, which can be helpful if your router is
configured for proxy ARP.
TThhee _s_e_r_v_e_r_-_i_d_e_n_t_i_f_i_e_r ssttaatteemmeenntt TThhee _s_e_r_v_e_r_-_i_d_e_n_t_i_f_i_e_r ssttaatteemmeenntt
sseerrvveerr--iiddeennttiiffiieerr _h_o_s_t_n_a_m_e;; sseerrvveerr--iiddeennttiiffiieerr _h_o_s_t_n_a_m_e;;
The server-identifier statement can be used to define the The server-identifier statement can be used to define the
value that is sent in the DHCP Server Identifier option value that is sent in the DHCP Server Identifier option
for a given scope. The value specified mmuusstt be an IP for a given scope. The value specified mmuusstt be an IP
address for the DHCP server, and must be reachable by all address for the DHCP server, and must be reachable by all
clients served by a particular scope. clients served by a particular scope.
The use of the server-identifier statement is not recom­ The use of the server-identifier statement is not recom­
mended - the only reason to use it is to force a value mended - the only reason to use it is to force a value
other than the default value to be sent on occasions where other than the default value to be sent on occasions where
the default value would be incorrect. The default value the default value would be incorrect. The default value
is the first IP address associated with the physical net­ is the first IP address associated with the physical net­
work interface on which the request arrived. work interface on which the request arrived.
The usual case where the _s_e_r_v_e_r_-_i_d_e_n_t_i_f_i_e_r statement needs The usual case where the _s_e_r_v_e_r_-_i_d_e_n_t_i_f_i_e_r statement needs
to be sent is when a physical interface has more than one to be sent is when a physical interface has more than one
IP address, and the one being sent by default isn't appro­ IP address, and the one being sent by default isn't appro­
priate for some or all clients served by that interface. priate for some or all clients served by that interface.
Another common case is when an alias is defined for the Another common case is when an alias is defined for the
purpose of having a consistent IP address for the DHCP purpose of having a consistent IP address for the DHCP
server, and it is desired that the clients use this IP server, and it is desired that the clients use this IP
address when contacting the server. address when contacting the server.
Supplying a value for the dhcp-server-identifier option is Supplying a value for the dhcp-server-identifier option is
@ -1627,21 +1629,19 @@ dhcpd.conf(5) dhcpd.conf(5)
ddddnnss--uuppddaatteess _f_l_a_g;; ddddnnss--uuppddaatteess _f_l_a_g;;
The _d_d_n_s_-_u_p_d_a_t_e_s parameter controls whether or not the The _d_d_n_s_-_u_p_d_a_t_e_s parameter controls whether or not the
server will attempt to do a ddns update when a lease is server will attempt to do a ddns update when a lease is
confirmed. Set this to _o_f_f if the server should not confirmed. Set this to _o_f_f if the server should not
attempt to do updates within a certain scope. The _d_d_n_s_- attempt to do updates within a certain scope. The _d_d_n_s_-
_u_p_d_a_t_e_s parameter is on by default. _u_p_d_a_t_e_s parameter is on by default.
RREEFFEERREENNCCEE:: OOPPTTIIOONN SSTTAATTEEMMEENNTTSS RREEFFEERREENNCCEE:: OOPPTTIIOONN SSTTAATTEEMMEENNTTSS
DHCP option statements are documented in the ddhhccpp-- DHCP option statements are documented in the ddhhccpp--
ooppttiioonnss((55)) manual page. ooppttiioonnss((55)) manual page.
SSEEEE AALLSSOO SSEEEE AALLSSOO
dhcpd.conf(5), dhcpd.leases(5), RFC2132, RFC2131. dhcpd.conf(5), dhcpd.leases(5), RFC2132, RFC2131.
AAUUTTHHOORR
ddhhccppdd((88)) was written by Ted Lemon <mellon@vix.com> under a
@ -1654,9 +1654,11 @@ AAUUTTHHOORR
dhcpd.conf(5) dhcpd.conf(5) dhcpd.conf(5) dhcpd.conf(5)
contract with Vixie Labs. Funding for this project was AAUUTTHHOORR
ddhhccppdd((88)) was written by Ted Lemon <mellon@vix.com> under a
contract with Vixie Labs. Funding for this project was
provided by the Internet Software Consortium. Information provided by the Internet Software Consortium. Information
about the Internet Software Consortium can be found at about the Internet Software Consortium can be found at
hhttttpp::////wwwwww..iisscc..oorrgg//iisscc.. hhttttpp::////wwwwww..iisscc..oorrgg//iisscc..
@ -1706,8 +1708,6 @@ dhcpd.conf(5) dhcpd.conf(5)

View File

@ -43,7 +43,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: failover.c,v 1.15 2000/05/17 16:04:26 mellon Exp $ Copyright (c) 1999-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: failover.c,v 1.16 2000/06/02 21:27:17 mellon Exp $ Copyright (c) 1999-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -383,6 +383,8 @@ isc_result_t dhcp_failover_link_signal (omapi_object_t *h,
a state object. */ a state object. */
/* XXX this should be authenticated! */ /* XXX this should be authenticated! */
if (link -> imsg -> type == FTM_CONNECT) { if (link -> imsg -> type == FTM_CONNECT) {
const char *errmsg;
int reason;
/* See if we can find a failover_state object that /* See if we can find a failover_state object that
matches this connection. This message should only matches this connection. This message should only
be received by a secondary from a primary. */ be received by a secondary from a primary. */
@ -396,10 +398,13 @@ isc_result_t dhcp_failover_link_signal (omapi_object_t *h,
/* If we can't find a failover protocol state /* If we can't find a failover protocol state
for this remote host, drop the connection */ for this remote host, drop the connection */
if (!state) { if (!state) {
errmsg = "unknown server";
reason = FTR_INVALID_PARTNER;
badconnect:
/* XXX Send a refusal message first? /* XXX Send a refusal message first?
XXX Look in protocol spec for guidance. */ XXX Look in protocol spec for guidance. */
log_error ("Failover CONNECT from %s %d.%d.%d.%d", log_error ("Failover CONNECT from %d.%d.%d.%d: %s",
"unknown server",
((u_int8_t *) ((u_int8_t *)
(&link -> imsg -> server_addr)) [0], (&link -> imsg -> server_addr)) [0],
((u_int8_t *) ((u_int8_t *)
@ -407,15 +412,32 @@ isc_result_t dhcp_failover_link_signal (omapi_object_t *h,
((u_int8_t *) ((u_int8_t *)
(&link -> imsg -> server_addr)) [2], (&link -> imsg -> server_addr)) [2],
((u_int8_t *) ((u_int8_t *)
(&link -> imsg -> server_addr)) [3]); (&link -> imsg -> server_addr)) [3],
errmsg);
dhcp_failover_send_connectack dhcp_failover_send_connectack
((omapi_object_t *)link, ((omapi_object_t *)link, state,
FTR_INVALID_PARTNER); reason, errmsg);
omapi_disconnect (c, 0); omapi_disconnect (c, 0);
link -> state = dhcp_flink_disconnected; link -> state = dhcp_flink_disconnected;
return ISC_R_SUCCESS; return ISC_R_SUCCESS;
} }
if (!(link -> imsg -> options_present & FTB_HBA) ||
link -> imsg -> hba.count != 32) {
errmsg = "invalid HBA";
reason = FTR_HBA_CONFLICT; /* XXX */
goto badconnect;
}
if (state -> hba)
dfree (state -> hba, MDL);
state -> hba = dmalloc (32, MDL);
if (!state -> hba) {
errmsg = "no memory";
reason = FTR_MISC_REJECT;
goto badconnect;
}
memcpy (state -> hba, link -> imsg -> hba.data, 32);
if (!link -> state_object) if (!link -> state_object)
dhcp_failover_state_reference dhcp_failover_state_reference
(&link -> state_object, state, MDL); (&link -> state_object, state, MDL);
@ -567,7 +589,7 @@ static isc_result_t do_a_failover_option (c, link)
ft_options [option_code].type == FT_DDNS1) { ft_options [option_code].type == FT_DDNS1) {
ddns_fqdn_t *ddns = ddns_fqdn_t *ddns =
((ddns_fqdn_t *) ((ddns_fqdn_t *)
(((char *)&link -> imsg) + (((char *)link -> imsg) +
ft_options [option_code].offset)); ft_options [option_code].offset));
op_count = (ft_options [option_code].type == FT_DDNS1 op_count = (ft_options [option_code].type == FT_DDNS1
@ -613,7 +635,7 @@ static isc_result_t do_a_failover_option (c, link)
op_count = option_len / op_size; op_count = option_len / op_size;
fo = ((failover_option_t *) fo = ((failover_option_t *)
(((char *)&link -> imsg) + (((char *)link -> imsg) +
ft_options [option_code].offset)); ft_options [option_code].offset));
fo -> count = op_count; fo -> count = op_count;
@ -1052,7 +1074,7 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *o,
dhcp_failover_link_reference (&state -> link_to_peer, dhcp_failover_link_reference (&state -> link_to_peer,
link, MDL); link, MDL);
status = (dhcp_failover_send_connectack status = (dhcp_failover_send_connectack
((omapi_object_t *)link, 0)); ((omapi_object_t *)link, state, 0, 0));
if (status != ISC_R_SUCCESS) { if (status != ISC_R_SUCCESS) {
dhcp_failover_link_dereference dhcp_failover_link_dereference
(&state -> link_to_peer, MDL); (&state -> link_to_peer, MDL);
@ -1061,8 +1083,10 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *o,
} }
dhcp_failover_state_transition (state, "connect"); dhcp_failover_state_transition (state, "connect");
} else if (link -> imsg -> type == FTM_CONNECTACK) { } else if (link -> imsg -> type == FTM_CONNECTACK) {
const char *errmsg;
int reason;
if (link -> imsg -> reject_reason) { if (link -> imsg -> reject_reason) {
log_error ("Failover CONNECTACK from %d.%d.%d.%d%s%s", log_error ("Failover CONNECT to %d.%d.%d.%d%s%s",
((u_int8_t *) ((u_int8_t *)
(&link -> imsg -> server_addr)) [0], (&link -> imsg -> server_addr)) [0],
((u_int8_t *) ((u_int8_t *)
@ -1074,6 +1098,7 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *o,
" rejected: ", " rejected: ",
(dhcp_failover_reject_reason_print (dhcp_failover_reject_reason_print
(link -> imsg -> reject_reason))); (link -> imsg -> reject_reason)));
/* XXX print message from peer if peer sent message. */
omapi_disconnect (link -> outer, 1); omapi_disconnect (link -> outer, 1);
return ISC_R_SUCCESS; return ISC_R_SUCCESS;
} }
@ -1082,8 +1107,10 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *o,
(state, (state,
(u_int8_t *)&link -> imsg -> server_addr, (u_int8_t *)&link -> imsg -> server_addr,
sizeof link -> imsg -> server_addr)) { sizeof link -> imsg -> server_addr)) {
log_error ("Failover CONNECTACK from %s %d.%d.%d.%d", errmsg = "unknown server";
"unknown server", reason = FTR_INVALID_PARTNER;
badconnectack:
log_error ("Failover CONNECTACK from %d.%d.%d.%d: %s",
((u_int8_t *) ((u_int8_t *)
(&link -> imsg -> server_addr)) [0], (&link -> imsg -> server_addr)) [0],
((u_int8_t *) ((u_int8_t *)
@ -1091,27 +1118,19 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *o,
((u_int8_t *) ((u_int8_t *)
(&link -> imsg -> server_addr)) [2], (&link -> imsg -> server_addr)) [2],
((u_int8_t *) ((u_int8_t *)
(&link -> imsg -> server_addr)) [3]); (&link -> imsg -> server_addr)) [3],
errmsg);
dhcp_failover_send_disconnect ((omapi_object_t *)link, dhcp_failover_send_disconnect ((omapi_object_t *)link,
FTR_INVALID_PARTNER, 0); reason, errmsg);
omapi_disconnect (link -> outer, 0); omapi_disconnect (link -> outer, 0);
} }
if (state -> link_to_peer) { if (state -> link_to_peer) {
log_error ("Failover CONNECTACK %s %d.%d.%d.%d", errmsg = "already connected";
"while already connected", reason = FTR_DUP_CONNECTION;
((u_int8_t *) goto badconnectack;
(&link -> imsg -> server_addr)) [0],
((u_int8_t *)
(&link -> imsg -> server_addr)) [1],
((u_int8_t *)
(&link -> imsg -> server_addr)) [2],
((u_int8_t *)
(&link -> imsg -> server_addr)) [3]);
dhcp_failover_send_disconnect ((omapi_object_t *)link,
FTR_DUP_CONNECTION, 0);
omapi_disconnect (link -> outer, 0);
} }
dhcp_failover_link_reference (&state -> link_to_peer, dhcp_failover_link_reference (&state -> link_to_peer,
link, MDL); link, MDL);
dhcp_failover_state_transition (state, "connect"); dhcp_failover_state_transition (state, "connect");
@ -1331,9 +1350,14 @@ int dhcp_failover_pool_rebalance (dhcp_failover_state_t *state)
{ {
int lts; int lts;
int leases_queued = 0; int leases_queued = 0;
struct lease *lp; struct lease *lp = (struct lease *)0;
struct lease *next = (struct lease *)0;
struct shared_network *s; struct shared_network *s;
struct pool *p; struct pool *p;
int polarity;
binding_state_t peer_lease_state;
binding_state_t my_lease_state;
struct lease **lq;
if (state -> my_state != normal || state -> i_am == secondary) if (state -> my_state != normal || state -> i_am == secondary)
return 0; return 0;
@ -1342,32 +1366,59 @@ int dhcp_failover_pool_rebalance (dhcp_failover_state_t *state)
for (p = s -> pools; p; p = p -> next) { for (p = s -> pools; p; p = p -> next) {
if (p -> failover_peer != state) if (p -> failover_peer != state)
continue; continue;
log_info ("pool %lx total %d local free %d peer free %d", log_info ("pool %lx total %d free %d backup %d",
(unsigned long)p, p -> lease_count, (unsigned long)p, p -> lease_count,
p -> local_leases, p -> peer_leases); p -> free_leases, p -> backup_leases);
lts = ((p -> local_leases + /* Right now we're giving the peer half of the free leases.
p -> peer_leases) / 2) - p -> peer_leases; If we have more leases than the peer (i.e., more than
if (lts > 1) { half), then the number of leases we have, less the number
struct lease lt; of leases the peer has, will be how many more leases we
have than the peer has. So if we send half that number
leases_queued += lts; to the peer, we should be even. */
for (lp = p -> last_lease; lp && lts; if (p -> failover_peer -> i_am == primary) {
lp = lp -> prev) { lts = (p -> free_leases - p -> backup_leases) / 2;
if (!(lp -> flags & PEER_IS_OWNER)) { peer_lease_state = FTS_BACKUP;
lp -> flags |= PEER_IS_OWNER; my_lease_state = FTS_FREE;
lp -> tstp = cur_time; lq = &p -> free;
if (!write_lease (lp) || } else {
!commit_leases () || lts = (p -> backup_leases - p -> free_leases) / 2;
!dhcp_failover_queue_update (lp)) { peer_lease_state = FTS_FREE;
log_info ("%s lease %s on giveaway", my_lease_state = FTS_BACKUP;
"unable to commit", lq = &p -> backup;
piaddr (lp -> ip_addr));
}
}
}
} }
if (lts > 1) {
lease_reference (&lp, *lq, MDL);
while (lp && lts) {
/* Remember the next lease in the list. */
if (next)
lease_dereference (&next, MDL);
if (lp -> next)
lease_reference (&next, lp -> next, MDL);
--lts;
++leases_queued;
lp -> next_binding_state = peer_lease_state;
lp -> tstp = cur_time;
lp -> starts = cur_time;
if (!supersede_lease (lp, (struct lease *)0, 1, 1, 0))
{
log_info ("can't commit lease %s on giveaway",
piaddr (lp -> ip_addr));
}
lease_dereference (&lp, MDL);
if (next)
lease_reference (&lp, next, MDL);
}
if (next)
lease_dereference (&next, MDL);
if (lp)
lease_dereference (&lp, MDL);
}
if (lts > 1) { if (lts > 1) {
log_info ("lease imbalance - lts = %d", lts); log_info ("lease imbalance - lts = %d", lts);
leases_queued -= lts; leases_queued -= lts;
@ -1375,6 +1426,7 @@ int dhcp_failover_pool_rebalance (dhcp_failover_state_t *state)
} }
} }
dhcp_failover_send_poolresp (state, leases_queued); dhcp_failover_send_poolresp (state, leases_queued);
dhcp_failover_send_updates (state);
return leases_queued; return leases_queued;
} }
@ -1388,12 +1440,15 @@ int dhcp_failover_pool_check (struct pool *pool)
pool -> failover_peer -> my_state != normal) pool -> failover_peer -> my_state != normal)
return 0; return 0;
log_info ("pool %lx total %d local free %d peer free %d", if (pool -> failover_peer -> i_am == primary)
(unsigned long)pool, pool -> lease_count, lts = (pool -> backup_leases - pool -> free_leases) / 2;
pool -> local_leases, pool -> peer_leases); else
lts = (pool -> free_leases - pool -> backup_leases) / 2;
log_info ("pool %lx total %d free %d backup %d lts %d",
(unsigned long)pool, pool -> lease_count,
pool -> free_leases, pool -> backup_leases, lts);
lts = ((pool -> local_leases +
pool -> peer_leases) / 2) - pool -> local_leases;
if (lts > 1) { if (lts > 1) {
/* XXX What about multiple pools? */ /* XXX What about multiple pools? */
dhcp_failover_send_poolreq (pool -> failover_peer); dhcp_failover_send_poolreq (pool -> failover_peer);
@ -1477,7 +1532,7 @@ isc_result_t dhcp_failover_send_updates (dhcp_failover_state_t *state)
not an error for this to be called on a lease for which there's no not an error for this to be called on a lease for which there's no
failover peer. */ failover peer. */
int dhcp_failover_queue_update (struct lease *lease) int dhcp_failover_queue_update (struct lease *lease, int immediate)
{ {
dhcp_failover_state_t *state; dhcp_failover_state_t *state;
@ -1509,7 +1564,8 @@ int dhcp_failover_queue_update (struct lease *lease)
} }
lease_reference (&state -> update_queue_tail, lease, MDL); lease_reference (&state -> update_queue_tail, lease, MDL);
lease -> flags |= ON_UPDATE_QUEUE; lease -> flags |= ON_UPDATE_QUEUE;
dhcp_failover_send_updates (state); if (immediate)
dhcp_failover_send_updates (state);
return 1; return 1;
} }
@ -1530,7 +1586,7 @@ void dhcp_failover_ack_queue_remove (dhcp_failover_state_t *state,
return; return;
} }
for (lp = state -> ack_queue_head; for (lp = state -> ack_queue_head;
lp -> next_pending != lease; lp = lp -> next_pending) lp && lp -> next_pending != lease; lp = lp -> next_pending)
; ;
if (lp) { if (lp) {
lease_dereference (&lp -> next_pending, MDL); lease_dereference (&lp -> next_pending, MDL);
@ -2140,7 +2196,8 @@ failover_option_t *dhcp_failover_option_printf (unsigned code,
char *obuf, char *obuf,
unsigned *obufix, unsigned *obufix,
unsigned obufmax, unsigned obufmax,
const char *fmt, ...) { const char *fmt, ...)
{
va_list va; va_list va;
char tbuf [256]; char tbuf [256];
@ -2472,6 +2529,7 @@ isc_result_t dhcp_failover_send_connect (omapi_object_t *l)
dhcp_failover_link_t *link; dhcp_failover_link_t *link;
dhcp_failover_state_t *state; dhcp_failover_state_t *state;
isc_result_t status; isc_result_t status;
char hba [32];
#if defined (DEBUG_FAILOVER_MESSAGES) #if defined (DEBUG_FAILOVER_MESSAGES)
char obuf [64]; char obuf [64];
unsigned obufix = 0; unsigned obufix = 0;
@ -2489,6 +2547,12 @@ isc_result_t dhcp_failover_send_connect (omapi_object_t *l)
if (!l -> outer || l -> outer -> type != omapi_type_connection) if (!l -> outer || l -> outer -> type != omapi_type_connection)
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
if (state -> hba) {
int i;
for (i = 0; i < 32; i++)
hba [i] = ~state -> hba [i];
}
status = (dhcp_failover_put_message status = (dhcp_failover_put_message
(link, l -> outer, (link, l -> outer,
FTM_CONNECT, FTM_CONNECT,
@ -2507,7 +2571,9 @@ isc_result_t dhcp_failover_send_connect (omapi_object_t *l)
0, 0), 0, 0),
dhcp_failover_make_option (FTO_MCLT, FMA, dhcp_failover_make_option (FTO_MCLT, FMA,
state -> mclt), state -> mclt),
dhcp_failover_make_option (FTO_HBA, FMA, 32, state -> hba), (state -> hba
? dhcp_failover_make_option (FTO_HBA, FMA, 32, hba)
: &skip_failover_option),
(failover_option_t *)0)); (failover_option_t *)0));
#if defined (DEBUG_FAILOVER_MESSAGES) #if defined (DEBUG_FAILOVER_MESSAGES)
@ -2521,10 +2587,11 @@ isc_result_t dhcp_failover_send_connect (omapi_object_t *l)
return status; return status;
} }
isc_result_t dhcp_failover_send_connectack (omapi_object_t *l, int reason) isc_result_t dhcp_failover_send_connectack (omapi_object_t *l,
dhcp_failover_state_t *state,
int reason, const char *errmsg)
{ {
dhcp_failover_link_t *link; dhcp_failover_link_t *link;
dhcp_failover_state_t *state;
isc_result_t status; isc_result_t status;
#if defined (DEBUG_FAILOVER_MESSAGES) #if defined (DEBUG_FAILOVER_MESSAGES)
char obuf [64]; char obuf [64];
@ -2539,20 +2606,26 @@ isc_result_t dhcp_failover_send_connectack (omapi_object_t *l, int reason)
if (!l || l -> type != dhcp_type_failover_link) if (!l || l -> type != dhcp_type_failover_link)
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
link = (dhcp_failover_link_t *)l; link = (dhcp_failover_link_t *)l;
state = link -> state_object;
if (!l -> outer || l -> outer -> type != omapi_type_connection) if (!l -> outer || l -> outer -> type != omapi_type_connection)
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
status = (dhcp_failover_put_message status = (dhcp_failover_put_message
(link, l -> outer, (link, l -> outer,
FTM_CONNECTACK, FTM_CONNECTACK,
dhcp_failover_make_option (FTO_SERVER_ADDR, FMA, (state
state -> server_identifier.len, ? (dhcp_failover_make_option
state -> server_identifier.data), (FTO_SERVER_ADDR, FMA,
dhcp_failover_make_option (FTO_MAX_UNACKED, FMA, state -> server_identifier.len,
state -> max_flying_updates), state -> server_identifier.data))
dhcp_failover_make_option (FTO_RECEIVE_TIMER, FMA, : &skip_failover_option),
state -> max_response_delay), (state
? dhcp_failover_make_option (FTO_MAX_UNACKED, FMA,
state -> max_flying_updates)
: &skip_failover_option),
(state
? dhcp_failover_make_option (FTO_RECEIVE_TIMER, FMA,
state -> max_response_delay)
: &skip_failover_option),
dhcp_failover_option_printf (FTO_VENDOR_CLASS, FMA, dhcp_failover_option_printf (FTO_VENDOR_CLASS, FMA,
"isc-%s", DHCP_VERSION), "isc-%s", DHCP_VERSION),
dhcp_failover_make_option (FTO_PROTOCOL_VERSION, FMA, dhcp_failover_make_option (FTO_PROTOCOL_VERSION, FMA,
@ -2563,7 +2636,11 @@ isc_result_t dhcp_failover_send_connectack (omapi_object_t *l, int reason)
? dhcp_failover_make_option (FTO_REJECT_REASON, ? dhcp_failover_make_option (FTO_REJECT_REASON,
FMA, reason) FMA, reason)
: &skip_failover_option), : &skip_failover_option),
(failover_option_t *)0)); (errmsg
? dhcp_failover_make_option (FTO_MESSAGE, FMA,
strlen (errmsg), errmsg)
: &skip_failover_option),
(failover_option_t *)0));
#if defined (DEBUG_FAILOVER_MESSAGES) #if defined (DEBUG_FAILOVER_MESSAGES)
if (status != ISC_R_SUCCESS) if (status != ISC_R_SUCCESS)
@ -2635,7 +2712,6 @@ isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *state,
#if defined (DEBUG_FAILOVER_MESSAGES) #if defined (DEBUG_FAILOVER_MESSAGES)
char obuf [64]; char obuf [64];
unsigned obufix = 0; unsigned obufix = 0;
int binding_status;
# define FMA obuf, &obufix, sizeof obuf # define FMA obuf, &obufix, sizeof obuf
failover_print (FMA, "(bndupd"); failover_print (FMA, "(bndupd");
@ -2651,26 +2727,6 @@ isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *state,
if (!link -> outer || link -> outer -> type != omapi_type_connection) if (!link -> outer || link -> outer -> type != omapi_type_connection)
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
/* Kludge up the binding status. */
if (lease -> flags & ABANDONED)
binding_status = FTS_ABANDONED;
else if (lease -> tsfp <= cur_time) {
if (lease -> flags & PEER_IS_OWNER) {
if (state -> i_am == primary)
binding_status = FTS_BACKUP;
else
binding_status = FTS_FREE;
} else {
if (state -> i_am == primary)
binding_status = FTS_FREE;
else
binding_status = FTS_BACKUP;
}
} else if (lease -> ends <= cur_time) {
binding_status = FTS_EXPIRED;
} else
binding_status = FTS_ACTIVE;
/* Send the update. */ /* Send the update. */
status = (dhcp_failover_put_message status = (dhcp_failover_put_message
(link, link -> outer, (link, link -> outer,
@ -2679,7 +2735,7 @@ isc_result_t dhcp_failover_send_bind_update (dhcp_failover_state_t *state,
lease -> ip_addr.len, lease -> ip_addr.len,
lease -> ip_addr.iabuf), lease -> ip_addr.iabuf),
dhcp_failover_make_option (FTO_BINDING_STATUS, FMA, dhcp_failover_make_option (FTO_BINDING_STATUS, FMA,
binding_status), lease -> binding_state),
lease -> uid_len lease -> uid_len
? dhcp_failover_make_option (FTO_CLIENT_IDENTIFIER, FMA, ? dhcp_failover_make_option (FTO_CLIENT_IDENTIFIER, FMA,
lease -> uid_len, lease -> uid_len,
@ -2726,7 +2782,6 @@ isc_result_t dhcp_failover_send_bind_ack (dhcp_failover_state_t *state,
#if defined (DEBUG_FAILOVER_MESSAGES) #if defined (DEBUG_FAILOVER_MESSAGES)
char obuf [64]; char obuf [64];
unsigned obufix = 0; unsigned obufix = 0;
int binding_status;
# define FMA obuf, &obufix, sizeof obuf # define FMA obuf, &obufix, sizeof obuf
failover_print (FMA, "(bndack"); failover_print (FMA, "(bndack");
@ -2742,26 +2797,6 @@ isc_result_t dhcp_failover_send_bind_ack (dhcp_failover_state_t *state,
if (!link -> outer || link -> outer -> type != omapi_type_connection) if (!link -> outer || link -> outer -> type != omapi_type_connection)
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
/* Kludge up the binding status. */
if (lease -> flags & ABANDONED)
binding_status = FTS_ABANDONED;
else if (lease -> tsfp <= cur_time) {
if (lease -> flags & PEER_IS_OWNER) {
if (state -> i_am == primary)
binding_status = FTS_BACKUP;
else
binding_status = FTS_FREE;
} else {
if (state -> i_am == primary)
binding_status = FTS_FREE;
else
binding_status = FTS_BACKUP;
}
} else if (lease -> ends <= cur_time) {
binding_status = FTS_EXPIRED;
} else
binding_status = FTS_ACTIVE;
if (!message && reason) if (!message && reason)
message = dhcp_failover_reject_reason_print (reason); message = dhcp_failover_reject_reason_print (reason);
@ -2773,7 +2808,7 @@ isc_result_t dhcp_failover_send_bind_ack (dhcp_failover_state_t *state,
lease -> ip_addr.len, lease -> ip_addr.len,
lease -> ip_addr.iabuf), lease -> ip_addr.iabuf),
dhcp_failover_make_option (FTO_BINDING_STATUS, FMA, dhcp_failover_make_option (FTO_BINDING_STATUS, FMA,
binding_status), lease -> binding_state),
lease -> uid_len lease -> uid_len
? dhcp_failover_make_option (FTO_CLIENT_IDENTIFIER, FMA, ? dhcp_failover_make_option (FTO_CLIENT_IDENTIFIER, FMA,
lease -> uid_len, lease -> uid_len,
@ -2864,7 +2899,7 @@ isc_result_t dhcp_failover_send_poolresp (dhcp_failover_state_t *state,
unsigned obufix = 0; unsigned obufix = 0;
# define FMA obuf, &obufix, sizeof obuf # define FMA obuf, &obufix, sizeof obuf
failover_print (FMA, "(poolreq"); failover_print (FMA, "(poolresp");
#else #else
# define FMA (unsigned char *)0, (unsigned *)0, 0 # define FMA (unsigned char *)0, (unsigned *)0, 0
#endif #endif
@ -2902,6 +2937,7 @@ isc_result_t dhcp_failover_process_bind_update (dhcp_failover_state_t *state,
struct iaddr ia; struct iaddr ia;
int reason = FTR_MISC_REJECT; int reason = FTR_MISC_REJECT;
const char *message; const char *message;
int new_binding_state;
ia.len = sizeof msg -> assigned_addr; ia.len = sizeof msg -> assigned_addr;
memcpy (ia.iabuf, &msg -> assigned_addr, ia.len); memcpy (ia.iabuf, &msg -> assigned_addr, ia.len);
@ -2964,21 +3000,20 @@ isc_result_t dhcp_failover_process_bind_update (dhcp_failover_state_t *state,
} }
if (msg -> options_present & FTB_BINDING_STATUS) { if (msg -> options_present & FTB_BINDING_STATUS) {
if (state -> i_am == primary) { /* Check the requested transition to make sure it's
if (msg -> binding_status == FTS_BACKUP) valid. */
lease -> flags |= PEER_IS_OWNER; new_binding_state = (binding_state_transition_check
else if (msg -> binding_status == FTS_FREE) (lease, state, msg -> binding_status));
lease -> flags &= ~PEER_IS_OWNER; if (new_binding_state != msg -> binding_status) {
} else { dhcp_failover_send_bind_ack
if (msg -> binding_status == FTS_BACKUP) (state, lease, msg, FTR_FATAL_CONFLICT,
lease -> flags &= PEER_IS_OWNER; "invalid binding state transition");
else if (msg -> binding_status == FTS_FREE)
lease -> flags |= ~PEER_IS_OWNER;
} }
lt -> next_binding_state = new_binding_state;
} }
/* Try to install the new information. */ /* Try to install the new information. */
if (!supersede_lease (lease, lt, 1, 0)) { if (!supersede_lease (lease, lt, 1, 0, 0)) {
message = "database update failed"; message = "database update failed";
bad: bad:
dhcp_failover_send_bind_ack (state, lease, msg, dhcp_failover_send_bind_ack (state, lease, msg,
@ -3022,7 +3057,7 @@ isc_result_t dhcp_failover_process_bind_ack (dhcp_failover_state_t *state,
} }
/* Try to install the new information. */ /* Try to install the new information. */
supersede_lease (lease, lt, 1, 0); supersede_lease (lease, lt, 1, 0, 0);
state -> cur_unacked_updates--; state -> cur_unacked_updates--;
dhcp_failover_ack_queue_remove (state, lease); dhcp_failover_ack_queue_remove (state, lease);
@ -3120,6 +3155,11 @@ int load_balance_mine (struct packet *packet, dhcp_failover_state_t *state)
return 1; return 1;
} }
/* If we don't have a hash bucket array, we can't tell if this
one's ours, so we assume it's not. */
if (!state -> hba)
return 0;
oc = lookup_option (&dhcp_universe, packet -> options, oc = lookup_option (&dhcp_universe, packet -> options,
DHO_DHCP_CLIENT_IDENTIFIER); DHO_DHCP_CLIENT_IDENTIFIER);
memset (&ds, 0, sizeof ds); memset (&ds, 0, sizeof ds);
@ -3139,6 +3179,195 @@ int load_balance_mine (struct packet *packet, dhcp_failover_state_t *state)
return !hm; return !hm;
} }
binding_state_t binding_state_transition_check (struct lease *lease,
dhcp_failover_state_t *state,
binding_state_t binding_state)
{
/* If there is no transition, it's no problem. */
if (binding_state == lease -> binding_state)
return binding_state;
/* This is really only dealing with what to do with bind updates when
we're in the normal state - if we were down and came back, and the
peer is in partner_down state, then we should take whatever it
sends, as long as it hasn't done anything illegal. What about
when we're in potential_conflict? */
/* Also, we should sanity check things here - the partner shouldn't
be allowed to set a lease to the EXPIRED state when it hasn't
expired, for example. */
/* Note that tsfp had better be set from the latest bind update
_before_ this function is called! */
switch (lease -> binding_state) {
case FTS_FREE:
case FTS_ABANDONED:
switch (binding_state) {
case FTS_ACTIVE:
case FTS_ABANDONED:
case FTS_BACKUP:
case FTS_RESERVED:
case FTS_BOOTP:
/* If the lease was free, and our peer is primary,
then it can make it active, or abandoned, or
backup. Abandoned is treated like free in
this case. */
if (state -> i_am == secondary)
return binding_state;
/* Otherwise, it can't do any sort of state
transition. */
case FTS_FREE: /* for compiler */
case FTS_EXPIRED:
case FTS_RELEASED:
case FTS_RESET:
return FTS_FREE;
}
case FTS_ACTIVE:
case FTS_RESERVED:
case FTS_BOOTP:
/* The secondary can't change the state of an active
lease. */
if (state -> i_am == primary)
return FTS_ACTIVE;
/* So this is only for transitions made by the primary: */
switch (binding_state) {
case FTS_FREE:
case FTS_BACKUP:
/* Can't set a lease to free or backup until the
peer agrees that it's expired. */
if (lease -> tsfp > cur_time)
return FTS_ACTIVE;
return binding_state;
case FTS_EXPIRED:
if (lease -> ends > cur_time)
return lease -> binding_state;
case FTS_RESERVED:
case FTS_BOOTP:
case FTS_RELEASED:
case FTS_ABANDONED:
case FTS_RESET:
case FTS_ACTIVE:
return binding_state;
}
case FTS_EXPIRED:
switch (binding_state) {
case FTS_FREE:
case FTS_BACKUP:
/* Can't set a lease to free or backup until the
peer agrees that it's expired. */
if (lease -> tsfp > cur_time)
return FTS_ACTIVE;
return binding_state;
case FTS_RESERVED:
case FTS_BOOTP:
case FTS_ACTIVE:
case FTS_RELEASED:
case FTS_ABANDONED:
case FTS_RESET:
case FTS_EXPIRED:
return binding_state;
}
case FTS_RELEASED:
switch (binding_state) {
case FTS_FREE:
case FTS_BACKUP:
/* Can't set a lease to free or backup until the
peer agrees that it's expired. */
if (lease -> tsfp > cur_time)
return FTS_ACTIVE;
return binding_state;
case FTS_RESERVED:
case FTS_BOOTP:
case FTS_EXPIRED:
case FTS_ABANDONED:
case FTS_RESET:
case FTS_ACTIVE:
case FTS_RELEASED:
return binding_state;
}
case FTS_RESET:
switch (binding_state) {
case FTS_FREE:
case FTS_BACKUP:
/* Can't set a lease to free or backup until the
peer agrees that it's expired. */
if (lease -> tsfp > cur_time)
return FTS_ACTIVE;
return binding_state;
case FTS_ACTIVE:
case FTS_RESERVED:
case FTS_BOOTP:
case FTS_EXPIRED:
case FTS_RELEASED:
case FTS_ABANDONED:
case FTS_RESET:
return binding_state;
}
case FTS_BACKUP:
switch (binding_state) {
case FTS_ACTIVE:
case FTS_ABANDONED:
case FTS_FREE:
case FTS_RESERVED:
case FTS_BOOTP:
/* If the lease was in backup, and our peer is
secondary, then it can make it active, or
abandoned, or free. */
if (state -> i_am == primary)
return binding_state;
/* Otherwise, it can't do any sort of state
transition. */
case FTS_EXPIRED:
case FTS_RELEASED:
case FTS_RESET:
return lease -> binding_state;
case FTS_BACKUP:
return FTS_BACKUP;
}
}
/*NOTREACHED*/
return lease -> binding_state;
}
int lease_mine_to_extend (struct lease *lease)
{
dhcp_failover_state_t *peer;
if (lease && lease -> pool &&
lease -> pool -> failover_peer) {
peer = lease -> pool -> failover_peer;
/* XXX This does't seem right - either peer can extend a lease to MCLT. */
if (peer -> my_state == normal) { /* XXX */
switch (lease -> binding_state) {
case FTS_ACTIVE:
case FTS_ABANDONED:
case FTS_RESET:
case FTS_RELEASED:
case FTS_EXPIRED:
case FTS_FREE:
case FTS_BOOTP:
case FTS_RESERVED:
if (peer -> i_am == secondary)
return 0;
break;
case FTS_BACKUP:
if (peer -> i_am == primary)
return 0;
break;
}
}
}
return 1;
}
OMAPI_OBJECT_ALLOC (dhcp_failover_state, dhcp_failover_state_t, OMAPI_OBJECT_ALLOC (dhcp_failover_state, dhcp_failover_state_t,
dhcp_type_failover_state) dhcp_type_failover_state)
OMAPI_OBJECT_ALLOC (dhcp_failover_listener, dhcp_failover_listener_t, OMAPI_OBJECT_ALLOC (dhcp_failover_listener, dhcp_failover_listener_t,

View File

@ -3,7 +3,7 @@
Server-specific in-memory database support. */ Server-specific in-memory database support. */
/* /*
* Copyright (c) 1996-1999 Internet Software Consortium. * Copyright (c) 1996-2000 Internet Software Consortium.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -43,7 +43,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: mdb.c,v 1.32 2000/05/16 23:03:46 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: mdb.c,v 1.33 2000/06/02 21:27:19 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -498,45 +498,27 @@ void new_address_range (low, high, subnet, pool)
subnet -> netmask, subnet -> netmask,
i + min)), i + min)),
isc_result_totext (status)); isc_result_totext (status));
/* Fill in the last lease if it hasn't been already... */
if (!pool -> last_lease) {
lease_reference (&pool -> last_lease, lp, MDL);
}
#endif #endif
lp -> ip_addr = ip_addr (subnet -> net, lp -> ip_addr = ip_addr (subnet -> net,
subnet -> netmask, i + min); subnet -> netmask, i + min);
lp -> starts = lp -> timestamp = MIN_TIME; lp -> starts = lp -> timestamp = MIN_TIME;
lp -> ends = MIN_TIME; lp -> ends = MIN_TIME;
subnet_reference (&lp -> subnet, subnet, MDL); subnet_reference (&lp -> subnet, subnet, MDL);
pool_reference (&lp -> pool, pool, MDL); pool_reference (&lp -> pool, pool, MDL);
#if defined (FAILOVER_PROTOCOL) lp -> binding_state = FTS_FREE;
if (pool -> failover_peer && lp -> next_binding_state = FTS_FREE;
pool -> failover_peer -> i_am == secondary) lp -> flags = 0;
lp -> flags = PEER_IS_OWNER;
else
lp -> flags = 0;
#endif
/* Link this entry into the list. */ /* Link this entry into the list. */
if (pool -> leases) { if (pool -> free) {
lease_reference (&lp -> next, pool -> leases, MDL); lease_reference (&lp -> next, pool -> free, MDL);
lease_dereference (&pool -> leases, MDL); lease_dereference (&pool -> free, MDL);
} }
lease_reference (&pool -> leases, lp, MDL); lease_reference (&pool -> free, lp, MDL);
if (lp -> next)
lease_reference (&lp -> next -> prev,
pool -> leases, MDL);
lease_hash_add (lease_ip_addr_hash, lp -> ip_addr.iabuf, lease_hash_add (lease_ip_addr_hash, lp -> ip_addr.iabuf,
lp -> ip_addr.len, lp, MDL); lp -> ip_addr.len, lp, MDL);
} }
#if defined (COMPACT_LEASES)
/* Fill in the last lease if it hasn't been already... */
if (!pool -> last_lease) {
lease_reference (&pool -> last_lease, &address_range [0], MDL);
}
#endif
/* Find out if any dangling leases are in range... */ /* Find out if any dangling leases are in range... */
plp = (struct lease *)0; plp = (struct lease *)0;
for (lp = dangling_leases; lp; lp = lp -> next) { for (lp = dangling_leases; lp; lp = lp -> next) {
@ -568,7 +550,7 @@ void new_address_range (low, high, subnet, pool)
lp -> hostname = (char *)0; lp -> hostname = (char *)0;
lt -> client_hostname = lp -> client_hostname; lt -> client_hostname = lp -> client_hostname;
lp -> client_hostname = (char *)0; lp -> client_hostname = (char *)0;
supersede_lease (lt, lp, 0, 0); supersede_lease (lt, lp, 0, 0, 0);
lease_dereference (&lt, MDL); lease_dereference (&lt, MDL);
} }
lease_dereference (&lp, MDL); lease_dereference (&lp, MDL);
@ -744,15 +726,13 @@ void enter_lease (lease)
/* If we don't have a place for this lease yet, save it for /* If we don't have a place for this lease yet, save it for
later. */ later. */
if (!find_lease_by_ip_addr (&comp, lease -> ip_addr, MDL)) { if (!find_lease_by_ip_addr (&comp, lease -> ip_addr, MDL)) {
if (comp -> next) if (lease -> next)
lease_dereference (&comp -> next, MDL); lease_dereference (&lease -> next, MDL);
if (dangling_leases) if (dangling_leases)
lease_reference (&comp -> next, dangling_leases, MDL); lease_reference (&lease -> next, dangling_leases, MDL);
lease_reference (&dangling_leases, comp, MDL); lease_reference (&dangling_leases, lease, MDL);
if (comp -> prev)
lease_dereference (&comp -> prev, MDL);
} else { } else {
supersede_lease (comp, lease, 0, 0); supersede_lease (comp, lease, 0, 0, 0);
} }
} }
@ -761,14 +741,20 @@ void enter_lease (lease)
list of leases by expiry time so that we can always find the oldest list of leases by expiry time so that we can always find the oldest
lease. */ lease. */
int supersede_lease (comp, lease, commit, propogate) int supersede_lease (comp, lease, commit, propogate, pimmediate)
struct lease *comp, *lease; struct lease *comp, *lease;
int commit; int commit;
int propogate; int propogate;
int pimmediate;
{ {
int enter_uid = 0; int enter_uid = 0;
int enter_hwaddr = 0; int enter_hwaddr = 0;
struct lease *lp; struct lease *lp, **lq, *prev;
TIME lp_next_state;
/* If there is no sample lease, just do the move. */
if (!lease)
goto just_move_it;
/* Static leases are not currently kept in the database... */ /* Static leases are not currently kept in the database... */
if (lease -> flags & STATIC_LEASE) if (lease -> flags & STATIC_LEASE)
@ -783,8 +769,10 @@ int supersede_lease (comp, lease, commit, propogate)
lease, then we allow that, in case a dynamic BOOTP lease is lease, then we allow that, in case a dynamic BOOTP lease is
requested *after* a DHCP lease has been assigned. */ requested *after* a DHCP lease has been assigned. */
if (!(lease -> flags & ABANDONED_LEASE) && if (lease -> binding_state != FTS_ABANDONED &&
comp -> ends > cur_time && (comp -> binding_state == FTS_ACTIVE ||
comp -> binding_state == FTS_RESERVED ||
comp -> binding_state == FTS_BOOTP) &&
(((comp -> uid && lease -> uid) && (((comp -> uid && lease -> uid) &&
(comp -> uid_len != lease -> uid_len || (comp -> uid_len != lease -> uid_len ||
memcmp (comp -> uid, lease -> uid, comp -> uid_len))) || memcmp (comp -> uid, lease -> uid, comp -> uid_len))) ||
@ -905,274 +893,234 @@ int supersede_lease (comp, lease, commit, propogate)
hw_hash_add (comp); hw_hash_add (comp);
} }
/* Remove the lease from its current place in the
timeout sequence. */
if (comp -> prev) {
lease_dereference (&comp -> prev -> next, MDL);
if (comp -> next) {
lease_reference (&comp -> prev -> next,
comp -> next, MDL);
lease_dereference (&comp -> next, MDL);
}
} else {
lease_dereference (&comp -> pool -> leases, MDL);
if (comp -> next) {
lease_reference (&comp -> pool -> leases,
comp -> next, MDL);
}
}
if (comp -> next) {
lease_dereference (&comp -> next -> prev, MDL);
if (comp -> prev) {
lease_reference (&comp -> next -> prev,
comp -> prev, MDL);
}
}
if (comp -> pool -> last_lease == comp) {
lease_dereference (&comp -> pool -> last_lease, MDL);
if (comp -> prev)
lease_reference (&comp -> pool -> last_lease,
comp -> prev, MDL);
}
if (comp -> prev)
lease_dereference (&comp -> prev, MDL);
if (comp -> next)
lease_dereference (&comp -> next, MDL);
/* If there's an expiry event on this lease, get rid of it
(we may wind up putting it back, but we can't count on
that here without too much additional complexity). */
if (comp -> pool -> next_expiry == comp) {
#if defined (FAILOVER_PROTOCOL) #if defined (FAILOVER_PROTOCOL)
lp = comp -> prev;
#else
for (lp = comp -> prev; lp; lp = lp -> prev)
if (lp -> on_expiry)
break;
#endif
if (lp
#if !defined (FAILOVER_PROTOCOL)
&& lp -> on_expiry
#endif
) {
lease_dereference (&comp -> pool -> next_expiry, MDL);
lease_reference (&comp -> pool -> next_expiry,
lp, MDL);
if (commit)
add_timeout (lp -> ends,
pool_timer, lp -> pool,
(tvref_t)pool_reference,
(tvunref_t)pool_dereference);
} else {
lease_dereference (&comp -> pool -> next_expiry, MDL);
if (commit)
cancel_timeout (pool_timer, comp -> pool);
}
}
/* Find the last insertion point... */
if (comp == comp -> pool -> insertion_point ||
!comp -> pool -> insertion_point) {
lp = comp -> pool -> leases;
} else {
lp = comp -> pool -> insertion_point;
}
if (!lp) {
/* Nothing on the list yet? Just make comp the
head of the list. */
lease_reference (&comp -> pool -> leases, comp, MDL);
if (comp -> pool -> last_lease) {
lease_dereference (&comp -> pool -> last_lease, MDL);
lease_reference (&comp -> pool -> last_lease,
comp, MDL);
}
} else if (lp -> ends > lease -> ends) {
/* Skip down the list until we run out of list
or find a place for comp. */
while (lp -> next && lp -> ends > lease -> ends) {
lp = lp -> next;
}
if (lp -> ends > lease -> ends) {
/* If we ran out of list, put comp at the end. */
lease_reference (&lp -> next, comp, MDL);
lease_reference (&comp -> prev, lp, MDL);
if (comp -> pool -> last_lease)
lease_dereference (&comp -> pool -> last_lease,
MDL);
lease_reference (&comp -> pool -> last_lease,
comp, MDL);
} else {
/* If we didn't, put it between lp and
the previous item on the list. */
if (lp -> prev) {
lease_reference (&comp -> prev,
lp -> prev, MDL);
lease_dereference (&lp -> prev -> next, MDL);
lease_reference (&comp -> prev -> next,
comp, MDL);
lease_dereference (&lp -> prev, MDL);
} else {
if (comp -> pool -> leases)
lease_dereference
(&comp -> pool -> leases, MDL);
lease_reference (&comp -> pool -> leases,
comp, MDL);
}
lease_reference (&comp -> next, lp, MDL);
lease_reference (&lp -> prev, comp, MDL);
}
} else {
/* Skip up the list until we run out of list
or find a place for comp. */
while (lp -> prev && lp -> ends < lease -> ends) {
lp = lp -> prev;
}
if (lp -> ends < lease -> ends) {
/* If we ran out of list, put comp at the beginning. */
lease_reference (&lp -> prev, comp, MDL);
lease_reference (&comp -> next, lp, MDL);
if (comp -> pool -> leases)
lease_dereference (&comp -> pool -> leases,
MDL);
lease_reference (&comp -> pool -> leases, comp, MDL);
} else {
/* If we didn't, put it between lp and
the next item on the list. */
if (lp -> next) {
lease_reference (&comp -> next,
lp -> next, MDL);
lease_dereference (&lp -> next -> prev, MDL);
lease_reference (&lp -> next -> prev,
comp, MDL);
lease_dereference (&lp -> next, MDL);
} else {
/* XXX are we really supposed to
XXX be doing this? */
if (comp -> pool -> last_lease)
lease_dereference
(&comp -> pool -> last_lease,
MDL);
lease_reference (&comp -> pool -> last_lease,
comp, MDL);
}
lease_reference (&comp -> prev, lp, MDL);
lease_reference (&lp -> next, comp, MDL);
}
}
if (comp -> pool -> insertion_point)
lease_dereference (&comp -> pool -> insertion_point, MDL);
lease_reference (&comp -> pool -> insertion_point, comp, MDL);
#if defined (FAILOVER_PROTOCOL)
if (comp -> ends <= cur_time && lease -> ends > cur_time) {
if (lease -> flags & PEER_IS_OWNER)
comp -> pool -> peer_leases--;
else
comp -> pool -> local_leases--;
} else if (comp -> ends > cur_time && lease -> ends <= cur_time) {
if (lease -> flags & PEER_IS_OWNER)
comp -> pool -> peer_leases++;
else
comp -> pool -> local_leases++;
}
comp -> cltt = lease -> cltt; comp -> cltt = lease -> cltt;
comp -> tstp = lease -> tstp; comp -> tstp = lease -> tstp;
comp -> tsfp = lease -> tsfp; comp -> tsfp = lease -> tsfp;
#endif /* FAILOVER_PROTOCOL */ #endif /* FAILOVER_PROTOCOL */
comp -> ends = lease -> ends; comp -> ends = lease -> ends;
comp -> next_binding_state = lease -> next_binding_state;
/* If there's an expiry event on this lease, process it or just_move_it:
queue it. */ /* Figure out which queue it's on. */
#if !defined (FAILOVER_PROTOCOL) switch (comp -> binding_state) {
if (comp -> on_expiry) { case FTS_FREE:
#endif lq = &comp -> pool -> free;
if (comp -> ends <= cur_time && commit) { comp -> pool -> free_leases--;
if (comp -> on_expiry) { break;
execute_statements ((struct packet *)0, lease,
(struct option_state *)0,
(struct option_state *)0, /* XXX */
&lease -> scope,
comp -> on_expiry);
executable_statement_dereference (&comp -> on_expiry,
MDL);
}
/* No sense releasing a lease after it's expired. */ case FTS_ACTIVE:
if (comp -> on_release) case FTS_RESERVED:
executable_statement_dereference case FTS_BOOTP:
(&comp -> on_release, MDL); lq = &comp -> pool -> active;
} else { break;
/* If this is the next lease that will timeout on the
pool, zap the old timeout and set the timeout on case FTS_EXPIRED:
this pool to the time that the lease ends. case FTS_RELEASED:
case FTS_RESET:
We do not actually set the timeout unless commit is lq = &comp -> pool -> expired;
true - we don't want to thrash the timer queue when break;
reading the lease database. Instead, the database
code calls the expiry event on each pool after case FTS_ABANDONED:
reading in the lease file, and the expiry code sets lq = &comp -> pool -> abandoned;
the timer if there's anything left to expire after break;
it's run any outstanding expiry events on the
pool. */ case FTS_BACKUP:
if (comp -> pool) { lq = &comp -> pool -> backup;
if (!comp -> pool -> next_expiry || comp -> pool -> backup_leases--;
(comp -> ends < break;
comp -> pool -> next_expiry -> ends)) {
if (comp -> pool -> next_expiry) default:
lease_dereference log_error ("Lease with bogus binding state: %d",
(&comp -> pool -> next_expiry, comp -> binding_state);
MDL); return 0;
lease_reference }
(&comp -> pool -> next_expiry,
comp, MDL); /* Remove the lease from its current place in its current
if (commit) timer sequence. */
add_timeout (comp -> ends, prev = (struct lease *)0;
pool_timer, for (lp = *lq; lp; lp = lp -> next) {
comp -> pool, if (lp == comp)
(tvref_t)pool_reference, break;
(tvunref_t) prev = lp;
pool_dereference); }
} else if (comp -> ends ==
comp -> pool -> next_expiry -> ends) { if (!lp) {
/* If there are other leases that expire at log_error ("Lease with binding state %s not on its queue.",
the same time as comp, we need to make (comp -> binding_state < 1 &&
sure that we have the one that appears comp -> binding_state < FTS_BOOTP)
last on the list that needs an expiry ? "unknown"
event - otherwise we'll miss expiry : binding_state_names [comp -> binding_state - 1]);
events until the server restarts. */ return 0;
struct lease *foo; }
struct lease *install = comp;
for (foo = comp; if (prev) {
foo && foo -> ends == comp -> ends; lease_dereference (&prev -> next, MDL);
foo = foo -> next) { if (comp -> next) {
#if !defined (FAILOVER_PROTOCOL) lease_reference (&prev -> next, comp -> next, MDL);
if (foo -> on_expiry) lease_dereference (&comp -> next, MDL);
#endif }
install = foo; } else {
} lease_dereference (lq, MDL);
lease_dereference if (comp -> next) {
(&comp -> pool -> next_expiry, lease_reference (lq, comp -> next, MDL);
MDL); lease_dereference (&comp -> next, MDL);
lease_reference }
(&comp -> pool -> next_expiry, }
install, MDL);
} /* Make the state transition. */
} if (commit)
} process_state_transition (comp);
#if !defined (FAILOVER_PROTOCOL)
/* Figure out which queue it's going to. */
switch (comp -> binding_state) {
case FTS_FREE:
lq = &comp -> pool -> free;
comp -> pool -> free_leases++;
comp -> sort_time = comp -> ends;
break;
case FTS_ACTIVE:
case FTS_RESERVED:
case FTS_BOOTP:
lq = &comp -> pool -> active;
comp -> sort_time = comp -> ends;
break;
case FTS_EXPIRED:
case FTS_RELEASED:
case FTS_RESET:
lq = &comp -> pool -> expired;
comp -> sort_time = comp -> ends;
break;
case FTS_ABANDONED:
lq = &comp -> pool -> abandoned;
comp -> sort_time = comp -> ends;
break;
case FTS_BACKUP:
lq = &comp -> pool -> backup;
comp -> pool -> backup_leases++;
comp -> sort_time = comp -> ends;
break;
default:
log_error ("Lease with bogus binding state: %d",
comp -> binding_state);
return 0;
}
/* Insertion sort the lease onto the appropriate queue. */
prev = (struct lease *)0;
for (lp = *lq; lp; lp = lp -> next) {
if (lp -> sort_time > comp -> sort_time)
break;
prev = lp;
}
if (prev) {
if (prev -> next) {
lease_reference (&comp -> next, prev -> next, MDL);
lease_dereference (&prev -> next, MDL);
}
lease_reference (&prev -> next, comp, MDL);
} else {
if (*lq) {
lease_reference (&comp -> next, *lq, MDL);
lease_dereference (lq, MDL);
}
lease_reference (lq, comp, MDL);
}
/* If this is the next lease that will timeout on the pool,
zap the old timeout and set the timeout on this pool to the
time that the lease's next event will happen.
We do not actually set the timeout unless commit is true -
we don't want to thrash the timer queue when reading the
lease database. Instead, the database code calls the
expiry event on each pool after reading in the lease file,
and the expiry code sets the timer if there's anything left
to expire after it's run any outstanding expiry events on
the pool. */
if (commit &&
comp -> sort_time != MIN_TIME &&
comp -> sort_time < cur_time &&
comp -> sort_time < comp -> pool -> next_event_time) {
comp -> pool -> next_event_time = comp -> sort_time;
add_timeout (comp -> pool -> next_event_time,
pool_timer, comp -> pool,
(tvref_t)pool_reference,
(tvunref_t)pool_dereference);
} }
#endif
/* Return zero if we didn't commit the lease to permanent storage; /* Return zero if we didn't commit the lease to permanent storage;
nonzero if we did. */ nonzero if we did. */
return commit && write_lease (comp) && commit_leases () return commit && write_lease (comp) && commit_leases ()
#if defined (FAILOVER_PROTOCOL) #if defined (FAILOVER_PROTOCOL)
&& (!propogate || dhcp_failover_queue_update (comp)) && (!propogate ||
dhcp_failover_queue_update (comp, pimmediate))
#endif #endif
; ;
} }
void process_state_transition (struct lease *lease)
{
/* If the lease was active and is now no longer active, but isn't
released, then it just expired, so do the expiry event. */
if (lease -> next_binding_state != lease -> binding_state &&
(lease -> binding_state == FTS_ACTIVE ||
lease -> binding_state == FTS_BOOTP ||
lease -> binding_state == FTS_RESERVED) &&
lease -> next_binding_state != FTS_RELEASED) {
if (lease -> on_expiry) {
execute_statements ((struct packet *)0, lease,
(struct option_state *)0,
(struct option_state *)0, /* XXX */
&lease -> scope,
lease -> on_expiry);
executable_statement_dereference (&lease -> on_expiry,
MDL);
}
/* No sense releasing a lease after it's expired. */
if (lease -> on_release)
executable_statement_dereference (&lease -> on_release,
MDL);
/* Send the expiry time to the peer. */
lease -> tstp = lease -> ends;
}
/* If the lease was active and is now released, do the release
event. */
if ((lease -> binding_state == FTS_ACTIVE ||
lease -> binding_state == FTS_BOOTP ||
lease -> binding_state == FTS_RESERVED) &&
lease -> next_binding_state == FTS_RELEASED) {
if (lease -> on_release) {
execute_statements ((struct packet *)0, lease,
(struct option_state *)0,
(struct option_state *)0, /* XXX */
&lease -> scope,
lease -> on_release);
executable_statement_dereference (&lease -> on_release,
MDL);
}
/* A released lease can't expire. */
if (lease -> on_expiry)
executable_statement_dereference (&lease -> on_expiry,
MDL);
/* Send the release time (should be == cur_time) to the
peer. */
lease -> tstp = lease -> ends;
}
lease -> binding_state = lease -> next_binding_state;
}
/* Copy the contents of one lease into another, correctly maintaining /* Copy the contents of one lease into another, correctly maintaining
reference counts. */ reference counts. */
int lease_copy (struct lease **lp, int lease_copy (struct lease **lp,
@ -1242,6 +1190,8 @@ int lease_copy (struct lease **lp,
lt -> tstp = lease -> tstp; lt -> tstp = lease -> tstp;
lt -> tsfp = lease -> tsfp; lt -> tsfp = lease -> tsfp;
lt -> cltt = lease -> cltt; lt -> cltt = lease -> cltt;
lt -> binding_state = lease -> binding_state;
lt -> next_binding_state = lease -> next_binding_state;
status = lease_reference (lp, lt, file, line); status = lease_reference (lp, lt, file, line);
lease_dereference (&lt, MDL); lease_dereference (&lt, MDL);
return status == ISC_R_SUCCESS; return status == ISC_R_SUCCESS;
@ -1252,8 +1202,6 @@ void release_lease (lease, packet)
struct lease *lease; struct lease *lease;
struct packet *packet; struct packet *packet;
{ {
struct lease *lt;
/* If there are statements to execute when the lease is /* If there are statements to execute when the lease is
released, execute them. */ released, execute them. */
if (lease -> on_release) { if (lease -> on_release) {
@ -1272,21 +1220,26 @@ void release_lease (lease, packet)
executable_statement_dereference (&lease -> on_expiry, MDL); executable_statement_dereference (&lease -> on_expiry, MDL);
if (lease -> ends > cur_time) { if (lease -> ends > cur_time) {
if (!lease_copy (&lt, lease, MDL)) if (lease -> on_commit)
return; executable_statement_dereference (&lease -> on_commit,
if (lt -> on_commit)
executable_statement_dereference (&lt -> on_commit,
MDL); MDL);
/* Blow away any bindings. */ /* Blow away any bindings. */
lt -> scope.bindings = (struct binding *)0; /* XXX free them?!? */
lease -> scope.bindings = (struct binding *)0;
lt -> ends = cur_time; lease -> ends = cur_time;
if (lt -> billing_class) #if defined (FAILOVER_PROTOCOL)
class_dereference (&lt -> billing_class, MDL); if (lease -> pool && lease -> pool -> failover_peer) {
supersede_lease (lease, lt, 1, 1); lease -> next_binding_state = FTS_RELEASED;
lease_dereference (&lt, MDL); } else {
lease -> next_binding_state = FTS_FREE;
}
#else
lease -> next_binding_state = FTS_FREE;
#endif
if (lease -> billing_class)
class_dereference (&lease -> billing_class, MDL);
supersede_lease (lease, (struct lease *)0, 1, 1, 1);
} }
} }
@ -1299,7 +1252,6 @@ void abandon_lease (lease, message)
{ {
struct lease *lt = (struct lease *)0; struct lease *lt = (struct lease *)0;
lease -> flags |= ABANDONED_LEASE;
if (!lease_copy (&lt, lease, MDL)) if (!lease_copy (&lt, lease, MDL))
return; return;
@ -1312,8 +1264,9 @@ void abandon_lease (lease, message)
/* Blow away any bindings. */ /* Blow away any bindings. */
lt -> scope.bindings = (struct binding *)0; lt -> scope.bindings = (struct binding *)0;
lt -> ends = cur_time; /* XXX */ lt -> ends = cur_time; /* XXX */
lt -> next_binding_state = FTS_ABANDONED;
log_error ("Abandoning IP address %s: %s", log_error ("Abandoning IP address %s: %s",
piaddr (lease -> ip_addr), message); piaddr (lease -> ip_addr), message);
lt -> hardware_addr.hlen = 0; lt -> hardware_addr.hlen = 0;
@ -1324,7 +1277,7 @@ void abandon_lease (lease, message)
lt -> uid_max = 0; lt -> uid_max = 0;
if (lt -> billing_class) if (lt -> billing_class)
class_dereference (&lt -> billing_class, MDL); class_dereference (&lt -> billing_class, MDL);
supersede_lease (lease, lt, 1, 1); supersede_lease (lease, lt, 1, 1, 1);
lease_dereference (&lt, MDL); lease_dereference (&lt, MDL);
} }
@ -1349,6 +1302,15 @@ void dissociate_lease (lease)
/* Blow away any bindings. */ /* Blow away any bindings. */
lt -> scope.bindings = (struct binding *)0; lt -> scope.bindings = (struct binding *)0;
#if defined (FAILOVER_PROTOCOL)
if (lease -> pool && lease -> pool -> failover_peer) {
lt -> next_binding_state = FTS_RESET;
} else {
lt -> next_binding_state = FTS_FREE;
}
#else
lt -> next_binding_state = FTS_FREE;
#endif
lt -> ends = cur_time; /* XXX */ lt -> ends = cur_time; /* XXX */
lt -> hardware_addr.hlen = 0; lt -> hardware_addr.hlen = 0;
if (lt -> uid != lt -> uid_buf) if (lt -> uid != lt -> uid_buf)
@ -1358,7 +1320,7 @@ void dissociate_lease (lease)
lt -> uid_max = 0; lt -> uid_max = 0;
if (lt -> billing_class) if (lt -> billing_class)
class_dereference (&lt -> billing_class, MDL); class_dereference (&lt -> billing_class, MDL);
supersede_lease (lease, lt, 1, 1); supersede_lease (lease, lt, 1, 1, 1);
lease_dereference (&lt, MDL); lease_dereference (&lt, MDL);
} }
@ -1367,72 +1329,75 @@ void pool_timer (vpool)
void *vpool; void *vpool;
{ {
struct pool *pool; struct pool *pool;
struct lease *lease; struct lease *lt = (struct lease *)0;
struct lease *next = (struct lease *)0;
struct lease *lease = (struct lease *)0;
struct lease **lptr [5];
TIME next_expiry = MAX_TIME;
int i;
pool = (struct pool *)vpool; pool = (struct pool *)vpool;
for (lease = pool -> next_expiry; lease; lease = lease -> prev) {
/* Stop processing when we get to the first lease that has not
yet expired. */
if (lease -> ends > cur_time)
break;
/* Skip entries that aren't set to expire. */ #define FREE_LEASES 0
if (lease -> on_expiry) { lptr [FREE_LEASES] = &pool -> free;
/* Okay, the current lease needs to expire, so #define ACTIVE_LEASES 1
do it. */ lptr [ACTIVE_LEASES] = &pool -> active;
execute_statements ((struct packet *)0, lease, #define EXPIRED_LEASES 2
(struct option_state *)0, lptr [EXPIRED_LEASES] = &pool -> expired;
(struct option_state *)0, /* XXX */ #define ABANDONED_LEASES 3
&lease -> scope, lptr [ABANDONED_LEASES] = &pool -> abandoned;
lease -> on_expiry); #define BACKUP_LEASES 4
if (lease -> on_expiry) lptr [BACKUP_LEASES] = &pool -> backup;
executable_statement_dereference
(&lease -> on_expiry, MDL);
}
/* If there's an on_release event, blow it away. */ for (i = FREE_LEASES; i <= BACKUP_LEASES; i++) {
if (lease -> on_release) /* If there's nothing on the queue, skip it. */
executable_statement_dereference (&lease -> on_release, if (!*(lptr [i]))
MDL); continue;
/* There are two problems with writing the lease out here. lease_reference (&lease, *(lptr [i]), MDL);
The first is that we've just done a commit, and the write while (lease) {
may fail, in which case we will redo the operation. If the /* Remember the next lease in the list. */
operation is not idempotent, we're in trouble here. I have if (next)
no proposed solution for this problem - make the event lease_dereference (&next, MDL);
idempotent, or make sure that it at least isn't harmful to if (lease -> next)
do it twice. lease_reference (&next, lease -> next, MDL);
The second is that if we just read in the lease file and ran /* If we've run out of things to expire on this list,
all the expiry events, we're going to rewrite all expiring stop. */
leases twice. There's no real answer for this - if we if (lease -> sort_time > cur_time) {
postpone writing until we've expired all leases, we're if (lease -> sort_time < next_expiry)
increasing the window to lose as described above. I guess a next_expiry = lease -> sort_time;
dirty bit on the lease would work. Hm. */ break;
if (!write_lease (lease)) { }
log_error ("Error updating lease %s after expiry",
piaddr (lease -> ip_addr)); /* If there is a pending state change, and
this lease has gotten to the time when the
state change should happen, just call
supersede_lease on it to make the change
happen. */
if (lease -> next_binding_state !=
lease -> binding_state)
supersede_lease (lease,
(struct lease *)0, 1, 1, 1);
lease_dereference (&lease, MDL);
if (next)
lease_reference (&lease, next, MDL);
} }
if (!commit_leases ()) { if (next)
log_error ("Error committing after writing lease %s", lease_dereference (&next, MDL);
piaddr (lease -> ip_addr)); if (lease)
} lease_dereference (&lease, MDL);
#if defined (FAILOVER_PROTOCOL)
if (lease -> flags & PEER_IS_OWNER)
pool -> peer_leases++;
else
pool -> local_leases++;
#endif
} }
if (pool -> next_expiry) if (next_expiry != MAX_TIME) {
lease_dereference (&pool -> next_expiry, MDL); pool -> next_event_time = next_expiry;
if (lease) { add_timeout (pool -> next_event_time, pool_timer, pool,
lease_reference (&pool -> next_expiry, lease, MDL);
add_timeout (lease -> ends, pool_timer, pool,
(tvref_t)pool_reference, (tvref_t)pool_reference,
(tvunref_t)pool_dereference); (tvunref_t)pool_dereference);
} } else
pool -> next_event_time = MIN_TIME;
} }
/* Locate the lease associated with a given IP address... */ /* Locate the lease associated with a given IP address... */
@ -1618,6 +1583,7 @@ void write_leases ()
struct hash_bucket *hb; struct hash_bucket *hb;
int i; int i;
int num_written; int num_written;
struct lease **lptr [5];
/* Write all the dynamically-created group declarations. */ /* Write all the dynamically-created group declarations. */
if (group_name_hash) { if (group_name_hash) {
@ -1682,18 +1648,25 @@ void write_leases ()
/* Write all the leases. */ /* Write all the leases. */
num_written = 0; num_written = 0;
for (s = shared_networks; s; s = s -> next) { for (s = shared_networks; s; s = s -> next) {
for (p = s -> pools; p; p = p -> next) { for (p = s -> pools; p; p = p -> next) {
for (l = p -> leases; l; l = l -> next) { lptr [FREE_LEASES] = &p -> free;
if (l -> hardware_addr.hlen || lptr [ACTIVE_LEASES] = &p -> active;
l -> uid_len || lptr [EXPIRED_LEASES] = &p -> expired;
(l -> flags & ABANDONED_LEASE)) { lptr [ABANDONED_LEASES] = &p -> abandoned;
if (!write_lease (l)) lptr [BACKUP_LEASES] = &p -> backup;
log_fatal ("Can't rewrite %s",
"lease database"); for (i = FREE_LEASES; i <= BACKUP_LEASES; i++) {
num_written++; for (l = *(lptr [i]); l; l = l -> next) {
} if (l -> hardware_addr.hlen ||
l -> uid_len ||
(l -> binding_state != FTS_FREE)) {
if (!write_lease (l))
log_fatal ("Can't rewrite lease database");
num_written++;
} }
}
} }
}
} }
log_info ("Wrote %d leases to leases file.", num_written); log_info ("Wrote %d leases to leases file.", num_written);
if (!commit_leases ()) if (!commit_leases ())
@ -1712,6 +1685,7 @@ void expire_all_pools ()
struct hash_bucket *hb; struct hash_bucket *hb;
int i; int i;
struct lease *l; struct lease *l;
struct lease **lptr [5];
/* Loop through each pool in each shared network and call the /* Loop through each pool in each shared network and call the
expiry routine on the pool. */ expiry routine on the pool. */
@ -1721,21 +1695,29 @@ void expire_all_pools ()
#if defined (FAILOVER_PROTOCOL) #if defined (FAILOVER_PROTOCOL)
p -> lease_count = 0; p -> lease_count = 0;
p -> local_leases = 0; p -> free_leases = 0;
p -> peer_leases = 0; p -> backup_leases = 0;
for (l = p -> leases; l; l = l -> next) { lptr [FREE_LEASES] = &p -> free;
lptr [ACTIVE_LEASES] = &p -> active;
lptr [EXPIRED_LEASES] = &p -> expired;
lptr [ABANDONED_LEASES] = &p -> abandoned;
lptr [BACKUP_LEASES] = &p -> backup;
for (i = FREE_LEASES; i <= BACKUP_LEASES; i++) {
for (l = *(lptr [i]); l; l = l -> next) {
p -> lease_count++; p -> lease_count++;
if (l -> ends <= cur_time) { if (l -> ends <= cur_time) {
if (l -> flags & PEER_IS_OWNER) if (l -> binding_state == FTS_FREE)
p -> peer_leases++; p -> free_leases++;
else else if (l -> binding_state == FTS_BACKUP)
p -> local_leases++; p -> backup_leases++;
} }
if (p -> failover_peer && if (p -> failover_peer &&
l -> tstp > l -> tsfp && l -> tstp > l -> tsfp &&
!(l -> flags & ON_UPDATE_QUEUE)) !(l -> flags & ON_UPDATE_QUEUE))
dhcp_failover_queue_update (l); dhcp_failover_queue_update (l, 1);
}
} }
#endif #endif
} }
@ -1748,6 +1730,8 @@ void dump_subnets ()
struct shared_network *s; struct shared_network *s;
struct subnet *n; struct subnet *n;
struct pool *p; struct pool *p;
struct lease **lptr [5];
int i;
log_info ("Subnets:"); log_info ("Subnets:");
for (n = subnets; n; n = n -> next_subnet) { for (n = subnets; n; n = n -> next_subnet) {
@ -1757,14 +1741,20 @@ void dump_subnets ()
} }
log_info ("Shared networks:"); log_info ("Shared networks:");
for (s = shared_networks; s; s = s -> next) { for (s = shared_networks; s; s = s -> next) {
log_info (" %s", s -> name); log_info (" %s", s -> name);
for (p = s -> pools; p; p = p -> next) { for (p = s -> pools; p; p = p -> next) {
for (l = p -> leases; l; l = l -> next) { lptr [FREE_LEASES] = &p -> free;
print_lease (l); lptr [ACTIVE_LEASES] = &p -> active;
} lptr [EXPIRED_LEASES] = &p -> expired;
log_debug ("Last Lease:"); lptr [ABANDONED_LEASES] = &p -> abandoned;
print_lease (p -> last_lease); lptr [BACKUP_LEASES] = &p -> backup;
for (i = FREE_LEASES; i <= BACKUP_LEASES; i++) {
for (l = *(lptr [i]); l; l = l -> next) {
print_lease (l);
}
} }
}
} }
} }

View File

@ -50,7 +50,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: omapi.c,v 1.28 2000/05/16 23:03:48 mellon Exp $ Copyright (c) 1999-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: omapi.c,v 1.29 2000/06/02 21:27:20 mellon Exp $ Copyright (c) 1999-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -179,27 +179,21 @@ isc_result_t dhcp_lease_set_value (omapi_object_t *h,
lease = (struct lease *)h; lease = (struct lease *)h;
/* We're skipping a lot of things it might be interesting to /* We're skipping a lot of things it might be interesting to
set - for now, we just make it possible to whack the abandoned set - for now, we just make it possible to whack the state. */
flag. */ if (!omapi_ds_strcmp (name, "state")) {
if (!omapi_ds_strcmp (name, "abandoned")) { unsigned long bar;
int bar; status = omapi_get_int_value (&bar, value);
if (status != ISC_R_SUCCESS)
return status;
if (value -> type == omapi_datatype_int) if (bar < 1 || bar > FTS_BOOTP)
bar = value -> u.integer;
else if (value -> type == omapi_datatype_data &&
value -> u.buffer.len == sizeof (int)) {
memcpy (&bar, value -> u.buffer.value, sizeof bar);
/* No need to byte-swap here. */
} else
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
if (lease -> binding_state != bar) {
foo = lease -> flags; lease -> next_binding_state = bar;
if (bar) if (supersede_lease (lease, 0, 1, 1, 1))
lease -> flags |= ABANDONED_LEASE; return ISC_R_SUCCESS;
else return ISC_R_IOERROR;
lease -> flags &= ~ABANDONED_LEASE; }
if (foo != lease -> flags)
return ISC_R_SUCCESS;
return ISC_R_UNCHANGED; return ISC_R_UNCHANGED;
} }
@ -226,14 +220,9 @@ isc_result_t dhcp_lease_get_value (omapi_object_t *h, omapi_object_t *id,
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
lease = (struct lease *)h; lease = (struct lease *)h;
if (!omapi_ds_strcmp (name, "abandoned")) if (!omapi_ds_strcmp (name, "state"))
return omapi_make_int_value (value, name, return omapi_make_int_value (value, name,
(lease -> flags & (int)lease -> binding_state, MDL);
ABANDONED_LEASE) ? 1 : 0, MDL);
else if (!omapi_ds_strcmp (name, "bootpp"))
return omapi_make_int_value (value, name,
(lease -> flags &
BOOTP_LEASE) ? 1 : 0, MDL);
else if (!omapi_ds_strcmp (name, "ip-address")) else if (!omapi_ds_strcmp (name, "ip-address"))
return omapi_make_const_value (value, name, return omapi_make_const_value (value, name,
lease -> ip_addr.iabuf, lease -> ip_addr.iabuf,
@ -362,7 +351,7 @@ isc_result_t dhcp_lease_signal_handler (omapi_object_t *h,
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
if (!write_lease (lease) || !commit_leases () if (!write_lease (lease) || !commit_leases ()
#if defined (FAILOVER_PROTOCOL) #if defined (FAILOVER_PROTOCOL)
|| !dhcp_failover_queue_update (lease) || !dhcp_failover_queue_update (lease, 1)
#endif #endif
) { ) {
return ISC_R_IOERROR; return ISC_R_IOERROR;
@ -395,26 +384,13 @@ isc_result_t dhcp_lease_stuff_values (omapi_object_t *c,
/* Write out all the values. */ /* Write out all the values. */
status = omapi_connection_put_name (c, "abandoned"); status = omapi_connection_put_name (c, "state");
if (status != ISC_R_SUCCESS) if (status != ISC_R_SUCCESS)
return status; return status;
status = omapi_connection_put_uint32 (c, sizeof (int)); status = omapi_connection_put_uint32 (c, sizeof (int));
if (status != ISC_R_SUCCESS) if (status != ISC_R_SUCCESS)
return status; return status;
status = omapi_connection_put_uint32 (c, (lease -> flags & status = omapi_connection_put_uint32 (c, lease -> binding_state);
ABANDONED_LEASE) ? 1U : 0U);
if (status != ISC_R_SUCCESS)
return status;
status = omapi_connection_put_name (c, "bootpp");
if (status != ISC_R_SUCCESS)
return status;
status = omapi_connection_put_uint32 (c, sizeof (int));
if (status != ISC_R_SUCCESS)
return status;
status = omapi_connection_put_uint32 (c, ((unsigned)
((lease -> flags &
BOOTP_LEASE) ? 1 : 0)));
if (status != ISC_R_SUCCESS) if (status != ISC_R_SUCCESS)
return status; return status;

View File

@ -43,7 +43,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: stables.c,v 1.12 2000/05/16 23:03:49 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n"; "$Id: stables.c,v 1.13 2000/06/02 21:27:21 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@ -176,6 +176,12 @@ const char *dhcp_flink_state_names [] = {
}; };
#endif /* FAILOVER_PROTOCOL */ #endif /* FAILOVER_PROTOCOL */
/* Failover binding state names. These are used even if there is no
failover protocol support. */
const char *binding_state_names [] = {
"free", "active", "expired", "released", "abandoned",
"reset", "backup", "reserved", "bootp" };
struct universe agent_universe; struct universe agent_universe;
struct option agent_options [256] = { struct option agent_options [256] = {
{ "pad", "", &agent_universe, 0 }, { "pad", "", &agent_universe, 0 },