summaryrefslogtreecommitdiffstats
path: root/contrib/isc-dhcp/client
diff options
context:
space:
mode:
authormurray <murray@FreeBSD.org>2002-02-19 11:04:34 +0000
committermurray <murray@FreeBSD.org>2002-02-19 11:04:34 +0000
commit57b30d23e7c11fa1a8c8c23f27de40971872952f (patch)
tree229464d9b3244ab78e2784c9a0a1f78de317089a /contrib/isc-dhcp/client
parent7acb11388cf5d680b16902b8ed6f46c46dc4d47b (diff)
downloadFreeBSD-src-57b30d23e7c11fa1a8c8c23f27de40971872952f.zip
FreeBSD-src-57b30d23e7c11fa1a8c8c23f27de40971872952f.tar.gz
Import ISC DHCP 3.0.1 RC6 client.
Diffstat (limited to 'contrib/isc-dhcp/client')
-rw-r--r--contrib/isc-dhcp/client/Makefile.dist76
-rw-r--r--contrib/isc-dhcp/client/clparse.c1139
-rw-r--r--contrib/isc-dhcp/client/dhclient-script.860
-rw-r--r--contrib/isc-dhcp/client/dhclient.8250
-rw-r--r--contrib/isc-dhcp/client/dhclient.c3061
-rw-r--r--contrib/isc-dhcp/client/dhclient.conf.5120
-rw-r--r--contrib/isc-dhcp/client/dhclient.leases.58
-rwxr-xr-xcontrib/isc-dhcp/client/scripts/freebsd100
8 files changed, 3009 insertions, 1805 deletions
diff --git a/contrib/isc-dhcp/client/Makefile.dist b/contrib/isc-dhcp/client/Makefile.dist
index 2b261a7..a1f8a38 100644
--- a/contrib/isc-dhcp/client/Makefile.dist
+++ b/contrib/isc-dhcp/client/Makefile.dist
@@ -1,33 +1,20 @@
# Makefile.dist
#
-# Copyright (c) 1996, 1997, 1999 The Internet Software Consortium.
-# All rights reserved.
+# Copyright (c) 1996-1999 Internet Software Consortium.
+# Use is subject to license terms which appear in the file named
+# ISC-LICENSE that should have accompanied this file when you
+# received it. If a file named ISC-LICENSE did not accompany this
+# file, or you are not sure the one you have is correct, you may
+# obtain an applicable copy of the license at:
#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
+# http://www.isc.org/isc-license-1.0.html.
#
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-# 3. Neither the name of The Internet Software Consortium nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
+# This file is part of the ISC DHCP distribution. The documentation
+# associated with this file is listed in the file DOCUMENTATION,
+# included in the top-level directory of this release.
#
-# THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
-# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
-# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
-# THE INTERNET SOFTWARE CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
-# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
-# OF THE POSSIBILITY OF SUCH DAMAGE.
+# Support and other services are available for ISC products - see
+# http://www.isc.org for more information.
#
CATMANPAGES = dhclient.cat8 dhclient.conf.cat5 dhclient-script.cat8 \
@@ -39,9 +26,8 @@ OBJS = dhclient.o clparse.o
PROG = dhclient
MAN = dhclient.8 dhclient.conf.5 dhclient-script.8 dhclient.leases.5
-DEBUG = -g
-INCLUDES = -I.. -I../includes
-DHCPLIB = ../common/libdhcp.a
+INCLUDES = -I$(TOP) $(BINDINC) -I$(TOP)/includes
+DHCPLIB = ../common/libdhcp.a $(BINDLIB) ../omapip/libomapi.a ../dst/libdst.a
CFLAGS = $(DEBUG) $(PREDEFINES) $(INCLUDES) $(COPTS) \
-DCLIENT_PATH=${CLIENT_PATH}
@@ -64,8 +50,9 @@ install: all
if [ x$(SCRIPT) = xnone ]; then \
echo "No client script available."; \
else \
- $(INSTALL) scripts/$(SCRIPT) $(DESTDIR)$(ETC)/dhclient-script; \
- $(CHMOD) 700 $(DESTDIR)$(ETC)/dhclient-script; \
+ $(INSTALL) $(TOP)/client/scripts/$(SCRIPT)\
+ $(DESTDIR)$(CLIENTBINDIR)/dhclient-script; \
+ $(CHMOD) 700 $(DESTDIR)$(CLIENTBINDIR)/dhclient-script; \
fi
$(MANINSTALL) $(MANFROM) dhclient.$(MANCAT)8 $(MANTO) \
$(DESTDIR)$(ADMMANDIR)/dhclient$(ADMMANEXT)
@@ -76,15 +63,26 @@ install: all
$(MANINSTALL) $(MANFROM) dhclient.leases.$(MANCAT)5 $(MANTO) \
$(DESTDIR)$(FFMANDIR)/dhclient.leases$(FFMANEXT)
+depend:
+ $(MKDEP) $(INCLUDES) $(PREDEFINES) $(SRCS)
+
clean:
-rm -f $(OBJS)
-
+
realclean: clean
-rm -f $(PROG) $(CATMANPAGES) $(SEDMANPAGES) *~ #*
distclean: realclean
-rm -f Makefile
+links:
+ @for foo in $(SRCS) $(MAN); do \
+ if [ ! -b $$foo ]; then \
+ rm -f $$foo; \
+ fi; \
+ ln -s $(TOP)/client/$$foo $$foo; \
+ done
+
# These should only be done on 4.4 BSD-based systems, since the mandoc
# macros aren't available on older unices. Catted man pages are
# provided in the distribution so that this doesn't become a problem.
@@ -94,6 +92,7 @@ dhclient.cat8: dhclient.man8
dhclient.man8: dhclient.8
sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \
+ -e "s#CLIENTBINDIR#$(CLIENTBINDIR)#g" \
-e "s#RUNDIR#$(VARRUN)#g" < dhclient.8 >dhclient.man8
dhclient-script.cat8: dhclient-script.man8
@@ -101,11 +100,13 @@ dhclient-script.cat8: dhclient-script.man8
dhclient-script.man8: dhclient-script.8
sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \
+ -e "s#CLIENTBINDIR#$(CLIENTBINDIR)#g" \
-e "s#RUNDIR#$(VARRUN)#g" < dhclient-script.8 \
>dhclient-script.man8
dhclient.conf.man5: dhclient.conf.5
sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \
+ -e "s#CLIENTBINDIR#$(CLIENTBINDIR)#g" \
-e "s#RUNDIR#$(VARRUN)#g" < dhclient.conf.5 \
>dhclient.conf.man5
@@ -114,24 +115,15 @@ dhclient.conf.cat5: dhclient.conf.man5
dhclient.leases.man5: dhclient.leases.5
sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \
+ -e "s#CLIENTBINDIR#$(CLIENTBINDIR)#g" \
-e "s#RUNDIR#$(VARRUN)#g" < dhclient.leases.5 \
>dhclient.leases.man5
dhclient.leases.cat5: dhclient.leases.man5
nroff -man dhclient.leases.man5 >dhclient.leases.cat5
+
dhclient: $(OBJS) $(DHCPLIB)
$(CC) $(LFLAGS) -o $(PROG) $(OBJS) $(DHCPLIB) $(LIBS)
# Dependencies (semi-automatically-generated)
-
-dhclient.o: dhclient.c ../includes/dhcpd.h \
- ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \
- ../includes/cf/netbsd.h ../includes/dhcp.h \
- ../includes/tree.h ../includes/hash.h ../includes/inet.h \
- ../includes/sysconf.h ../includes/version.h
-clparse.o: clparse.c ../includes/dhcpd.h \
- ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \
- ../includes/cf/netbsd.h ../includes/dhcp.h \
- ../includes/tree.h ../includes/hash.h ../includes/inet.h \
- ../includes/sysconf.h ../includes/dhctoken.h
diff --git a/contrib/isc-dhcp/client/clparse.c b/contrib/isc-dhcp/client/clparse.c
index 9af7744..7cd8529 100644
--- a/contrib/isc-dhcp/client/clparse.c
+++ b/contrib/isc-dhcp/client/clparse.c
@@ -3,7 +3,7 @@
Parser for dhclient config and lease files... */
/*
- * Copyright (c) 1997 The Internet Software Consortium.
+ * Copyright (c) 1996-2001 Internet Software Consortium.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,41 +34,49 @@
* SUCH DAMAGE.
*
* This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
*/
#ifndef lint
static char copyright[] =
-"$Id: clparse.c,v 1.13.2.5 2000/07/20 05:06:40 mellon Exp $ Copyright (c) 1997 The Internet Software Consortium. All rights reserved.\n";
+"$Id: clparse.c,v 1.62.2.1 2001/06/01 17:26:44 mellon Exp $ Copyright (c) 1996-2001 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
-#include "dhctoken.h"
-struct client_config top_level_config;
+static TIME parsed_time;
-char client_script_name [] = "/etc/dhclient-script";
+struct client_config top_level_config;
-/* client-conf-file :== client-declarations EOF
+u_int32_t default_requested_options [] = {
+ DHO_SUBNET_MASK,
+ DHO_BROADCAST_ADDRESS,
+ DHO_TIME_OFFSET,
+ DHO_ROUTERS,
+ DHO_DOMAIN_NAME,
+ DHO_DOMAIN_NAME_SERVERS,
+ DHO_HOST_NAME,
+ 0
+};
+
+/* client-conf-file :== client-declarations END_OF_FILE
client-declarations :== <nil>
| client-declaration
| client-declarations client-declaration */
-int read_client_conf ()
+isc_result_t read_client_conf ()
{
- FILE *cfile;
- char *val;
- int token;
struct client_config *config;
+ struct client_state *state;
struct interface_info *ip;
-
- new_parse (path_dhclient_conf);
+ isc_result_t status;
/* Set up the initial dhcp option universe. */
- initialize_universes ();
+ initialize_common_option_spaces ();
/* Initialize the top level client configuration. */
memset (&top_level_config, 0, sizeof top_level_config);
@@ -80,98 +88,138 @@ int read_client_conf ()
top_level_config.retry_interval = 300;
top_level_config.backoff_cutoff = 15;
top_level_config.initial_interval = 3;
- top_level_config.bootp_policy = ACCEPT;
- top_level_config.script_name = client_script_name;
- top_level_config.requested_options
- [top_level_config.requested_option_count++] =
- DHO_SUBNET_MASK;
- top_level_config.requested_options
- [top_level_config.requested_option_count++] =
- DHO_BROADCAST_ADDRESS;
- top_level_config.requested_options
- [top_level_config.requested_option_count++] =
- DHO_TIME_OFFSET;
- top_level_config.requested_options
- [top_level_config.requested_option_count++] =
- DHO_ROUTERS;
- top_level_config.requested_options
- [top_level_config.requested_option_count++] =
- DHO_DOMAIN_NAME;
- top_level_config.requested_options
- [top_level_config.requested_option_count++] =
- DHO_DOMAIN_NAME_SERVERS;
- top_level_config.requested_options
- [top_level_config.requested_option_count++] =
- DHO_HOST_NAME;
-
- if ((cfile = fopen (path_dhclient_conf, "r")) != NULL) {
+ top_level_config.bootp_policy = P_ACCEPT;
+ top_level_config.script_name = path_dhclient_script;
+ top_level_config.requested_options = default_requested_options;
+ top_level_config.omapi_port = -1;
+
+ group_allocate (&top_level_config.on_receipt, MDL);
+ if (!top_level_config.on_receipt)
+ log_fatal ("no memory for top-level on_receipt group");
+
+ group_allocate (&top_level_config.on_transmission, MDL);
+ if (!top_level_config.on_transmission)
+ log_fatal ("no memory for top-level on_transmission group");
+
+ status = read_client_conf_file (path_dhclient_conf,
+ (struct interface_info *)0,
+ &top_level_config);
+ if (status != ISC_R_SUCCESS) {
+ ;
+#ifdef LATER
+ /* Set up the standard name service updater routine. */
+ parse = (struct parse *)0;
+ status = new_parse (&parse, -1, default_client_config,
+ (sizeof default_client_config) - 1,
+ "default client configuration", 0);
+ if (status != ISC_R_SUCCESS)
+ log_fatal ("can't begin default client config!");
+
do {
- token = peek_token (&val, cfile);
- if (token == EOF)
+ token = peek_token (&val, (unsigned *)0, cfile);
+ if (token == END_OF_FILE)
break;
parse_client_statement (cfile,
(struct interface_info *)0,
&top_level_config);
} while (1);
- token = next_token (&val, cfile); /* Clear the peek buffer */
- fclose (cfile);
+ end_parse (&parse);
+#endif
}
/* Set up state and config structures for clients that don't
- have per-interface configuration declarations. */
+ have per-interface configuration statements. */
config = (struct client_config *)0;
for (ip = interfaces; ip; ip = ip -> next) {
if (!ip -> client) {
ip -> client = (struct client_state *)
- malloc (sizeof (struct client_state));
+ dmalloc (sizeof (struct client_state), MDL);
if (!ip -> client)
- error ("no memory for client state.");
+ log_fatal ("no memory for client state.");
memset (ip -> client, 0, sizeof *(ip -> client));
+ ip -> client -> interface = ip;
}
+
if (!ip -> client -> config) {
if (!config) {
config = (struct client_config *)
- malloc (sizeof (struct client_config));
+ dmalloc (sizeof (struct client_config),
+ MDL);
if (!config)
- error ("no memory for client config.");
+ log_fatal ("no memory for client config.");
memcpy (config, &top_level_config,
sizeof top_level_config);
}
ip -> client -> config = config;
}
}
+ return status;
+}
+
+int read_client_conf_file (const char *name, struct interface_info *ip,
+ struct client_config *client)
+{
+ int file;
+ struct parse *cfile;
+ const char *val;
+ int token;
+ isc_result_t status;
+
+ if ((file = open (name, O_RDONLY)) < 0)
+ return uerr2isc (errno);
+
+ cfile = (struct parse *)0;
+ new_parse (&cfile, file, (char *)0, 0, path_dhclient_conf, 0);
- return !warnings_occurred;
+ do {
+ token = peek_token (&val, (unsigned *)0, cfile);
+ if (token == END_OF_FILE)
+ break;
+ parse_client_statement (cfile, ip, client);
+ } while (1);
+ token = next_token (&val, (unsigned *)0, cfile);
+ status = (cfile -> warnings_occurred
+ ? ISC_R_BADPARSE
+ : ISC_R_SUCCESS);
+ close (file);
+ end_parse (&cfile);
+ return status;
}
-/* lease-file :== client-lease-statements EOF
+
+/* lease-file :== client-lease-statements END_OF_FILE
client-lease-statements :== <nil>
| client-lease-statements LEASE client-lease-statement */
void read_client_leases ()
{
- FILE *cfile;
- char *val;
+ int file;
+ struct parse *cfile;
+ const char *val;
int token;
- new_parse (path_dhclient_db);
-
/* Open the lease file. If we can't open it, just return -
we can safely trust the server to remember our state. */
- if ((cfile = fopen (path_dhclient_db, "r")) == NULL)
+ if ((file = open (path_dhclient_db, O_RDONLY)) < 0)
return;
+ cfile = (struct parse *)0;
+ new_parse (&cfile, file, (char *)0, 0, path_dhclient_db, 0);
+
do {
- token = next_token (&val, cfile);
- if (token == EOF)
+ token = next_token (&val, (unsigned *)0, cfile);
+ if (token == END_OF_FILE)
break;
if (token != LEASE) {
- warn ("Corrupt lease file - possible data loss!");
+ log_error ("Corrupt lease file - possible data loss!");
skip_to_semi (cfile);
break;
} else
parse_client_lease_statement (cfile, 0);
} while (1);
+
+ close (file);
+ end_parse (&cfile);
}
/* client-declaration :==
@@ -188,332 +236,569 @@ void read_client_leases ()
REBOOT number |
SELECT_TIMEOUT number |
SCRIPT string |
+ VENDOR_SPACE string |
interface-declaration |
LEASE client-lease-statement |
- ALIAS client-lease-statement */
+ ALIAS client-lease-statement |
+ KEY key-definition */
void parse_client_statement (cfile, ip, config)
- FILE *cfile;
+ struct parse *cfile;
struct interface_info *ip;
struct client_config *config;
{
int token;
- char *val;
+ const char *val;
struct option *option;
-
- switch (next_token (&val, cfile)) {
- case SEND:
- parse_option_decl (cfile, &config -> send_options [0]);
+ struct executable_statement *stmt, **p;
+ enum statement_op op;
+ int lose;
+ char *name;
+ struct data_string key_id;
+ enum policy policy;
+ int known;
+ int tmp, i;
+ isc_result_t status;
+
+ switch (peek_token (&val, (unsigned *)0, cfile)) {
+ case INCLUDE:
+ next_token (&val, (unsigned *)0, cfile);
+ token = next_token (&val, (unsigned *)0, cfile);
+ if (token != STRING) {
+ parse_warn (cfile, "filename string expected.");
+ skip_to_semi (cfile);
+ } else {
+ status = read_client_conf_file (val, ip, config);
+ if (status != ISC_R_SUCCESS)
+ parse_warn (cfile, "%s: bad parse.", val);
+ parse_semi (cfile);
+ }
return;
-
- case DEFAULT:
- option = parse_option_decl (cfile, &config -> defaults [0]);
- if (option)
- config -> default_actions [option -> code] =
- ACTION_DEFAULT;
+
+ case KEY:
+ next_token (&val, (unsigned *)0, cfile);
+ if (ip) {
+ /* This may seem arbitrary, but there's a reason for
+ doing it: the authentication key database is not
+ scoped. If we allow the user to declare a key other
+ than in the outer scope, the user is very likely to
+ believe that the key will only be used in that
+ scope. If the user only wants the key to be used on
+ one interface, because it's known that the other
+ interface may be connected to an insecure net and
+ the secret key is considered sensitive, we don't
+ want to lull them into believing they've gotten
+ their way. This is a bit contrived, but people
+ tend not to be entirely rational about security. */
+ parse_warn (cfile, "key definition not allowed here.");
+ skip_to_semi (cfile);
+ break;
+ }
+ parse_key (cfile);
return;
- case SUPERSEDE:
- option = parse_option_decl (cfile, &config -> defaults [0]);
- if (option)
- config -> default_actions [option -> code] =
- ACTION_SUPERSEDE;
+ /* REQUIRE can either start a policy statement or a
+ comma-seperated list of names of required options. */
+ case REQUIRE:
+ next_token (&val, (unsigned *)0, cfile);
+ token = peek_token (&val, (unsigned *)0, cfile);
+ if (token == AUTHENTICATION) {
+ policy = P_REQUIRE;
+ goto do_policy;
+ }
+ parse_option_list (cfile, &config -> required_options);
return;
- case APPEND:
- option = parse_option_decl (cfile, &config -> defaults [0]);
- if (option)
- config -> default_actions [option -> code] =
- ACTION_APPEND;
- return;
+ case IGNORE:
+ next_token (&val, (unsigned *)0, cfile);
+ policy = P_IGNORE;
+ goto do_policy;
+
+ case ACCEPT:
+ next_token (&val, (unsigned *)0, cfile);
+ policy = P_ACCEPT;
+ goto do_policy;
+
+ case PREFER:
+ next_token (&val, (unsigned *)0, cfile);
+ policy = P_PREFER;
+ goto do_policy;
+
+ case DONT:
+ next_token (&val, (unsigned *)0, cfile);
+ policy = P_DONT;
+ goto do_policy;
+
+ do_policy:
+ token = next_token (&val, (unsigned *)0, cfile);
+ if (token == AUTHENTICATION) {
+ if (policy != P_PREFER &&
+ policy != P_REQUIRE &&
+ policy != P_DONT) {
+ parse_warn (cfile,
+ "invalid authentication policy.");
+ skip_to_semi (cfile);
+ return;
+ }
+ config -> auth_policy = policy;
+ } else if (token != TOKEN_BOOTP) {
+ if (policy != P_PREFER &&
+ policy != P_IGNORE &&
+ policy != P_ACCEPT) {
+ parse_warn (cfile, "invalid bootp policy.");
+ skip_to_semi (cfile);
+ return;
+ }
+ config -> bootp_policy = policy;
+ } else {
+ parse_warn (cfile, "expecting a policy type.");
+ skip_to_semi (cfile);
+ return;
+ }
+ break;
+
+ case OPTION:
+ token = next_token (&val, (unsigned *)0, cfile);
+
+ token = peek_token (&val, (unsigned *)0, cfile);
+ if (token == SPACE) {
+ if (ip) {
+ parse_warn (cfile,
+ "option space definitions %s",
+ " may not be scoped.");
+ skip_to_semi (cfile);
+ break;
+ }
+ parse_option_space_decl (cfile);
+ return;
+ }
+
+ option = parse_option_name (cfile, 1, &known);
+ if (!option)
+ return;
- case PREPEND:
- option = parse_option_decl (cfile, &config -> defaults [0]);
- if (option)
- config -> default_actions [option -> code] =
- ACTION_PREPEND;
+ token = next_token (&val, (unsigned *)0, cfile);
+ if (token != CODE) {
+ parse_warn (cfile, "expecting \"code\" keyword.");
+ skip_to_semi (cfile);
+ free_option (option, MDL);
+ return;
+ }
+ if (ip) {
+ parse_warn (cfile,
+ "option definitions may only appear in %s",
+ "the outermost scope.");
+ skip_to_semi (cfile);
+ free_option (option, MDL);
+ return;
+ }
+ if (!parse_option_code_definition (cfile, option))
+ free_option (option, MDL);
return;
case MEDIA:
+ token = next_token (&val, (unsigned *)0, cfile);
parse_string_list (cfile, &config -> media, 1);
return;
case HARDWARE:
+ token = next_token (&val, (unsigned *)0, cfile);
if (ip) {
parse_hardware_param (cfile, &ip -> hw_address);
} else {
- parse_warn ("hardware address parameter %s",
+ parse_warn (cfile, "hardware address parameter %s",
"not allowed here.");
skip_to_semi (cfile);
}
return;
case REQUEST:
- config -> requested_option_count =
- parse_option_list (cfile, config -> requested_options);
- return;
-
- case REQUIRE:
- memset (config -> required_options, 0,
- sizeof config -> required_options);
- parse_option_list (cfile, config -> required_options);
+ token = next_token (&val, (unsigned *)0, cfile);
+ if (config -> requested_options == default_requested_options)
+ config -> requested_options = (u_int32_t *)0;
+ parse_option_list (cfile, &config -> requested_options);
return;
case TIMEOUT:
+ token = next_token (&val, (unsigned *)0, cfile);
parse_lease_time (cfile, &config -> timeout);
return;
case RETRY:
+ token = next_token (&val, (unsigned *)0, cfile);
parse_lease_time (cfile, &config -> retry_interval);
return;
case SELECT_TIMEOUT:
+ token = next_token (&val, (unsigned *)0, cfile);
parse_lease_time (cfile, &config -> select_interval);
return;
+ case OMAPI:
+ token = next_token (&val, (unsigned *)0, cfile);
+ token = next_token (&val, (unsigned *)0, cfile);
+ if (token != PORT) {
+ parse_warn (cfile,
+ "unexpected omapi subtype: %s", val);
+ skip_to_semi (cfile);
+ return;
+ }
+ token = next_token (&val, (unsigned *)0, cfile);
+ if (token != NUMBER) {
+ parse_warn (cfile, "invalid port number: `%s'", val);
+ skip_to_semi (cfile);
+ return;
+ }
+ tmp = atoi (val);
+ if (tmp < 0 || tmp > 65535)
+ parse_warn (cfile, "invalid omapi port %d.", tmp);
+ else if (config != &top_level_config)
+ parse_warn (cfile,
+ "omapi port only works at top level.");
+ else
+ config -> omapi_port = tmp;
+ parse_semi (cfile);
+ return;
+
case REBOOT:
+ token = next_token (&val, (unsigned *)0, cfile);
parse_lease_time (cfile, &config -> reboot_timeout);
return;
case BACKOFF_CUTOFF:
+ token = next_token (&val, (unsigned *)0, cfile);
parse_lease_time (cfile, &config -> backoff_cutoff);
return;
case INITIAL_INTERVAL:
+ token = next_token (&val, (unsigned *)0, cfile);
parse_lease_time (cfile, &config -> initial_interval);
return;
case SCRIPT:
- config -> script_name = parse_string (cfile);
+ token = next_token (&val, (unsigned *)0, cfile);
+ parse_string (cfile, &config -> script_name, (unsigned *)0);
+ return;
+
+ case VENDOR:
+ token = next_token (&val, (unsigned *)0, cfile);
+ token = next_token (&val, (unsigned *)0, cfile);
+ if (token != OPTION) {
+ parse_warn (cfile, "expecting 'vendor option space'");
+ skip_to_semi (cfile);
+ return;
+ }
+ token = next_token (&val, (unsigned *)0, cfile);
+ if (token != SPACE) {
+ parse_warn (cfile, "expecting 'vendor option space'");
+ skip_to_semi (cfile);
+ return;
+ }
+ token = next_token (&val, (unsigned *)0, cfile);
+ if (!is_identifier (token)) {
+ parse_warn (cfile, "expecting an identifier.");
+ skip_to_semi (cfile);
+ return;
+ }
+ config -> vendor_space_name = dmalloc (strlen (val) + 1, MDL);
+ if (!config -> vendor_space_name)
+ log_fatal ("no memory for vendor option space name.");
+ strcpy (config -> vendor_space_name, val);
+ for (i = 0; i < universe_count; i++)
+ if (!strcmp (universes [i] -> name,
+ config -> vendor_space_name))
+ break;
+ if (i == universe_count) {
+ log_error ("vendor option space %s not found.",
+ config -> vendor_space_name);
+ }
+ parse_semi (cfile);
return;
case INTERFACE:
+ token = next_token (&val, (unsigned *)0, cfile);
if (ip)
- parse_warn ("nested interface declaration.");
- parse_interface_declaration (cfile, config);
+ parse_warn (cfile, "nested interface declaration.");
+ parse_interface_declaration (cfile, config, (char *)0);
return;
+ case PSEUDO:
+ token = next_token (&val, (unsigned *)0, cfile);
+ token = next_token (&val, (unsigned *)0, cfile);
+ name = dmalloc (strlen (val) + 1, MDL);
+ if (!name)
+ log_fatal ("no memory for pseudo interface name");
+ strcpy (name, val);
+ parse_interface_declaration (cfile, config, name);
+ return;
+
case LEASE:
+ token = next_token (&val, (unsigned *)0, cfile);
parse_client_lease_statement (cfile, 1);
return;
case ALIAS:
+ token = next_token (&val, (unsigned *)0, cfile);
parse_client_lease_statement (cfile, 2);
return;
case REJECT:
+ token = next_token (&val, (unsigned *)0, cfile);
parse_reject_statement (cfile, config);
return;
default:
- parse_warn ("expecting a statement.");
- skip_to_semi (cfile);
- break;
- }
- token = next_token (&val, cfile);
- if (token != SEMI) {
- parse_warn ("semicolon expected.");
- skip_to_semi (cfile);
- }
-}
-
-int parse_X (cfile, buf, max)
- FILE *cfile;
- u_int8_t *buf;
- int max;
-{
- int token;
- char *val;
- int len;
-
- token = peek_token (&val, cfile);
- if (token == NUMBER_OR_NAME || token == NUMBER) {
- len = 0;
- do {
- token = next_token (&val, cfile);
- if (token != NUMBER && token != NUMBER_OR_NAME) {
- parse_warn ("expecting hexadecimal constant.");
+ lose = 0;
+ stmt = (struct executable_statement *)0;
+ if (!parse_executable_statement (&stmt,
+ cfile, &lose, context_any)) {
+ if (!lose) {
+ parse_warn (cfile, "expecting a statement.");
skip_to_semi (cfile);
- return 0;
}
- convert_num (&buf [len], val, 16, 8);
- if (len++ > max) {
- parse_warn ("hexadecimal constant too long.");
- skip_to_semi (cfile);
- return 0;
+ } else {
+ struct executable_statement **eptr, *sptr;
+ if (stmt &&
+ (stmt -> op == send_option_statement ||
+ (stmt -> op == on_statement &&
+ (stmt -> data.on.evtypes & ON_TRANSMISSION)))) {
+ eptr = &config -> on_transmission -> statements;
+ if (stmt -> op == on_statement) {
+ sptr = (struct executable_statement *)0;
+ executable_statement_reference
+ (&sptr,
+ stmt -> data.on.statements, MDL);
+ executable_statement_dereference (&stmt,
+ MDL);
+ executable_statement_reference (&stmt,
+ sptr,
+ MDL);
+ executable_statement_dereference (&sptr,
+ MDL);
+ }
+ } else
+ eptr = &config -> on_receipt -> statements;
+
+ if (stmt) {
+ for (; *eptr; eptr = &(*eptr) -> next)
+ ;
+ executable_statement_reference (eptr,
+ stmt, MDL);
}
- token = peek_token (&val, cfile);
- if (token == COLON)
- token = next_token (&val, cfile);
- } while (token == COLON);
- val = (char *)buf;
- } else if (token == STRING) {
- token = next_token (&val, cfile);
- len = strlen (val);
- if (len + 1 > max) {
- parse_warn ("string constant too long.");
- skip_to_semi (cfile);
- return 0;
+ return;
}
- memcpy (buf, val, len + 1);
- } else {
- parse_warn ("expecting string or hexadecimal data");
- skip_to_semi (cfile);
- return 0;
+ break;
}
- return len;
+ parse_semi (cfile);
}
/* option-list :== option_name |
option_list COMMA option_name */
-int parse_option_list (cfile, list)
- FILE *cfile;
- u_int8_t *list;
+void parse_option_list (cfile, list)
+ struct parse *cfile;
+ u_int32_t **list;
{
int ix, i;
int token;
- char *val;
+ const char *val;
+ pair p = (pair)0, q, r;
ix = 0;
do {
- token = next_token (&val, cfile);
+ token = next_token (&val, (unsigned *)0, cfile);
+ if (token == SEMI)
+ break;
if (!is_identifier (token)) {
- parse_warn ("expected option name.");
+ parse_warn (cfile, "%s: expected option name.", val);
skip_to_semi (cfile);
- return 0;
+ return;
}
for (i = 0; i < 256; i++) {
if (!strcasecmp (dhcp_options [i].name, val))
break;
}
if (i == 256) {
- parse_warn ("%s: expected option name.");
- skip_to_semi (cfile);
- return 0;
- }
- list [ix++] = i;
- if (ix == 256) {
- parse_warn ("%s: too many options.", val);
+ parse_warn (cfile, "%s: expected option name.", val);
skip_to_semi (cfile);
- return 0;
+ return;
}
- token = next_token (&val, cfile);
+ r = new_pair (MDL);
+ if (!r)
+ log_fatal ("can't allocate pair for option code.");
+ r -> car = (caddr_t)(long)i;
+ r -> cdr = (pair)0;
+ if (p)
+ q -> cdr = r;
+ else
+ p = r;
+ q = r;
+ ++ix;
+ token = next_token (&val, (unsigned *)0, cfile);
} while (token == COMMA);
if (token != SEMI) {
- parse_warn ("expecting semicolon.");
+ parse_warn (cfile, "expecting semicolon.");
skip_to_semi (cfile);
- return 0;
+ return;
+ }
+ /* XXX we can't free the list here, because we may have copied
+ XXX it from an outer config state. */
+ *list = (u_int32_t *)0;
+ if (ix) {
+ *list = dmalloc ((ix + 1) * sizeof **list, MDL);
+ if (!*list)
+ log_error ("no memory for option list.");
+ else {
+ ix = 0;
+ for (q = p; q; q = q -> cdr)
+ (*list) [ix++] = (u_int32_t)(long)q -> car;
+ (*list) [ix] = 0;
+ }
+ while (p) {
+ q = p -> cdr;
+ free_pair (p, MDL);
+ p = q;
+ }
}
- return ix;
}
/* interface-declaration :==
INTERFACE string LBRACE client-declarations RBRACE */
-void parse_interface_declaration (cfile, outer_config)
- FILE *cfile;
+void parse_interface_declaration (cfile, outer_config, name)
+ struct parse *cfile;
struct client_config *outer_config;
+ char *name;
{
int token;
- char *val;
+ const char *val;
+ struct client_state *client, **cp;
+ struct interface_info *ip = (struct interface_info *)0;
- struct interface_info *ip;
-
- token = next_token (&val, cfile);
+ token = next_token (&val, (unsigned *)0, cfile);
if (token != STRING) {
- parse_warn ("expecting interface name (in quotes).");
+ parse_warn (cfile, "expecting interface name (in quotes).");
skip_to_semi (cfile);
return;
}
- ip = interface_or_dummy (val);
+ if (!interface_or_dummy (&ip, val))
+ log_fatal ("Can't allocate interface %s.", val);
- if (!ip -> client)
- make_client_state (ip);
+ /* If we were given a name, this is a pseudo-interface. */
+ if (name) {
+ make_client_state (&client);
+ client -> name = name;
+ client -> interface = ip;
+ for (cp = &ip -> client; *cp; cp = &((*cp) -> next))
+ ;
+ *cp = client;
+ } else {
+ if (!ip -> client) {
+ make_client_state (&ip -> client);
+ ip -> client -> interface = ip;
+ }
+ client = ip -> client;
+ }
- if (!ip -> client -> config)
- make_client_config (ip, outer_config);
+ if (!client -> config)
+ make_client_config (client, outer_config);
ip -> flags &= ~INTERFACE_AUTOMATIC;
interfaces_requested = 1;
- token = next_token (&val, cfile);
+ token = next_token (&val, (unsigned *)0, cfile);
if (token != LBRACE) {
- parse_warn ("expecting left brace.");
+ parse_warn (cfile, "expecting left brace.");
skip_to_semi (cfile);
return;
}
do {
- token = peek_token (&val, cfile);
- if (token == EOF) {
- parse_warn ("unterminated interface declaration.");
+ token = peek_token (&val, (unsigned *)0, cfile);
+ if (token == END_OF_FILE) {
+ parse_warn (cfile,
+ "unterminated interface declaration.");
return;
}
if (token == RBRACE)
break;
- parse_client_statement (cfile, ip, ip -> client -> config);
+ parse_client_statement (cfile, ip, client -> config);
} while (1);
- token = next_token (&val, cfile);
+ token = next_token (&val, (unsigned *)0, cfile);
}
-struct interface_info *interface_or_dummy (name)
- char *name;
+int interface_or_dummy (struct interface_info **pi, const char *name)
{
- struct interface_info *ip;
+ struct interface_info *i;
+ struct interface_info *ip = (struct interface_info *)0;
+ isc_result_t status;
/* Find the interface (if any) that matches the name. */
- for (ip = interfaces; ip; ip = ip -> next) {
- if (!strcmp (ip -> name, name))
+ for (i = interfaces; i; i = i -> next) {
+ if (!strcmp (i -> name, name)) {
+ interface_reference (&ip, i, MDL);
break;
+ }
}
/* If it's not a real interface, see if it's on the dummy list. */
if (!ip) {
for (ip = dummy_interfaces; ip; ip = ip -> next) {
- if (!strcmp (ip -> name, name))
+ if (!strcmp (ip -> name, name)) {
+ interface_reference (&ip, i, MDL);
break;
+ }
}
}
/* If we didn't find an interface, make a dummy interface as
a placeholder. */
if (!ip) {
- ip = ((struct interface_info *)malloc (sizeof *ip));
- if (!ip)
- error ("Insufficient memory to record interface %s",
- name);
- memset (ip, 0, sizeof *ip);
+ isc_result_t status;
+ status = interface_allocate (&ip, MDL);
+ if (status != ISC_R_SUCCESS)
+ log_fatal ("Can't record interface %s: %s",
+ name, isc_result_totext (status));
strcpy (ip -> name, name);
- ip -> next = dummy_interfaces;
- dummy_interfaces = ip;
+ if (dummy_interfaces) {
+ interface_reference (&ip -> next,
+ dummy_interfaces, MDL);
+ interface_dereference (&dummy_interfaces, MDL);
+ }
+ interface_reference (&dummy_interfaces, ip, MDL);
}
- return ip;
+ if (pi)
+ status = interface_reference (pi, ip, MDL);
+ interface_dereference (&ip, MDL);
+ if (status != ISC_R_SUCCESS)
+ return 0;
+ return 1;
}
-void make_client_state (ip)
- struct interface_info *ip;
+void make_client_state (state)
+ struct client_state **state;
{
- ip -> client =
- ((struct client_state *)malloc (sizeof *(ip -> client)));
- if (!ip -> client)
- error ("no memory for state on %s\n", ip -> name);
- memset (ip -> client, 0, sizeof *(ip -> client));
+ *state = ((struct client_state *)dmalloc (sizeof **state, MDL));
+ if (!*state)
+ log_fatal ("no memory for client state\n");
+ memset (*state, 0, sizeof **state);
}
-void make_client_config (ip, config)
- struct interface_info *ip;
+void make_client_config (client, config)
+ struct client_state *client;
struct client_config *config;
{
- ip -> client -> config =
- ((struct client_config *)
- malloc (sizeof (struct client_config)));
- if (!ip -> client -> config)
- error ("no memory for config for %s\n", ip -> name);
- memset (ip -> client -> config, 0,
- sizeof *(ip -> client -> config));
- memcpy (ip -> client -> config, config, sizeof *config);
+ client -> config = (((struct client_config *)
+ dmalloc (sizeof (struct client_config), MDL)));
+ if (!client -> config)
+ log_fatal ("no memory for client config\n");
+ memcpy (client -> config, config, sizeof *config);
+ if (!clone_group (&client -> config -> on_receipt,
+ config -> on_receipt, MDL) ||
+ !clone_group (&client -> config -> on_transmission,
+ config -> on_transmission, MDL))
+ log_fatal ("no memory for client state groups.");
}
/* client-lease-statement :==
@@ -526,51 +811,57 @@ void make_client_config (ip, config)
void parse_client_lease_statement (cfile, is_static)
- FILE *cfile;
+ struct parse *cfile;
int is_static;
{
struct client_lease *lease, *lp, *pl;
- struct interface_info *ip;
+ struct interface_info *ip = (struct interface_info *)0;
int token;
- char *val;
+ const char *val;
+ struct client_state *client = (struct client_state *)0;
- token = next_token (&val, cfile);
+ token = next_token (&val, (unsigned *)0, cfile);
if (token != LBRACE) {
- parse_warn ("expecting left brace.");
+ parse_warn (cfile, "expecting left brace.");
skip_to_semi (cfile);
return;
}
- lease = (struct client_lease *)malloc (sizeof (struct client_lease));
+ lease = ((struct client_lease *)
+ dmalloc (sizeof (struct client_lease), MDL));
if (!lease)
- error ("no memory for lease.\n");
+ log_fatal ("no memory for lease.\n");
memset (lease, 0, sizeof *lease);
lease -> is_static = is_static;
-
- ip = (struct interface_info *)0;
+ if (!option_state_allocate (&lease -> options, MDL))
+ log_fatal ("no memory for lease options.\n");
do {
- token = peek_token (&val, cfile);
- if (token == EOF) {
- parse_warn ("unterminated lease declaration.");
+ token = peek_token (&val, (unsigned *)0, cfile);
+ if (token == END_OF_FILE) {
+ parse_warn (cfile, "unterminated lease declaration.");
return;
}
if (token == RBRACE)
break;
- parse_client_lease_declaration (cfile, lease, &ip);
+ parse_client_lease_declaration (cfile, lease, &ip, &client);
} while (1);
- token = next_token (&val, cfile);
+ token = next_token (&val, (unsigned *)0, cfile);
/* If the lease declaration didn't include an interface
declaration that we recognized, it's of no use to us. */
if (!ip) {
- free_client_lease (lease);
+ destroy_client_lease (lease);
return;
}
/* Make sure there's a client state structure... */
- if (!ip -> client)
- make_client_state (ip);
+ if (!ip -> client) {
+ make_client_state (&ip -> client);
+ ip -> client -> interface = ip;
+ }
+ if (!client)
+ client = ip -> client;
/* If this is an alias lease, it doesn't need to be sorted in. */
if (is_static == 2) {
@@ -583,15 +874,15 @@ void parse_client_lease_statement (cfile, is_static)
lease list looking for a lease with the same address, and
if we find it, toss it. */
pl = (struct client_lease *)0;
- for (lp = ip -> client -> leases; lp; lp = lp -> next) {
+ for (lp = client -> leases; lp; lp = lp -> next) {
if (lp -> address.len == lease -> address.len &&
!memcmp (lp -> address.iabuf, lease -> address.iabuf,
lease -> address.len)) {
if (pl)
pl -> next = lp -> next;
else
- ip -> client -> leases = lp -> next;
- free_client_lease (lp);
+ client -> leases = lp -> next;
+ destroy_client_lease (lp);
break;
}
}
@@ -599,8 +890,8 @@ void parse_client_lease_statement (cfile, is_static)
/* If this is a preloaded lease, just put it on the list of recorded
leases - don't make it the active lease. */
if (is_static) {
- lease -> next = ip -> client -> leases;
- ip -> client -> leases = lease;
+ lease -> next = client -> leases;
+ client -> leases = lease;
return;
}
@@ -615,22 +906,21 @@ void parse_client_lease_statement (cfile, is_static)
then if the old active lease has expired, we dump it; if not,
we put it on the list of leases for this interface which are
still valid but no longer active. */
- if (ip -> client -> active) {
- if (ip -> client -> active -> expiry < cur_time)
- free_client_lease (ip -> client -> active);
- else if (ip -> client -> active -> address.len ==
+ if (client -> active) {
+ if (client -> active -> expiry < cur_time)
+ destroy_client_lease (client -> active);
+ else if (client -> active -> address.len ==
lease -> address.len &&
- !memcmp (ip -> client -> active -> address.iabuf,
+ !memcmp (client -> active -> address.iabuf,
lease -> address.iabuf,
lease -> address.len))
- free_client_lease (ip -> client -> active);
+ destroy_client_lease (client -> active);
else {
- ip -> client -> active -> next =
- ip -> client -> leases;
- ip -> client -> leases = ip -> client -> active;
+ client -> active -> next = client -> leases;
+ client -> leases = client -> active;
}
}
- ip -> client -> active = lease;
+ client -> active = lease;
/* phew. */
}
@@ -644,31 +934,65 @@ void parse_client_lease_statement (cfile, is_static)
OPTION option-decl |
RENEW time-decl |
REBIND time-decl |
- EXPIRE time-decl */
+ EXPIRE time-decl |
+ KEY id */
-void parse_client_lease_declaration (cfile, lease, ipp)
- FILE *cfile;
+void parse_client_lease_declaration (cfile, lease, ipp, clientp)
+ struct parse *cfile;
struct client_lease *lease;
struct interface_info **ipp;
+ struct client_state **clientp;
{
int token;
- char *val;
+ const char *val;
+ char *t, *n;
struct interface_info *ip;
-
- switch (next_token (&val, cfile)) {
- case BOOTP:
+ struct option_cache *oc;
+ struct client_state *client = (struct client_state *)0;
+ struct data_string key_id;
+
+ switch (next_token (&val, (unsigned *)0, cfile)) {
+ case KEY:
+ token = next_token (&val, (unsigned *)0, cfile);
+ if (token != STRING && !is_identifier (token)) {
+ parse_warn (cfile, "expecting key name.");
+ skip_to_semi (cfile);
+ break;
+ }
+ if (omapi_auth_key_lookup_name (&lease -> key, val) !=
+ ISC_R_SUCCESS)
+ parse_warn (cfile, "unknown key %s", val);
+ parse_semi (cfile);
+ break;
+ case TOKEN_BOOTP:
lease -> is_bootp = 1;
break;
case INTERFACE:
- token = next_token (&val, cfile);
+ token = next_token (&val, (unsigned *)0, cfile);
if (token != STRING) {
- parse_warn ("expecting interface name (in quotes).");
+ parse_warn (cfile,
+ "expecting interface name (in quotes).");
skip_to_semi (cfile);
break;
}
- ip = interface_or_dummy (val);
- *ipp = ip;
+ interface_or_dummy (ipp, val);
+ break;
+
+ case NAME:
+ token = next_token (&val, (unsigned *)0, cfile);
+ ip = *ipp;
+ if (!ip) {
+ parse_warn (cfile, "state name precedes interface.");
+ break;
+ }
+ for (client = ip -> client; client; client = client -> next)
+ if (client -> name && !strcmp (client -> name, val))
+ break;
+ if (!client)
+ parse_warn (cfile,
+ "lease specified for unknown pseudo.");
+ *clientp = client;
break;
case FIXED_ADDR:
@@ -681,11 +1005,11 @@ void parse_client_lease_declaration (cfile, lease, ipp)
return;
case FILENAME:
- lease -> filename = parse_string (cfile);
+ parse_string (cfile, &lease -> filename, (unsigned *)0);
return;
case SERVER_NAME:
- lease -> server_name = parse_string (cfile);
+ parse_string (cfile, &lease -> server_name, (unsigned *)0);
return;
case RENEW:
@@ -701,239 +1025,33 @@ void parse_client_lease_declaration (cfile, lease, ipp)
return;
case OPTION:
- parse_option_decl (cfile, lease -> options);
+ oc = (struct option_cache *)0;
+ if (parse_option_decl (&oc, cfile)) {
+ save_option (oc -> option -> universe,
+ lease -> options, oc);
+ option_cache_dereference (&oc, MDL);
+ }
return;
default:
- parse_warn ("expecting lease declaration.");
+ parse_warn (cfile, "expecting lease declaration.");
skip_to_semi (cfile);
break;
}
- token = next_token (&val, cfile);
+ token = next_token (&val, (unsigned *)0, cfile);
if (token != SEMI) {
- parse_warn ("expecting semicolon.");
+ parse_warn (cfile, "expecting semicolon.");
skip_to_semi (cfile);
}
}
-struct option *parse_option_decl (cfile, options)
- FILE *cfile;
- struct option_data *options;
-{
- char *val;
- int token;
- u_int8_t buf [4];
- u_int8_t hunkbuf [1024];
- int hunkix = 0;
- char *vendor;
- char *fmt;
- struct universe *universe;
- struct option *option;
- struct iaddr ip_addr;
- u_int8_t *dp;
- int len;
- int nul_term = 0;
-
- token = next_token (&val, cfile);
- if (!is_identifier (token)) {
- parse_warn ("expecting identifier after option keyword.");
- if (token != SEMI)
- skip_to_semi (cfile);
- return (struct option *)0;
- }
- vendor = malloc (strlen (val) + 1);
- if (!vendor)
- error ("no memory for vendor information.");
- strcpy (vendor, val);
- token = peek_token (&val, cfile);
- if (token == DOT) {
- /* Go ahead and take the DOT token... */
- token = next_token (&val, cfile);
-
- /* The next token should be an identifier... */
- token = next_token (&val, cfile);
- if (!is_identifier (token)) {
- parse_warn ("expecting identifier after '.'");
- if (token != SEMI)
- skip_to_semi (cfile);
- return (struct option *)0;
- }
-
- /* Look up the option name hash table for the specified
- vendor. */
- universe = ((struct universe *)
- hash_lookup (&universe_hash,
- (unsigned char *)vendor, 0));
- /* If it's not there, we can't parse the rest of the
- declaration. */
- if (!universe) {
- parse_warn ("no vendor named %s.", vendor);
- skip_to_semi (cfile);
- return (struct option *)0;
- }
- } else {
- /* Use the default hash table, which contains all the
- standard dhcp option names. */
- val = vendor;
- universe = &dhcp_universe;
- }
-
- /* Look up the actual option info... */
- option = (struct option *)hash_lookup (universe -> hash,
- (unsigned char *)val, 0);
-
- /* If we didn't get an option structure, it's an undefined option. */
- if (!option) {
- if (val == vendor)
- parse_warn ("no option named %s", val);
- else
- parse_warn ("no option named %s for vendor %s",
- val, vendor);
- skip_to_semi (cfile);
- return (struct option *)0;
- }
-
- /* Free the initial identifier token. */
- free (vendor);
-
- /* Parse the option data... */
- do {
- for (fmt = option -> format; *fmt; fmt++) {
- if (*fmt == 'A')
- break;
- switch (*fmt) {
- case 'X':
- len = parse_X (cfile, &hunkbuf [hunkix],
- sizeof hunkbuf - hunkix);
- hunkix += len;
- break;
-
- case 't': /* Text string... */
- token = next_token (&val, cfile);
- if (token != STRING) {
- parse_warn ("expecting string.");
- skip_to_semi (cfile);
- return (struct option *)0;
- }
- len = strlen (val);
- if (hunkix + len + 1 > sizeof hunkbuf) {
- parse_warn ("option data buffer %s",
- "overflow");
- skip_to_semi (cfile);
- return (struct option *)0;
- }
- memcpy (&hunkbuf [hunkix], val, len + 1);
- nul_term = 1;
- hunkix += len;
- break;
-
- case 'I': /* IP address. */
- if (!parse_ip_addr (cfile, &ip_addr))
- return (struct option *)0;
- len = ip_addr.len;
- dp = ip_addr.iabuf;
-
- alloc:
- if (hunkix + len > sizeof hunkbuf) {
- parse_warn ("option data buffer %s",
- "overflow");
- skip_to_semi (cfile);
- return (struct option *)0;
- }
- memcpy (&hunkbuf [hunkix], dp, len);
- hunkix += len;
- break;
-
- case 'L': /* Unsigned 32-bit integer... */
- case 'l': /* Signed 32-bit integer... */
- token = next_token (&val, cfile);
- if (token != NUMBER) {
- need_number:
- parse_warn ("expecting number.");
- if (token != SEMI)
- skip_to_semi (cfile);
- return (struct option *)0;
- }
- convert_num (buf, val, 0, 32);
- len = 4;
- dp = buf;
- goto alloc;
-
- case 's': /* Signed 16-bit integer. */
- case 'S': /* Unsigned 16-bit integer. */
- token = next_token (&val, cfile);
- if (token != NUMBER)
- goto need_number;
- convert_num (buf, val, 0, 16);
- len = 2;
- dp = buf;
- goto alloc;
-
- case 'b': /* Signed 8-bit integer. */
- case 'B': /* Unsigned 8-bit integer. */
- token = next_token (&val, cfile);
- if (token != NUMBER)
- goto need_number;
- convert_num (buf, val, 0, 8);
- len = 1;
- dp = buf;
- goto alloc;
-
- case 'f': /* Boolean flag. */
- token = next_token (&val, cfile);
- if (!is_identifier (token)) {
- parse_warn ("expecting identifier.");
- bad_flag:
- if (token != SEMI)
- skip_to_semi (cfile);
- return (struct option *)0;
- }
- if (!strcasecmp (val, "true")
- || !strcasecmp (val, "on"))
- buf [0] = 1;
- else if (!strcasecmp (val, "false")
- || !strcasecmp (val, "off"))
- buf [0] = 0;
- else {
- parse_warn ("expecting boolean.");
- goto bad_flag;
- }
- len = 1;
- dp = buf;
- goto alloc;
-
- default:
- warn ("Bad format %c in parse_option_param.",
- *fmt);
- skip_to_semi (cfile);
- return (struct option *)0;
- }
- }
- token = next_token (&val, cfile);
- } while (*fmt == 'A' && token == COMMA);
-
- if (token != SEMI) {
- parse_warn ("semicolon expected.");
- skip_to_semi (cfile);
- return (struct option *)0;
- }
-
- options [option -> code].data =
- (unsigned char *)malloc (hunkix + nul_term);
- if (!options [option -> code].data)
- error ("out of memory allocating option data.");
- memcpy (options [option -> code].data, hunkbuf, hunkix + nul_term);
- options [option -> code].len = hunkix;
- return option;
-}
-
void parse_string_list (cfile, lp, multiple)
- FILE *cfile;
+ struct parse *cfile;
struct string_list **lp;
int multiple;
{
int token;
- char *val;
+ const char *val;
struct string_list *cur, *tmp;
/* Find the last medium in the media list. */
@@ -945,18 +1063,18 @@ void parse_string_list (cfile, lp, multiple)
}
do {
- token = next_token (&val, cfile);
+ token = next_token (&val, (unsigned *)0, cfile);
if (token != STRING) {
- parse_warn ("Expecting media options.");
+ parse_warn (cfile, "Expecting media options.");
skip_to_semi (cfile);
return;
}
- tmp = (struct string_list *)malloc (strlen (val) + 1 +
- sizeof
- (struct string_list *));
+ tmp = ((struct string_list *)
+ dmalloc (strlen (val) + sizeof (struct string_list),
+ MDL));
if (!tmp)
- error ("no memory for string list entry.");
+ log_fatal ("no memory for string list entry.");
strcpy (tmp -> string, val);
tmp -> next = (struct string_list *)0;
@@ -968,44 +1086,67 @@ void parse_string_list (cfile, lp, multiple)
*lp = tmp;
cur = tmp;
- token = next_token (&val, cfile);
+ token = next_token (&val, (unsigned *)0, cfile);
} while (multiple && token == COMMA);
if (token != SEMI) {
- parse_warn ("expecting semicolon.");
+ parse_warn (cfile, "expecting semicolon.");
skip_to_semi (cfile);
}
}
void parse_reject_statement (cfile, config)
- FILE *cfile;
+ struct parse *cfile;
struct client_config *config;
{
int token;
- char *val;
+ const char *val;
struct iaddr addr;
struct iaddrlist *list;
do {
if (!parse_ip_addr (cfile, &addr)) {
- parse_warn ("expecting IP address.");
+ parse_warn (cfile, "expecting IP address.");
skip_to_semi (cfile);
return;
}
- list = (struct iaddrlist *)malloc (sizeof (struct iaddrlist));
+ list = (struct iaddrlist *)dmalloc (sizeof (struct iaddrlist),
+ MDL);
if (!list)
- error ("no memory for reject list!");
+ log_fatal ("no memory for reject list!");
list -> addr = addr;
list -> next = config -> reject_list;
config -> reject_list = list;
- token = next_token (&val, cfile);
+ token = next_token (&val, (unsigned *)0, cfile);
} while (token == COMMA);
if (token != SEMI) {
- parse_warn ("expecting semicolon.");
+ parse_warn (cfile, "expecting semicolon.");
skip_to_semi (cfile);
}
}
+
+/* allow-deny-keyword :== BOOTP
+ | BOOTING
+ | DYNAMIC_BOOTP
+ | UNKNOWN_CLIENTS */
+
+int parse_allow_deny (oc, cfile, flag)
+ struct option_cache **oc;
+ struct parse *cfile;
+ int flag;
+{
+ enum dhcp_token token;
+ const char *val;
+ unsigned char rf = flag;
+ struct expression *data = (struct expression *)0;
+ int status;
+
+ parse_warn (cfile, "allow/deny/ignore not permitted here.");
+ skip_to_semi (cfile);
+ return 0;
+}
+
diff --git a/contrib/isc-dhcp/client/dhclient-script.8 b/contrib/isc-dhcp/client/dhclient-script.8
index 82212db..02b2252 100644
--- a/contrib/isc-dhcp/client/dhclient-script.8
+++ b/contrib/isc-dhcp/client/dhclient-script.8
@@ -1,8 +1,6 @@
.\" dhclient-script.8
.\"
-.\" Copyright (c) 1997 The Internet Software Consortium.
-.\" All rights reserved.
-.\"
+.\" Copyright (c) 1996-2001 Internet Software Consortium.
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
@@ -31,10 +29,11 @@
.\" SUCH DAMAGE.
.\"
.\" This software has been written for the Internet Software Consortium
-.\" by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
-.\" Enterprises. To learn more about the Internet Software Consortium,
-.\" see ``http://www.isc.org/isc''. To learn more about Vixie
-.\" Enterprises, see ``http://www.vix.com''.
+.\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+.\" To learn more about the Internet Software Consortium, see
+.\" ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+.\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+.\" ``http://www.nominum.com''.
.TH dhclient-script 8
.SH NAME
dhclient-script - DHCP client network configuration script
@@ -61,7 +60,7 @@ to a particular computer should be done in the
.B ETCDIR/dhclient.conf
file. If you find that you can't make such a customization without
customizing
-.B dhclient-script
+.B ETCDIR/dhclient.conf
or using the enter and exit hooks, please submit a bug report.
.SH HOOKS
When it starts, the client script first defines a shell function,
@@ -80,23 +79,29 @@ is available to this script, which may modify the environment if needed
to change the behaviour of the script. If an error occurs during the
execution of the script, it can set the exit_status variable to a nonzero
value, and
-.B ETCDIR/dhclient-script
+.B CLIENTBINDIR/dhclient-script
will exit with that error code immediately after the client script exits.
.PP
After all processing has completed,
-.B ETCDIR/dhclient-script
+.B CLIENTBINDIR/dhclient-script
checks for the presence of an executable
.B ETCDIR/dhclient-exit-hooks
-script, which if present is invoked using the '.' command. The exit status
-is passed in the exit_status shell variable, and will always be zero if the
-script succeeded at the task for which it was invoked.
+script, which if present is invoked using the '.' command. The exit
+status of dhclient-script will be passed to dhclient-exit-hooks in the
+exit_status shell variable, and will always be zero if the script
+succeeded at the task for which it was invoked. The rest of the
+environment as described previously for dhclient-enter-hooks is also
+present. The
+.B ETCDIR/dhclient-exit-hooks
+script can modify the valid of exit_status to change the exit status
+of dhclient-script.
.SH OPERATION
When dhclient needs to invoke the client configuration script, it
-writes a shell script into /tmp which defines a variety of variables.
+defines a set of variables in the environment, and then invokes
+.B CLIENTBINDIR/dhclient-script.
In all cases, $reason is set to the name of the reason why the script
has been invoked. The following reasons are currently defined:
-MEDIUM, PREINIT, ARPCHECK, ARPSEND, BOUND, RENEW, REBIND, REBOOT,
-EXPIRE, FAIL and TIMEOUT.
+MEDIUM, PREINIT, BOUND, RENEW, REBIND, REBOOT, EXPIRE, FAIL and TIMEOUT.
.PP
.SH MEDIUM
The DHCP client is requesting that an interface's media type
@@ -115,18 +120,6 @@ and the media type in $medium.
If an IP alias has been declared in dhclient.conf, its address will be
passed in $alias_ip_address, and that ip alias should be deleted from
the interface, along with any routes to it.
-.SH ARPSEND
-The DHCP client is requesting that an address that has been offered to
-it be checked to see if somebody else is using it, by sending an ARP
-request for that address. It's not clear how to implement this, so
-no examples exist yet. The IP address to check is passed in
-$new_ip_address, and the interface name is passed in $interface.
-.SH ARPCHECK
-The DHCP client wants to know if a response to the ARP request send
-using ARPSEND has been received. If one has, the script should exit
-with a nonzero status, indicating that the offered address has already
-been requested and should be declined. $new_ip_address and
-$interface are set as with ARPSEND.
.SH BOUND
The DHCP client has done an initial binding to a new address. The
new ip address is passed in $new_ip_address, and the interface name is
@@ -137,6 +130,13 @@ by underscores ('_') in order to make valid shell variables, and the
variable names start with new_. So for example, the new subnet mask
would be passed in $new_subnet_mask.
.PP
+Before actually configuring the address, dhclient-script should
+somehow ARP for it and exit with a nonzero status if it receives a
+reply. In this case, the client will send a DHCPDECLINE message to
+the server and acquire a different address. This may also be done in
+the RENEW, REBIND, or REBOOT states, but is not required, and indeed
+may not be desirable.
+.PP
When a binding has been completed, a lot of network parameters are
likely to need to be set up. A new /etc/resolv.conf needs to be
created, using the values of $new_domain_name and
@@ -216,10 +216,10 @@ dhclient.leases(5).
.SH AUTHOR
.B dhclient-script(8)
has been written for the Internet Software Consortium
-by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+by Ted Lemon in cooperation with Vixie
Enterprises. To learn more about the Internet Software Consortium,
see
-.B http://www.vix.com/isc.
+.B http://www.isc.org.
To learn more about Vixie
Enterprises, see
.B http://www.vix.com.
diff --git a/contrib/isc-dhcp/client/dhclient.8 b/contrib/isc-dhcp/client/dhclient.8
index eae8437..b47a4fd 100644
--- a/contrib/isc-dhcp/client/dhclient.8
+++ b/contrib/isc-dhcp/client/dhclient.8
@@ -1,40 +1,20 @@
.\" dhclient.8
.\"
-.\" Copyright (c) 1997 The Internet Software Consortium.
-.\" All rights reserved.
+.\" Copyright (c) 1996-1999 Internet Software Consortium.
+.\" Use is subject to license terms which appear in the file named
+.\" ISC-LICENSE that should have accompanied this file when you
+.\" received it. If a file named ISC-LICENSE did not accompany this
+.\" file, or you are not sure the one you have is correct, you may
+.\" obtain an applicable copy of the license at:
.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
+.\" http://www.isc.org/isc-license-1.0.html.
.\"
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. Neither the name of The Internet Software Consortium nor the names
-.\" of its contributors may be used to endorse or promote products derived
-.\" from this software without specific prior written permission.
+.\" This file is part of the ISC DHCP distribution. The documentation
+.\" associated with this file is listed in the file DOCUMENTATION,
+.\" included in the top-level directory of this release.
.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
-.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-.\" DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
-.\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.\" This software has been written for the Internet Software Consortium
-.\" by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
-.\" Enterprises. To learn more about the Internet Software Consortium,
-.\" see ``http://www.isc.org/isc''. To learn more about Vixie
-.\" Enterprises, see ``http://www.vix.com''.
+.\" Support and other services are available for ISC products - see
+.\" http://www.isc.org for more information.
.TH dhclient 8
.SH NAME
dhclient - Dynamic Host Configuration Protocol Client
@@ -48,6 +28,48 @@ dhclient - Dynamic Host Configuration Protocol Client
.B -d
]
[
+.B -q
+]
+[
+.B -1
+]
+[
+.B -r
+]
+[
+.B -lf
+.I lease-file
+]
+[
+.B -pf
+.I pid-file
+]
+[
+.B -cf
+.I config-file
+]
+[
+.B -sf
+.I script-file
+]
+[
+.B -s
+server
+]
+[
+.B -g
+relay
+]
+[
+.B -n
+]
+[
+.B -nw
+]
+[
+.B -w
+]
+[
.I if0
[
.I ...ifN
@@ -87,7 +109,7 @@ dhclient.leases file. In order to prevent the file from becoming
arbitrarily large, from time to time dhclient creates a new
dhclient.leases file from its in-core lease database. The old version
of the dhclient.leases file is retained under the name
-.IR dhcpd.leases~
+.IR dhclient.leases~
until the next time dhclient rewrites the database.
.PP
Old leases are kept around in case the DHCP server is unavailable when
@@ -112,49 +134,163 @@ than cycling through the list of old leases.
.PP
The names of the network interfaces that dhclient should attempt to
configure may be specified on the command line. If no interface names
-are specified on the command line dhclient will identify all network
-interfaces, elimininating non-broadcast interfaces if possible, and
-attempt to configure each interface.
+are specified on the command line dhclient will normally identify all
+network interfaces, elimininating non-broadcast interfaces if
+possible, and attempt to configure each interface.
.PP
-If dhclient should listen and transmit on a port other than the
+It is also possible to specify interfaces by name in the
+.B dhclient.conf(5)
+file. If interfaces are specified in this way, then the client will
+only configure interfaces that are either specified in the
+configuration file or on the command line, and will ignore all other
+interfaces.
+.PP
+If the DHCP client should listen and transmit on a port other than the
standard (port 68), the
.B -p
flag may used. It should be followed by the udp port number that
dhclient should use. This is mostly useful for debugging purposes.
-If the
-.B -p
-flag is specified, the client will transmit responses to servers at a
-port number that is one less than the one specified - i.e., if you
-specify
-.B -p
-68, then the client will listen on port 68 and transmit to port 67.
-Datagrams that must go through relay agents are sent to the port
-number specified with the
-.B -p
-flag - if you wish to use alternate port numbers, you must configure
-any relay agents you are using to use the same alternate port numbers.
+If a different port is specified for the client to listen on and
+transmit on, the client will also use a different destination port -
+one greater than the specified destination port.
+.PP
+The DHCP client normally transmits any protocol messages it sends
+before acquiring an IP address to, 255.255.255.255, the IP limited
+broadcast address. For debugging purposes, it may be useful to have
+the server transmit these messages to some other address. This can
+be specified with the
+.B -s
+flag, followed by the IP address or domain name of the destination.
.PP
-Dhclient will normally run in the foreground until it has configured
-an interface, and then will revert to running in the background.
-To run force dhclient to always run as a foreground process, the
+For testing purposes, the giaddr field of all packets that the client
+sends can be set using the
+.B -g
+flag, followed by the IP address to send. This is only useful for testing,
+and should not be expected to work in any consistent or useful way.
+.PP
+The DHCP client will normally run in the foreground until it has
+configured an interface, and then will revert to running in the
+background. To run force dhclient to always run as a foreground
+process, the
.B -d
-flag should be specified. This is useful when running dhclient under
-a debugger, or when running it out of inittab on System V systems.
+flag should be specified. This is useful when running the client
+under a debugger, or when running it out of inittab on System V
+systems.
+.PP
+The client normally prints a startup message and displays the
+protocol sequence to the standard error descriptor until it has
+acquired an address, and then only logs messages using the
+.B syslog (3)
+facility. The
+.B -q
+flag prevents any messages other than errors from being printed to the
+standard error descriptor.
+.PP
+The client normally doesn't release the current lease as it is not
+required by the DHCP protocol. Some cable ISPs require their clients
+to notify the server if they wish to release an assigned IP address.
+The
+.B -r
+flag explicitly releases the current lease, and once the lease has been
+released, the client exits.
+.PP
+The
+.B -1
+flag cause dhclient to try once to get a lease. If it fails, dhclient exits
+with exit code two.
+.PP
+The DHCP client normally gets its configuration information from
+.B ETCDIR/dhclient.conf,
+its lease database from
+.B DBDIR/dhclient.leases,
+stores its process ID in a file called
+.B RUNDIR/dhclient.pid,
+and configures the network interface using
+.B CLIENTBINDIR/dhclient-script
+To specify different names and/or locations for these files, use the
+.B -cf,
+.B -lf,
+.B -pf
+and
+.B -sf
+flags, respectively, followed by the name of the file. This can be
+particularly useful if, for example,
+.B DBDIR
+or
+.B RUNDIR
+has not yet been mounted when the DHCP client is started.
.PP
+The DHCP client normally exits if it isn't able to identify any
+network interfaces to configure. On laptop computers and other
+computers with hot-swappable I/O buses, it is possible that a
+broadcast interface may be added after system startup. The
+.B -w
+flag can be used to cause the client not to exit when it doesn't find
+any such interfaces. The
+.B omshell (8)
+program can then be used to notify the client when a network interface
+has been added or removed, so that the client can attempt to configure an IP
+address on that interface.
+.PP
+The DHCP client can be directed not to attempt to configure any interfaces
+using the
+.B -n
+flag. This is most likely to be useful in combination with the
+.B -w
+flag.
+.PP
+The client can also be instructed to become a daemon immediately, rather
+than waiting until it has acquired an IP address. This can be done by
+supplying the
+.B -nw
+flag.
.SH CONFIGURATION
The syntax of the dhclient.conf(8) file is discussed seperately.
+.SH OMAPI
+The DHCP client provides some ability to control it while it is
+running, without stopping it. This capability is provided using OMAPI,
+an API for manipulating remote objects. OMAPI clients connect to the
+client using TCP/IP, authenticate, and can then examine the client's
+current status and make changes to it.
+.PP
+Rather than implementing the underlying OMAPI protocol directly, user
+programs should use the dhcpctl API or OMAPI itself. Dhcpctl is a
+wrapper that handles some of the housekeeping chores that OMAPI does
+not do automatically. Dhcpctl and OMAPI are documented in \fBdhcpctl(3)\fR
+and \fBomapi(3)\fR. Most things you'd want to do with the client can
+be done directly using the \fBomshell(1)\fR command, rather than
+having to write a special program.
+.SH THE CONTROL OBJECT
+The control object allows you to shut the client down, releasing all
+leases that it holds and deleting any DNS records it may have added.
+It also allows you to pause the client - this unconfigures any
+interfaces the client is using. You can then restart it, which
+causes it to reconfigure those interfaces. You would normally pause
+the client prior to going into hibernation or sleep on a laptop
+computer. You would then resume it after the power comes back.
+This allows PC cards to be shut down while the computer is hibernating
+or sleeping, and then reinitialized to their previous state once the
+computer comes out of hibernation or sleep.
+.PP
+The control object has one attribute - the state attribute. To shut
+the client down, set its state attribute to 2. It will automatically
+do a DHCPRELEASE. To pause it, set its state attribute to 3. To
+resume it, set its state attribute to 4.
+.PP
.SH FILES
+.B CLIENTBINDIR/dhclient-script,
.B ETCDIR/dhclient.conf, DBDIR/dhclient.leases, RUNDIR/dhclient.pid,
.B DBDIR/dhclient.leases~.
.SH SEE ALSO
-dhcpd(8), dhcrelay(8), dhclient.conf(5), dhclient.leases(5)
+dhcpd(8), dhcrelay(8), dhclient-script (8), dhclient.conf(5),
+dhclient.leases(5).
.SH AUTHOR
.B dhclient(8)
has been written for the Internet Software Consortium
-by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+by Ted Lemon in cooperation with Vixie
Enterprises. To learn more about the Internet Software Consortium,
see
-.B http://www.vix.com/isc.
+.B http://www.isc.org
To learn more about Vixie
Enterprises, see
.B http://www.vix.com.
diff --git a/contrib/isc-dhcp/client/dhclient.c b/contrib/isc-dhcp/client/dhclient.c
index 129f99a..f1c0ddd 100644
--- a/contrib/isc-dhcp/client/dhclient.c
+++ b/contrib/isc-dhcp/client/dhclient.c
@@ -3,8 +3,8 @@
DHCP Client. */
/*
- * Copyright (c) 1995, 1996, 1997, 1998, 1999
- * The Internet Software Consortium. All rights reserved.
+ * Copyright (c) 1995-2001 Internet Software Consortium.
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -15,7 +15,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
+ * 3. Neither the name of Internet Software Consortium nor the names
* of its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -33,30 +33,15 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
- *
- * This client was substantially modified and enhanced by Elliot Poger
- * for use on Linux while he was working on the MosquitoNet project at
- * Stanford.
- *
- * The current version owes much to Elliot's Linux enhancements, but
- * was substantially reorganized and partially rewritten by Ted Lemon
- * so as to use the same networking framework that the Internet Software
- * Consortium DHCP server uses. Much system-specific configuration code
- * was moved into a shell script so that as support for more operating
- * systems is added, it will not be necessary to port and maintain
- * system-specific configuration code to these operating systems - instead,
- * the shell script can invoke the native tools to accomplish the same
- * purpose.
+ * This code is based on the original client state machine that was
+ * written by Elliot Poger. The code has been extensively hacked on
+ * by Ted Lemon since then, so any mistakes you find are probably his
+ * fault and not Elliot's.
*/
#ifndef lint
static char ocopyright[] =
-"$Id: dhclient.c,v 1.44.2.47 2000/09/06 20:59:09 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
+"$Id: dhclient.c,v 1.129.2.7 2001/08/08 14:46:14 mellon Exp $ Copyright (c) 1995-2001 Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
@@ -65,39 +50,44 @@ static char ocopyright[] =
TIME cur_time;
TIME default_lease_time = 43200; /* 12 hours... */
TIME max_lease_time = 86400; /* 24 hours... */
-struct tree_cache *global_options [256];
-char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
-char *path_dhclient_db = _PATH_DHCLIENT_DB;
-char *path_dhclient_pid = _PATH_DHCLIENT_PID;
+const char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
+const char *path_dhclient_db = _PATH_DHCLIENT_DB;
+const char *path_dhclient_pid = _PATH_DHCLIENT_PID;
+static char path_dhclient_script_array [] = _PATH_DHCLIENT_SCRIPT;
+char *path_dhclient_script = path_dhclient_script_array;
-int interfaces_requested = 0;
+int dhcp_max_agent_option_packet_length = 0;
-int log_perror = 1;
+int interfaces_requested = 0;
struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
struct iaddr iaddr_any = { 4, { 0, 0, 0, 0 } };
struct in_addr inaddr_any;
struct sockaddr_in sockaddr_broadcast;
+struct in_addr giaddr;
/* ASSERT_STATE() does nothing now; it used to be
assert (state_is == state_shouldbe). */
#define ASSERT_STATE(state_is, state_shouldbe) {}
+static char copyright[] = "Copyright 1995-2001 Internet Software Consortium.";
+static char arr [] = "All rights reserved.";
+static char message [] = "Internet Software Consortium DHCP Client";
+static char url [] = "For info, please visit http://www.isc.org/products/DHCP";
+
u_int16_t local_port;
u_int16_t remote_port;
-int log_priority;
int no_daemon;
-int save_scripts;
+struct string_list *client_env;
+int client_env_count;
+int onetry;
+int quiet;
+int nowait;
-static char copyright[] =
-"Copyright 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.";
-static char arr [] = "All rights reserved.";
-static char message [] = "Internet Software Consortium DHCP Client";
-static char contrib [] = "Please contribute if you find this software useful.";
-static char url [] = "For info, please visit http://www.isc.org/dhcp-contrib.html";
+static void usage PROTO ((void));
-static void usage PROTO ((char *));
+void do_release(struct client_state *);
int main (argc, argv, envp)
int argc;
@@ -106,105 +96,242 @@ int main (argc, argv, envp)
int i;
struct servent *ent;
struct interface_info *ip;
- int seed;
- int quiet = 0;
+ struct client_state *client;
+ unsigned seed;
+ char *server = (char *)0;
+ char *relay = (char *)0;
+ isc_result_t status;
+ int release_mode = 0;
+ omapi_object_t *listener;
+ isc_result_t result;
+ int persist = 0;
+ int omapi_port;
+ int no_dhclient_conf = 0;
+ int no_dhclient_db = 0;
+ int no_dhclient_pid = 0;
+ int no_dhclient_script = 0;
char *s;
- s = strrchr (argv [0], '/');
- if (!s)
- s = argv [0];
- else
- s++;
+ /* Make sure we have stdin, stdout and stderr. */
+ i = open ("/dev/null", O_RDWR);
+ if (i == 0)
+ i = open ("/dev/null", O_RDWR);
+ if (i == 1) {
+ i = open ("/dev/null", O_RDWR);
+ log_perror = 0; /* No sense logging to /dev/null. */
+ } else if (i != -1)
+ close (i);
- /* Initially, log errors to stderr as well as to syslogd. */
#ifdef SYSLOG_4_2
- openlog (s, LOG_NDELAY);
- log_priority = DHCPD_LOG_FACILITY;
+ openlog ("dhclient", LOG_NDELAY);
+ log_priority = LOG_DAEMON;
#else
- openlog (s, LOG_NDELAY, DHCPD_LOG_FACILITY);
+ openlog ("dhclient", LOG_NDELAY, LOG_DAEMON);
#endif
#if !(defined (DEBUG) || defined (SYSLOG_4_2) || defined (__CYGWIN32__))
setlogmask (LOG_UPTO (LOG_INFO));
#endif
+ /* Set up the OMAPI. */
+ status = omapi_init ();
+ if (status != ISC_R_SUCCESS)
+ log_fatal ("Can't initialize OMAPI: %s",
+ isc_result_totext (status));
+
+ /* Set up the OMAPI wrappers for various server database internal
+ objects. */
+ dhcp_common_objects_setup ();
+
+ dhcp_interface_discovery_hook = dhclient_interface_discovery_hook;
+ dhcp_interface_shutdown_hook = dhclient_interface_shutdown_hook;
+ dhcp_interface_startup_hook = dhclient_interface_startup_hook;
+
for (i = 1; i < argc; i++) {
- if (!strcmp (argv [i], "-p")) {
+ if (!strcmp (argv [i], "-r")) {
+ release_mode = 1;
+ no_daemon = 1;
+ } else if (!strcmp (argv [i], "-p")) {
if (++i == argc)
- usage (s);
+ usage ();
local_port = htons (atoi (argv [i]));
- debug ("binding to user-specified port %d",
+ log_debug ("binding to user-specified port %d",
ntohs (local_port));
} else if (!strcmp (argv [i], "-d")) {
no_daemon = 1;
- } else if (!strcmp (argv [i], "-D")) {
- save_scripts = 1;
- } else if (!strcmp (argv [i], "-cf")) {
+ } else if (!strcmp (argv [i], "-pf")) {
+ if (++i == argc)
+ usage ();
+ path_dhclient_pid = argv [i];
+ no_dhclient_pid = 1;
+ } else if (!strcmp (argv [i], "-cf")) {
+ if (++i == argc)
+ usage ();
+ path_dhclient_conf = argv [i];
+ no_dhclient_conf = 1;
+ } else if (!strcmp (argv [i], "-lf")) {
+ if (++i == argc)
+ usage ();
+ path_dhclient_db = argv [i];
+ no_dhclient_db = 1;
+ } else if (!strcmp (argv [i], "-sf")) {
if (++i == argc)
- usage (s);
- path_dhclient_conf = argv [i];
- } else if (!strcmp (argv [i], "-pf")) {
- if (++i == argc)
- usage (s);
- path_dhclient_pid = argv [i];
- } else if (!strcmp (argv [i], "-lf")) {
- if (++i == argc)
- usage (s);
- path_dhclient_db = argv [i];
+ usage ();
+ path_dhclient_script = argv [i];
+ no_dhclient_script = 1;
+ } else if (!strcmp (argv [i], "-1")) {
+ onetry = 1;
} else if (!strcmp (argv [i], "-q")) {
quiet = 1;
quiet_interface_discovery = 1;
+ } else if (!strcmp (argv [i], "-s")) {
+ if (++i == argc)
+ usage ();
+ server = argv [i];
+ } else if (!strcmp (argv [i], "-g")) {
+ if (++i == argc)
+ usage ();
+ relay = argv [i];
+ } else if (!strcmp (argv [i], "-n")) {
+ /* do not start up any interfaces */
+ interfaces_requested = 1;
+ } else if (!strcmp (argv [i], "-w")) {
+ /* do not exit if there are no broadcast interfaces. */
+ persist = 1;
} else if (argv [i][0] == '-') {
- usage (s);
+ usage ();
+ } else if (!strcmp (argv [i], "-e")) {
+ struct string_list *tmp;
+ if (++i == argc)
+ usage ();
+ tmp = dmalloc (strlen (argv [i]) + sizeof *tmp, MDL);
+ if (!tmp)
+ log_fatal ("No memory for %s", argv [i]);
+ strcpy (tmp -> string, argv [i]);
+ tmp -> next = client_env;
+ client_env = tmp;
+ client_env_count++;
+ } else if (!strcmp (argv [i], "--version")) {
+ log_info ("isc-dhclient-%s", DHCP_VERSION);
+ exit (0);
+ } else if (!strcmp (argv [i], "-nw")) {
+ nowait = 1;
} else {
- struct interface_info *tmp =
- ((struct interface_info *)
- dmalloc (sizeof *tmp, "specified_interface"));
- if (!tmp)
- error ("Insufficient memory to %s %s",
- "record interface", argv [i]);
- memset (tmp, 0, sizeof *tmp);
+ struct interface_info *tmp = (struct interface_info *)0;
+ status = interface_allocate (&tmp, MDL);
+ if (status != ISC_R_SUCCESS)
+ log_fatal ("Can't record interface %s:%s",
+ argv [i], isc_result_totext (status));
+ if (strlen (argv [i]) > sizeof tmp -> name)
+ log_fatal ("%s: interface name too long (max %ld)",
+ argv [i], (long)strlen (argv [i]));
strcpy (tmp -> name, argv [i]);
- tmp -> next = interfaces;
+ if (interfaces) {
+ interface_reference (&tmp -> next,
+ interfaces, MDL);
+ interface_dereference (&interfaces, MDL);
+ }
+ interface_reference (&interfaces, tmp, MDL);
tmp -> flags = INTERFACE_REQUESTED;
interfaces_requested = 1;
- interfaces = tmp;
}
}
+ if (!no_dhclient_conf && (s = getenv ("PATH_DHCLIENT_CONF"))) {
+ path_dhclient_conf = s;
+ }
+ if (!no_dhclient_db && (s = getenv ("PATH_DHCLIENT_DB"))) {
+ path_dhclient_db = s;
+ }
+ if (!no_dhclient_pid && (s = getenv ("PATH_DHCLIENT_PID"))) {
+ path_dhclient_pid = s;
+ }
+ if (!no_dhclient_script && (s = getenv ("PATH_DHCLIENT_SCRIPT"))) {
+ path_dhclient_script = s;
+ }
+
+ /* first kill of any currently running client */
+ if (release_mode) {
+ /* XXX inelegant hack to prove concept */
+ char command[1024];
+
+#if !defined (NO_SNPRINTF)
+ snprintf (command, 1024, "kill `cat %s`", path_dhclient_pid);
+#else
+ sprintf (command, "kill `cat %s`", path_dhclient_pid);
+#endif
+ system (command);
+ }
+
if (!quiet) {
- note ("%s %s", message, DHCP_VERSION);
- note (copyright);
- note (arr);
- note ("");
- note (contrib);
- note (url);
- note ("");
+ log_info ("%s %s", message, DHCP_VERSION);
+ log_info (copyright);
+ log_info (arr);
+ log_info (url);
+ log_info ("%s", "");
} else
log_perror = 0;
+ /* If we're given a relay agent address to insert, for testing
+ purposes, figure out what it is. */
+ if (relay) {
+ if (!inet_aton (relay, &giaddr)) {
+ struct hostent *he;
+ he = gethostbyname (relay);
+ if (he) {
+ memcpy (&giaddr, he -> h_addr_list [0],
+ sizeof giaddr);
+ } else {
+ log_fatal ("%s: no such host", relay);
+ }
+ }
+ }
+
/* Default to the DHCP/BOOTP port. */
if (!local_port) {
- ent = getservbyname ("dhcpc", "udp");
- if (!ent)
- local_port = htons (68);
- else
- local_port = ent -> s_port;
+ if (relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) {
+ local_port = htons (67);
+ } else {
+ ent = getservbyname ("dhcpc", "udp");
+ if (!ent)
+ local_port = htons (68);
+ else
+ local_port = ent -> s_port;
#ifndef __CYGWIN32__
- endservent ();
+ endservent ();
#endif
+ }
}
- remote_port = htons (ntohs (local_port) - 1); /* XXX */
+
+ /* If we're faking a relay agent, and we're not using loopback,
+ use the server port, not the client port. */
+ if (relay && giaddr.s_addr != htonl (INADDR_LOOPBACK)) {
+ local_port = htons (ntohs (local_port) - 1);
+ remote_port = local_port;
+ } else
+ remote_port = htons (ntohs (local_port) - 1); /* XXX */
/* Get the current time... */
GET_TIME (&cur_time);
sockaddr_broadcast.sin_family = AF_INET;
sockaddr_broadcast.sin_port = remote_port;
- sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
-#ifdef HAVE_SA_LEN
- sockaddr_broadcast.sin_len = sizeof sockaddr_broadcast;
-#endif
+ if (server) {
+ if (!inet_aton (server, &sockaddr_broadcast.sin_addr)) {
+ struct hostent *he;
+ he = gethostbyname (server);
+ if (he) {
+ memcpy (&sockaddr_broadcast.sin_addr,
+ he -> h_addr_list [0],
+ sizeof sockaddr_broadcast.sin_addr);
+ } else
+ sockaddr_broadcast.sin_addr.s_addr =
+ INADDR_BROADCAST;
+ }
+ } else {
+ sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
+ }
+
inaddr_any.s_addr = INADDR_ANY;
/* Discover all the network interfaces. */
@@ -219,17 +346,26 @@ int main (argc, argv, envp)
/* Rewrite the lease database... */
rewrite_client_leases ();
+ /* XXX */
+/* config_counter(&snd_counter, &rcv_counter); */
+
/* If no broadcast interfaces were discovered, call the script
and tell it so. */
if (!interfaces) {
- script_init ((struct interface_info *)0, "NBI",
+ /* Call dhclient-script with the NBI flag, in case somebody
+ cares. */
+ script_init ((struct client_state *)0, "NBI",
(struct string_list *)0);
- script_go ((struct interface_info *)0);
-
- note ("No broadcast interfaces found - exiting.");
- /* Nothing more to do. */
- exit (0);
- } else {
+ script_go ((struct client_state *)0);
+
+ /* If we haven't been asked to persist, waiting for new
+ interfaces, then just exit. */
+ if (!persist) {
+ /* Nothing more to do. */
+ log_info ("No broadcast interfaces found - exiting.");
+ exit (0);
+ }
+ } else if (!release_mode) {
/* Call the script with the list of interfaces. */
for (ip = interfaces; ip; ip = ip -> next) {
/* If interfaces were specified, don't configure
@@ -239,11 +375,12 @@ int main (argc, argv, envp)
INTERFACE_AUTOMATIC)) !=
INTERFACE_REQUESTED))
continue;
- script_init (ip, "PREINIT", (struct string_list *)0);
+ script_init (ip -> client,
+ "PREINIT", (struct string_list *)0);
if (ip -> client -> alias)
- script_write_params (ip, "alias_",
+ script_write_params (ip -> client, "alias_",
ip -> client -> alias);
- script_go (ip);
+ script_go (ip -> client);
}
}
@@ -260,25 +397,71 @@ int main (argc, argv, envp)
interface's hardware address interpreted as an integer.
Not much entropy, but we're booting, so we're not likely to
find anything better. */
- seed = 0; /* Unfortunately, what's on the stack isn't random. :') */
+ seed = 0;
for (ip = interfaces; ip; ip = ip -> next) {
int junk;
memcpy (&junk,
- &ip -> hw_address.haddr [ip -> hw_address.hlen -
- sizeof seed], sizeof seed);
+ &ip -> hw_address.hbuf [ip -> hw_address.hlen -
+ sizeof seed], sizeof seed);
seed += junk;
}
srandom (seed + cur_time);
/* Start a configuration state machine for each interface. */
for (ip = interfaces; ip; ip = ip -> next) {
- ip -> client -> state = S_INIT;
- state_reboot (ip);
+ ip -> flags |= INTERFACE_RUNNING;
+ for (client = ip -> client; client; client = client -> next) {
+ if (release_mode)
+ do_release (client);
+ else {
+ client -> state = S_INIT;
+ /* Set up a timeout to start the initialization
+ process. */
+ add_timeout (cur_time + random () % 5,
+ state_reboot, client, 0, 0);
+ }
+ }
+ }
+
+ if (release_mode)
+ return 0;
+
+ /* Start up a listener for the object management API protocol. */
+ if (top_level_config.omapi_port != -1) {
+ listener = (omapi_object_t *)0;
+ result = omapi_generic_new (&listener, MDL);
+ if (result != ISC_R_SUCCESS)
+ log_fatal ("Can't allocate new generic object: %s\n",
+ isc_result_totext (result));
+ result = omapi_protocol_listen (listener,
+ (unsigned)
+ top_level_config.omapi_port,
+ 1);
+ if (result != ISC_R_SUCCESS)
+ log_fatal ("Can't start OMAPI protocol: %s",
+ isc_result_totext (result));
}
/* Set up the bootp packet handler... */
bootp_packet_handler = do_packet;
+#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ dmalloc_cutoff_generation = dmalloc_generation;
+ dmalloc_longterm = dmalloc_outstanding;
+ dmalloc_outstanding = 0;
+#endif
+
+ /* If we're not supposed to wait before getting the address,
+ don't. */
+ if (nowait)
+ go_daemon ();
+
+ /* If we're not going to daemonize, write the pid file
+ now. */
+ if (no_daemon || nowait)
+ write_client_pid_file ();
+
/* Start dispatching packets and timeouts... */
dispatch ();
@@ -286,23 +469,51 @@ int main (argc, argv, envp)
return 0;
}
-static void usage (appname)
- char *appname;
+static void usage ()
+{
+ log_info ("%s %s", message, DHCP_VERSION);
+ log_info (copyright);
+ log_info (arr);
+ log_info (url);
+
+ log_error ("Usage: dhclient [-1dqr] [-nw] [-p <port>] %s",
+ "[-s server]");
+ log_error (" [-cf config-file] [-lf lease-file]%s",
+ "[-pf pid-file] [-e VAR=val]");
+ log_fatal (" [-sf script-file] [interface]");
+}
+
+isc_result_t find_class (struct class **c,
+ const char *s, const char *file, int line)
{
- note (message);
- note (copyright);
- note (arr);
- note ("");
- note (contrib);
- note (url);
- note ("");
-
- warn ("Usage: %s [-c] [-p <port>] [-lf lease-file]", appname);
- error (" [-pf pidfile] [interface]");
+ return 0;
}
-void cleanup ()
+int check_collection (packet, lease, collection)
+ struct packet *packet;
+ struct lease *lease;
+ struct collection *collection;
{
+ return 0;
+}
+
+void classify (packet, class)
+ struct packet *packet;
+ struct class *class;
+{
+}
+
+int unbill_class (lease, class)
+ struct lease *lease;
+ struct class *class;
+{
+ return 0;
+}
+
+int find_subnet (struct subnet **sp,
+ struct iaddr addr, const char *file, int line)
+{
+ return 0;
}
/* Individual States:
@@ -334,152 +545,141 @@ void cleanup ()
* can no longer legitimately use the lease.
*/
-void state_reboot (ipp)
- void *ipp;
+void state_reboot (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
+ struct client_state *client = cpp;
/* If we don't remember an active lease, go straight to INIT. */
- if (!ip -> client -> active ||
- ip -> client -> active -> is_bootp) {
- state_init (ip);
+ if (!client -> active ||
+ client -> active -> is_bootp ||
+ client -> active -> expiry <= cur_time) {
+ state_init (client);
return;
}
/* We are in the rebooting state. */
- ip -> client -> state = S_REBOOTING;
+ client -> state = S_REBOOTING;
/* make_request doesn't initialize xid because it normally comes
from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
so pick an xid now. */
- ip -> client -> xid = random ();
+ client -> xid = random ();
/* Make a DHCPREQUEST packet, and set appropriate per-interface
flags. */
- make_request (ip, ip -> client -> active);
- ip -> client -> destination = iaddr_broadcast;
- ip -> client -> first_sending = cur_time;
- ip -> client -> interval = ip -> client -> config -> initial_interval;
+ make_request (client, client -> active);
+ client -> destination = iaddr_broadcast;
+ client -> first_sending = cur_time;
+ client -> interval = client -> config -> initial_interval;
/* Zap the medium list... */
- ip -> client -> medium = (struct string_list *)0;
+ client -> medium = (struct string_list *)0;
/* Send out the first DHCPREQUEST packet. */
- send_request (ip);
+ send_request (client);
}
/* Called when a lease has completely expired and we've been unable to
renew it. */
-void state_init (ipp)
- void *ipp;
+void state_init (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
+ struct client_state *client = cpp;
ASSERT_STATE(state, S_INIT);
/* Make a DHCPDISCOVER packet, and set appropriate per-interface
flags. */
- make_discover (ip, ip -> client -> active);
- ip -> client -> xid = ip -> client -> packet.xid;
- ip -> client -> destination = iaddr_broadcast;
- ip -> client -> state = S_SELECTING;
- ip -> client -> first_sending = cur_time;
- ip -> client -> interval = ip -> client -> config -> initial_interval;
+ make_discover (client, client -> active);
+ client -> xid = client -> packet.xid;
+ client -> destination = iaddr_broadcast;
+ client -> state = S_SELECTING;
+ client -> first_sending = cur_time;
+ client -> interval = client -> config -> initial_interval;
/* Add an immediate timeout to cause the first DHCPDISCOVER packet
to go out. */
- send_discover (ip);
+ send_discover (client);
}
/* state_selecting is called when one or more DHCPOFFER packets have been
received and a configurable period of time has passed. */
-void state_selecting (ipp)
- void *ipp;
+void state_selecting (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
-
+ struct client_state *client = cpp;
struct client_lease *lp, *next, *picked;
+
ASSERT_STATE(state, S_SELECTING);
/* Cancel state_selecting and send_discover timeouts, since either
one could have got us here. */
- cancel_timeout (state_selecting, ip);
- cancel_timeout (send_discover, ip);
+ cancel_timeout (state_selecting, client);
+ cancel_timeout (send_discover, client);
/* We have received one or more DHCPOFFER packets. Currently,
the only criterion by which we judge leases is whether or
not we get a response when we arp for them. */
picked = (struct client_lease *)0;
- for (lp = ip -> client -> offered_leases; lp; lp = next) {
+ for (lp = client -> offered_leases; lp; lp = next) {
next = lp -> next;
/* Check to see if we got an ARPREPLY for the address
in this particular lease. */
if (!picked) {
- script_init (ip, "ARPCHECK", lp -> medium);
- script_write_params (ip, "check_", lp);
-
- /* If the ARPCHECK code detects another
- machine using the offered address, it exits
- nonzero. We need to send a DHCPDECLINE and
- toss the lease. */
- if (script_go (ip)) {
- make_decline (ip, lp);
- send_decline (ip);
- goto freeit;
- }
picked = lp;
picked -> next = (struct client_lease *)0;
} else {
freeit:
- free_client_lease (lp);
+ destroy_client_lease (lp);
}
}
- ip -> client -> offered_leases = (struct client_lease *)0;
+ client -> offered_leases = (struct client_lease *)0;
/* If we just tossed all the leases we were offered, go back
to square one. */
if (!picked) {
- ip -> client -> state = S_INIT;
- state_init (ip);
+ client -> state = S_INIT;
+ state_init (client);
return;
}
/* If it was a BOOTREPLY, we can just take the address right now. */
- if (!picked -> options [DHO_DHCP_MESSAGE_TYPE].len) {
- ip -> client -> new = picked;
+ if (picked -> is_bootp) {
+ client -> new = picked;
/* Make up some lease expiry times
XXX these should be configurable. */
- ip -> client -> new -> expiry = cur_time + 12000;
- ip -> client -> new -> renewal += cur_time + 8000;
- ip -> client -> new -> rebind += cur_time + 10000;
+ client -> new -> expiry = cur_time + 12000;
+ client -> new -> renewal += cur_time + 8000;
+ client -> new -> rebind += cur_time + 10000;
- ip -> client -> state = S_REQUESTING;
+ client -> state = S_REQUESTING;
/* Bind to the address we received. */
- bind_lease (ip);
+ bind_lease (client);
return;
}
/* Go to the REQUESTING state. */
- ip -> client -> destination = iaddr_broadcast;
- ip -> client -> state = S_REQUESTING;
- ip -> client -> first_sending = cur_time;
- ip -> client -> interval = ip -> client -> config -> initial_interval;
+ client -> destination = iaddr_broadcast;
+ client -> state = S_REQUESTING;
+ client -> first_sending = cur_time;
+ client -> interval = client -> config -> initial_interval;
/* Make a DHCPREQUEST packet from the lease we picked. */
- make_request (ip, picked);
- ip -> client -> xid = ip -> client -> packet.xid;
+ make_request (client, picked);
+ client -> xid = client -> packet.xid;
/* Toss the lease we picked - we'll get it back in a DHCPACK. */
- free_client_lease (picked);
+ destroy_client_lease (picked);
/* Add an immediate timeout to send the first DHCPREQUEST packet. */
- send_request (ip);
+ send_request (client);
}
/* state_requesting is called when we receive a DHCPACK message after
@@ -489,128 +689,200 @@ void dhcpack (packet)
struct packet *packet;
{
struct interface_info *ip = packet -> interface;
+ struct client_state *client;
struct client_lease *lease;
+ struct option_cache *oc;
+ struct data_string ds;
+ int i;
/* If we're not receptive to an offer right now, or if the offer
has an unrecognizable transaction id, then just drop it. */
- if (packet -> interface -> client -> xid != packet -> raw -> xid ||
- (packet -> interface -> hw_address.hlen !=
+ for (client = ip -> client; client; client = client -> next) {
+ if (client -> xid == packet -> raw -> xid)
+ break;
+ }
+ if (!client ||
+ (packet -> interface -> hw_address.hlen - 1 !=
packet -> raw -> hlen) ||
- (memcmp (packet -> interface -> hw_address.haddr,
+ (memcmp (&packet -> interface -> hw_address.hbuf [1],
packet -> raw -> chaddr, packet -> raw -> hlen))) {
#if defined (DEBUG)
- debug ("DHCPACK in wrong transaction.");
+ log_debug ("DHCPACK in wrong transaction.");
#endif
return;
}
- if (ip -> client -> state != S_REBOOTING &&
- ip -> client -> state != S_REQUESTING &&
- ip -> client -> state != S_RENEWING &&
- ip -> client -> state != S_REBINDING) {
+ if (client -> state != S_REBOOTING &&
+ client -> state != S_REQUESTING &&
+ client -> state != S_RENEWING &&
+ client -> state != S_REBINDING) {
#if defined (DEBUG)
- debug ("DHCPACK in wrong state.");
+ log_debug ("DHCPACK in wrong state.");
#endif
return;
}
- note ("DHCPACK from %s", piaddr (packet -> client_addr));
+ log_info ("DHCPACK from %s", piaddr (packet -> client_addr));
- lease = packet_to_lease (packet);
+ lease = packet_to_lease (packet, client);
if (!lease) {
- note ("packet_to_lease failed.");
+ log_info ("packet_to_lease failed.");
return;
}
- ip -> client -> new = lease;
+ client -> new = lease;
/* Stop resending DHCPREQUEST. */
- cancel_timeout (send_request, ip);
+ cancel_timeout (send_request, client);
/* Figure out the lease time. */
- ip -> client -> new -> expiry =
- getULong (ip -> client ->
- new -> options [DHO_DHCP_LEASE_TIME].data);
+ oc = lookup_option (&dhcp_universe, client -> new -> options,
+ DHO_DHCP_LEASE_TIME);
+ memset (&ds, 0, sizeof ds);
+ if (oc &&
+ evaluate_option_cache (&ds, packet, (struct lease *)0, client,
+ packet -> options, client -> new -> options,
+ &global_scope, oc, MDL)) {
+ if (ds.len > 3)
+ client -> new -> expiry = getULong (ds.data);
+ else
+ client -> new -> expiry = 0;
+ data_string_forget (&ds, MDL);
+ } else
+ client -> new -> expiry = 0;
+
+ if (!client -> new -> expiry) {
+ log_error ("no expiry time on offered lease.");
+ /* XXX this is going to be bad - if this _does_
+ XXX happen, we should probably dynamically
+ XXX disqualify the DHCP server that gave us the
+ XXX bad packet from future selections and
+ XXX then go back into the init state. */
+ state_init (client);
+ return;
+ }
+
/* A number that looks negative here is really just very large,
because the lease expiry offset is unsigned. */
- if (ip -> client -> new -> expiry < 0)
- ip -> client -> new -> expiry = TIME_MAX;
-
- /* Take the server-provided renewal time if there is one;
- otherwise figure it out according to the spec. */
- if (ip -> client -> new -> options [DHO_DHCP_RENEWAL_TIME].len)
- ip -> client -> new -> renewal =
- getULong (ip -> client ->
- new -> options [DHO_DHCP_RENEWAL_TIME].data);
- else
- ip -> client -> new -> renewal =
- ip -> client -> new -> expiry / 2;
+ if (client -> new -> expiry < 0)
+ client -> new -> expiry = TIME_MAX;
+ /* Take the server-provided renewal time if there is one. */
+ oc = lookup_option (&dhcp_universe, client -> new -> options,
+ DHO_DHCP_RENEWAL_TIME);
+ if (oc &&
+ evaluate_option_cache (&ds, packet, (struct lease *)0, client,
+ packet -> options, client -> new -> options,
+ &global_scope, oc, MDL)) {
+ if (ds.len > 3)
+ client -> new -> renewal = getULong (ds.data);
+ else
+ client -> new -> renewal = 0;
+ data_string_forget (&ds, MDL);
+ } else
+ client -> new -> renewal = 0;
+
+ /* If it wasn't specified by the server, calculate it. */
+ if (!client -> new -> renewal)
+ client -> new -> renewal =
+ client -> new -> expiry / 2;
+
+ /* Now introduce some randomness to the renewal time: */
+ client -> new -> renewal = (((client -> new -> renewal + 3) * 3 / 4) +
+ (random () % /* XXX NUMS */
+ ((client -> new -> renewal + 3) / 4)));
/* Same deal with the rebind time. */
- if (ip -> client -> new -> options [DHO_DHCP_REBINDING_TIME].len)
- ip -> client -> new -> rebind =
- getULong (ip -> client -> new ->
- options [DHO_DHCP_REBINDING_TIME].data);
- else
- ip -> client -> new -> rebind =
- ip -> client -> new -> renewal +
- ip -> client -> new -> renewal / 2 +
- ip -> client -> new -> renewal / 4;
+ oc = lookup_option (&dhcp_universe, client -> new -> options,
+ DHO_DHCP_REBINDING_TIME);
+ if (oc &&
+ evaluate_option_cache (&ds, packet, (struct lease *)0, client,
+ packet -> options, client -> new -> options,
+ &global_scope, oc, MDL)) {
+ if (ds.len > 3)
+ client -> new -> rebind = getULong (ds.data);
+ else
+ client -> new -> rebind = 0;
+ data_string_forget (&ds, MDL);
+ } else
+ client -> new -> rebind = 0;
+
+ if (!client -> new -> rebind)
+ client -> new -> rebind =
+ (client -> new -> expiry * 7) / 8; /* XXX NUMS */
+
+ /* Make sure our randomness didn't run the renewal time past the
+ rebind time. */
+ if (client -> new -> renewal > client -> new -> rebind)
+ client -> new -> renewal = (client -> new -> rebind * 3) / 4;
- ip -> client -> new -> expiry += cur_time;
+ client -> new -> expiry += cur_time;
/* Lease lengths can never be negative. */
- if (ip -> client -> new -> expiry < cur_time)
- ip -> client -> new -> expiry = TIME_MAX;
- ip -> client -> new -> renewal += cur_time;
- if (ip -> client -> new -> renewal < cur_time)
- ip -> client -> new -> renewal = TIME_MAX;
- ip -> client -> new -> rebind += cur_time;
- if (ip -> client -> new -> rebind < cur_time)
- ip -> client -> new -> rebind = TIME_MAX;
-
- bind_lease (ip);
+ if (client -> new -> expiry < cur_time)
+ client -> new -> expiry = TIME_MAX;
+ client -> new -> renewal += cur_time;
+ if (client -> new -> renewal < cur_time)
+ client -> new -> renewal = TIME_MAX;
+ client -> new -> rebind += cur_time;
+ if (client -> new -> rebind < cur_time)
+ client -> new -> rebind = TIME_MAX;
+
+ bind_lease (client);
}
-void bind_lease (ip)
- struct interface_info *ip;
+void bind_lease (client)
+ struct client_state *client;
{
- /* Remember the medium. */
- ip -> client -> new -> medium = ip -> client -> medium;
+ struct interface_info *ip = client -> interface;
- /* Write out the new lease. */
- write_client_lease (ip, ip -> client -> new, 0);
+ /* Remember the medium. */
+ client -> new -> medium = client -> medium;
/* Run the client script with the new parameters. */
- script_init (ip, (ip -> client -> state == S_REQUESTING
+ script_init (client, (client -> state == S_REQUESTING
? "BOUND"
- : (ip -> client -> state == S_RENEWING
+ : (client -> state == S_RENEWING
? "RENEW"
- : (ip -> client -> state == S_REBOOTING
+ : (client -> state == S_REBOOTING
? "REBOOT" : "REBIND"))),
- ip -> client -> new -> medium);
- if (ip -> client -> active && ip -> client -> state != S_REBOOTING)
- script_write_params (ip, "old_", ip -> client -> active);
- script_write_params (ip, "new_", ip -> client -> new);
- if (ip -> client -> alias)
- script_write_params (ip, "alias_", ip -> client -> alias);
- script_go (ip);
+ client -> new -> medium);
+ if (client -> active && client -> state != S_REBOOTING)
+ script_write_params (client, "old_", client -> active);
+ script_write_params (client, "new_", client -> new);
+ if (client -> alias)
+ script_write_params (client, "alias_", client -> alias);
+
+ /* If the BOUND/RENEW code detects another machine using the
+ offered address, it exits nonzero. We need to send a
+ DHCPDECLINE and toss the lease. */
+ if (script_go (client)) {
+ make_decline (client, client -> new);
+ send_decline (client);
+ destroy_client_lease (client -> new);
+ client -> new = (struct client_lease *)0;
+ state_init (client);
+ return;
+ }
+
+ /* Write out the new lease. */
+ write_client_lease (client, client -> new, 0, 0);
/* Replace the old active lease with the new one. */
- if (ip -> client -> active)
- free_client_lease (ip -> client -> active);
- ip -> client -> active = ip -> client -> new;
- ip -> client -> new = (struct client_lease *)0;
+ if (client -> active)
+ destroy_client_lease (client -> active);
+ client -> active = client -> new;
+ client -> new = (struct client_lease *)0;
/* Set up a timeout to start the renewal process. */
- add_timeout (ip -> client -> active -> renewal,
- state_bound, ip);
+ add_timeout (client -> active -> renewal,
+ state_bound, client, 0, 0);
- note ("bound to %s -- renewal in %d seconds.",
- piaddr (ip -> client -> active -> address),
- ip -> client -> active -> renewal - cur_time);
- ip -> client -> state = S_BOUND;
+ log_info ("bound to %s -- renewal in %ld seconds.",
+ piaddr (client -> active -> address),
+ (long)(client -> active -> renewal - cur_time));
+ client -> state = S_BOUND;
reinitialize_interfaces ();
go_daemon ();
+ client_dns_update (client, 1);
}
/* state_bound is called when we've successfully bound to a particular
@@ -618,32 +890,68 @@ void bind_lease (ip)
expected to unicast a DHCPREQUEST to the server that gave us our
original lease. */
-void state_bound (ipp)
- void *ipp;
+void state_bound (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
+ struct client_state *client = cpp;
+ int i;
+ struct option_cache *oc;
+ struct data_string ds;
ASSERT_STATE(state, S_BOUND);
/* T1 has expired. */
- make_request (ip, ip -> client -> active);
- ip -> client -> xid = ip -> client -> packet.xid;
-
- if (ip -> client -> active ->
- options [DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
- memcpy (ip -> client -> destination.iabuf,
- ip -> client -> active ->
- options [DHO_DHCP_SERVER_IDENTIFIER].data, 4);
- ip -> client -> destination.len = 4;
+ make_request (client, client -> active);
+ client -> xid = client -> packet.xid;
+
+ 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,
+ client, (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
- ip -> client -> destination = iaddr_broadcast;
+ client -> destination = iaddr_broadcast;
- ip -> client -> first_sending = cur_time;
- ip -> client -> interval = ip -> client -> config -> initial_interval;
- ip -> client -> state = S_RENEWING;
+ client -> first_sending = cur_time;
+ client -> interval = client -> config -> initial_interval;
+ client -> state = S_RENEWING;
/* Send the first packet immediately. */
- send_request (ip);
+ send_request (client);
+}
+
+/* state_stop is called when we've been told to shut down. We unconfigure
+ the interfaces, and then stop operating until told otherwise. */
+
+void state_stop (cpp)
+ void *cpp;
+{
+ struct client_state *client = cpp;
+ int i;
+
+ /* Cancel all timeouts. */
+ cancel_timeout (state_selecting, client);
+ cancel_timeout (send_discover, client);
+ cancel_timeout (send_request, client);
+ cancel_timeout (state_bound, client);
+
+ /* If we have an address, unconfigure it. */
+ if (client -> active) {
+ script_init (client, "STOP", client -> active -> medium);
+ script_write_params (client, "old_", client -> active);
+ if (client -> alias)
+ script_write_params (client, "alias_",
+ client -> alias);
+ script_go (client);
+ }
}
int commit_leases ()
@@ -657,7 +965,14 @@ int write_lease (lease)
return 0;
}
-void db_startup ()
+int write_host (host)
+ struct host_decl *host;
+{
+ return 0;
+}
+
+void db_startup (testp)
+ int testp;
{
}
@@ -674,7 +989,7 @@ void bootp (packet)
for (ap = packet -> interface -> client -> config -> reject_list;
ap; ap = ap -> next) {
if (addr_eq (packet -> client_addr, ap -> addr)) {
- note ("BOOTREPLY from %s rejected.",
+ log_info ("BOOTREPLY from %s rejected.",
piaddr (ap -> addr));
return;
}
@@ -689,7 +1004,7 @@ void dhcp (packet)
{
struct iaddrlist *ap;
void (*handler) PROTO ((struct packet *));
- char *type;
+ const char *type;
switch (packet -> packet_type) {
case DHCPOFFER:
@@ -716,7 +1031,7 @@ void dhcp (packet)
for (ap = packet -> interface -> client -> config -> reject_list;
ap; ap = ap -> next) {
if (addr_eq (packet -> client_addr, ap -> addr)) {
- note ("%s from %s rejected.",
+ log_info ("%s from %s rejected.",
type, piaddr (ap -> addr));
return;
}
@@ -728,186 +1043,196 @@ void dhcpoffer (packet)
struct packet *packet;
{
struct interface_info *ip = packet -> interface;
+ struct client_state *client;
struct client_lease *lease, *lp;
int i;
- int arp_timeout_needed, stop_selecting;
- char *name = (packet -> options [DHO_DHCP_MESSAGE_TYPE].len
- ? "DHCPOFFER" : "BOOTREPLY");
+ int stop_selecting;
+ const char *name = packet -> packet_type ? "DHCPOFFER" : "BOOTREPLY";
+ struct iaddrlist *ap;
+ struct option_cache *oc;
+ char obuf [1024];
#ifdef DEBUG_PACKET
dump_packet (packet);
#endif
+ /* Find a client state that matches the xid... */
+ for (client = ip -> client; client; client = client -> next)
+ if (client -> xid == packet -> raw -> xid)
+ break;
+
/* If we're not receptive to an offer right now, or if the offer
has an unrecognizable transaction id, then just drop it. */
- if (ip -> client -> state != S_SELECTING ||
- packet -> interface -> client -> xid != packet -> raw -> xid ||
- (packet -> interface -> hw_address.hlen !=
+ if (!client ||
+ client -> state != S_SELECTING ||
+ (packet -> interface -> hw_address.hlen - 1 !=
packet -> raw -> hlen) ||
- (memcmp (packet -> interface -> hw_address.haddr,
+ (memcmp (&packet -> interface -> hw_address.hbuf [1],
packet -> raw -> chaddr, packet -> raw -> hlen))) {
#if defined (DEBUG)
- debug ("%s in wrong transaction.", name);
+ log_debug ("%s in wrong transaction.", name);
#endif
return;
}
- note ("%s from %s", name, piaddr (packet -> client_addr));
+ sprintf (obuf, "%s from %s", name, piaddr (packet -> client_addr));
/* If this lease doesn't supply the minimum required parameters,
blow it off. */
- for (i = 0; ip -> client -> config -> required_options [i]; i++) {
- if (!packet -> options [ip -> client -> config ->
- required_options [i]].len) {
- note ("%s isn't satisfactory.", name);
- return;
+ if (client -> config -> required_options) {
+ for (i = 0; client -> config -> required_options [i]; i++) {
+ if (!lookup_option
+ (&dhcp_universe, packet -> options,
+ client -> config -> required_options [i])) {
+ log_info ("%s: no %s option.",
+ obuf, (dhcp_universe.options
+ [client -> config -> required_options [i]]
+ -> name));
+ return;
+ }
}
}
/* If we've already seen this lease, don't record it again. */
- for (lease = ip -> client -> offered_leases;
- lease; lease = lease -> next) {
+ for (lease = client -> offered_leases; lease; lease = lease -> next) {
if (lease -> address.len == sizeof packet -> raw -> yiaddr &&
!memcmp (lease -> address.iabuf,
&packet -> raw -> yiaddr, lease -> address.len)) {
- debug ("%s already seen.", name);
+ log_debug ("%s: already seen.", obuf);
return;
}
}
- lease = packet_to_lease (packet);
+ lease = packet_to_lease (packet, client);
if (!lease) {
- note ("packet_to_lease failed.");
+ log_info ("%s: packet_to_lease failed.", obuf);
return;
}
/* If this lease was acquired through a BOOTREPLY, record that
fact. */
- if (!packet -> options [DHO_DHCP_MESSAGE_TYPE].len)
+ if (!packet -> options_valid || !packet -> packet_type)
lease -> is_bootp = 1;
/* Record the medium under which this lease was offered. */
- lease -> medium = ip -> client -> medium;
-
- /* Send out an ARP Request for the offered IP address. */
- script_init (ip, "ARPSEND", lease -> medium);
- script_write_params (ip, "check_", lease);
- /* If the script can't send an ARP request without waiting,
- we'll be waiting when we do the ARPCHECK, so don't wait now. */
- if (script_go (ip))
- arp_timeout_needed = 0;
- else
- arp_timeout_needed = 2;
+ lease -> medium = client -> medium;
/* Figure out when we're supposed to stop selecting. */
- stop_selecting = (ip -> client -> first_sending +
- ip -> client -> config -> select_interval);
+ stop_selecting = (client -> first_sending +
+ client -> config -> select_interval);
/* If this is the lease we asked for, put it at the head of the
list, and don't mess with the arp request timeout. */
- if (lease -> address.len == ip -> client -> requested_address.len &&
+ if (lease -> address.len == client -> requested_address.len &&
!memcmp (lease -> address.iabuf,
- ip -> client -> requested_address.iabuf,
- ip -> client -> requested_address.len)) {
- lease -> next = ip -> client -> offered_leases;
- ip -> client -> offered_leases = lease;
+ client -> requested_address.iabuf,
+ client -> requested_address.len)) {
+ lease -> next = client -> offered_leases;
+ client -> offered_leases = lease;
} else {
- /* If we already have an offer, and arping for this
- offer would take us past the selection timeout,
- then don't extend the timeout - just hope for the
- best. */
- if (ip -> client -> offered_leases &&
- (cur_time + arp_timeout_needed) > stop_selecting)
- arp_timeout_needed = 0;
-
/* Put the lease at the end of the list. */
lease -> next = (struct client_lease *)0;
- if (!ip -> client -> offered_leases)
- ip -> client -> offered_leases = lease;
+ if (!client -> offered_leases)
+ client -> offered_leases = lease;
else {
- for (lp = ip -> client -> offered_leases; lp -> next;
+ for (lp = client -> offered_leases; lp -> next;
lp = lp -> next)
;
lp -> next = lease;
}
}
- /* If we're supposed to stop selecting before we've had time
- to wait for the ARPREPLY, add some delay to wait for
- the ARPREPLY. */
- if (stop_selecting - cur_time < arp_timeout_needed)
- stop_selecting = cur_time + arp_timeout_needed;
-
/* If the selecting interval has expired, go immediately to
state_selecting(). Otherwise, time out into
state_selecting at the select interval. */
if (stop_selecting <= 0)
- state_selecting (ip);
+ state_selecting (client);
else {
- add_timeout (stop_selecting, state_selecting, ip);
- cancel_timeout (send_discover, ip);
+ add_timeout (stop_selecting, state_selecting, client, 0, 0);
+ cancel_timeout (send_discover, client);
}
+ log_info ("%s", obuf);
}
/* Allocate a client_lease structure and initialize it from the parameters
in the specified packet. */
-struct client_lease *packet_to_lease (packet)
+struct client_lease *packet_to_lease (packet, client)
struct packet *packet;
+ struct client_state *client;
{
struct client_lease *lease;
- int i;
+ unsigned i;
+ struct option_cache *oc;
+ struct data_string data;
- lease = (struct client_lease *)malloc (sizeof (struct client_lease));
+ lease = (struct client_lease *)new_client_lease (MDL);
if (!lease) {
- warn ("dhcpoffer: no memory to record lease.\n");
+ log_error ("packet_to_lease: no memory to record lease.\n");
return (struct client_lease *)0;
}
memset (lease, 0, sizeof *lease);
/* Copy the lease options. */
- for (i = 0; i < 256; i++) {
- if (packet -> options [i].len) {
- lease -> options [i].data =
- (unsigned char *)
- malloc (packet -> options [i].len + 1);
- if (!lease -> options [i].data) {
- warn ("dhcpoffer: no memory for option %d\n",
- i);
- free_client_lease (lease);
- return (struct client_lease *)0;
- } else {
- memcpy (lease -> options [i].data,
- packet -> options [i].data,
- packet -> options [i].len);
- lease -> options [i].len =
- packet -> options [i].len;
- lease -> options [i].data
- [lease -> options [i].len] = 0;
- }
- }
- }
+ option_state_reference (&lease -> options, packet -> options, MDL);
lease -> address.len = sizeof (packet -> raw -> yiaddr);
memcpy (lease -> address.iabuf, &packet -> raw -> yiaddr,
lease -> address.len);
+ if (client -> config -> vendor_space_name) {
+ i = DHO_VENDOR_ENCAPSULATED_OPTIONS;
+
+ /* See if there was a vendor encapsulation option. */
+ oc = lookup_option (&dhcp_universe, lease -> options, i);
+ memset (&data, 0, sizeof data);
+ if (oc &&
+ client -> config -> vendor_space_name &&
+ evaluate_option_cache (&data, packet,
+ (struct lease *)0, client,
+ packet -> options, lease -> options,
+ &global_scope, oc, MDL)) {
+ if (data.len) {
+ parse_encapsulated_suboptions
+ (packet -> options, &dhcp_options [i],
+ data.data, data.len, &dhcp_universe,
+ client -> config -> vendor_space_name
+ );
+ }
+ data_string_forget (&data, MDL);
+ }
+ } else
+ i = 0;
+
+ /* Figure out the overload flag. */
+ oc = lookup_option (&dhcp_universe, lease -> options,
+ DHO_DHCP_OPTION_OVERLOAD);
+ if (oc &&
+ evaluate_option_cache (&data, packet, (struct lease *)0, client,
+ packet -> options, lease -> options,
+ &global_scope, oc, MDL)) {
+ if (data.len > 0)
+ i = data.data [0];
+ else
+ i = 0;
+ data_string_forget (&data, MDL);
+ } else
+ i = 0;
+
/* If the server name was filled out, copy it. */
- if ((!packet -> options [DHO_DHCP_OPTION_OVERLOAD].len ||
- !(packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 2)) &&
- packet -> raw -> sname [0]) {
- int len;
+ if (!(i & 2) && packet -> raw -> sname [0]) {
+ unsigned len;
/* Don't count on the NUL terminator. */
for (len = 0; len < 64; len++)
if (!packet -> raw -> sname [len])
break;
- lease -> server_name = malloc (len + 1);
+ lease -> server_name = dmalloc (len + 1, MDL);
if (!lease -> server_name) {
- warn ("dhcpoffer: no memory for filename.\n");
- free_client_lease (lease);
+ log_error ("dhcpoffer: no memory for filename.\n");
+ destroy_client_lease (lease);
return (struct client_lease *)0;
} else {
memcpy (lease -> server_name,
@@ -917,18 +1242,16 @@ struct client_lease *packet_to_lease (packet)
}
/* Ditto for the filename. */
- if ((!packet -> options [DHO_DHCP_OPTION_OVERLOAD].len ||
- !(packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 1)) &&
- packet -> raw -> file [0]) {
- int len;
+ if (!(i & 1) && packet -> raw -> file [0]) {
+ unsigned len;
/* Don't count on the NUL terminator. */
for (len = 0; len < 64; len++)
if (!packet -> raw -> file [len])
break;
- lease -> filename = malloc (len + 1);
+ lease -> filename = dmalloc (len + 1, MDL);
if (!lease -> filename) {
- warn ("dhcpoffer: no memory for filename.\n");
- free_client_lease (lease);
+ log_error ("dhcpoffer: no memory for filename.\n");
+ destroy_client_lease (lease);
return (struct client_lease *)0;
} else {
memcpy (lease -> filename,
@@ -936,6 +1259,15 @@ struct client_lease *packet_to_lease (packet)
lease -> filename [len] = 0;
}
}
+
+ execute_statements_in_scope ((struct binding_value **)0,
+ (struct packet *)packet,
+ (struct lease *)0, client,
+ lease -> options, lease -> options,
+ &global_scope,
+ client -> config -> on_receipt,
+ (struct group *)0);
+
return lease;
}
@@ -943,95 +1275,103 @@ void dhcpnak (packet)
struct packet *packet;
{
struct interface_info *ip = packet -> interface;
+ struct client_state *client;
+
+ /* Find a client state that matches the xid... */
+ for (client = ip -> client; client; client = client -> next)
+ if (client -> xid == packet -> raw -> xid)
+ break;
/* If we're not receptive to an offer right now, or if the offer
has an unrecognizable transaction id, then just drop it. */
- if (packet -> interface -> client -> xid != packet -> raw -> xid ||
- (packet -> interface -> hw_address.hlen !=
+ if (!client ||
+ (packet -> interface -> hw_address.hlen - 1 !=
packet -> raw -> hlen) ||
- (memcmp (packet -> interface -> hw_address.haddr,
+ (memcmp (&packet -> interface -> hw_address.hbuf [1],
packet -> raw -> chaddr, packet -> raw -> hlen))) {
#if defined (DEBUG)
- debug ("DHCPNAK in wrong transaction.");
+ log_debug ("DHCPNAK in wrong transaction.");
#endif
return;
}
- if (ip -> client -> state != S_REBOOTING &&
- ip -> client -> state != S_REQUESTING &&
- ip -> client -> state != S_RENEWING &&
- ip -> client -> state != S_REBINDING) {
+ if (client -> state != S_REBOOTING &&
+ client -> state != S_REQUESTING &&
+ client -> state != S_RENEWING &&
+ client -> state != S_REBINDING) {
#if defined (DEBUG)
- debug ("DHCPNAK in wrong state.");
+ log_debug ("DHCPNAK in wrong state.");
#endif
return;
}
- note ("DHCPNAK from %s", piaddr (packet -> client_addr));
+ log_info ("DHCPNAK from %s", piaddr (packet -> client_addr));
- if (!ip -> client -> active) {
- note ("DHCPNAK with no active lease.\n");
+ if (!client -> active) {
+#if defined (DEBUG)
+ log_info ("DHCPNAK with no active lease.\n");
+#endif
return;
}
- free_client_lease (ip -> client -> active);
- ip -> client -> active = (struct client_lease *)0;
+ destroy_client_lease (client -> active);
+ client -> active = (struct client_lease *)0;
/* Stop sending DHCPREQUEST packets... */
- cancel_timeout (send_request, ip);
+ cancel_timeout (send_request, client);
- ip -> client -> state = S_INIT;
- state_init (ip);
+ client -> state = S_INIT;
+ state_init (client);
}
/* Send out a DHCPDISCOVER packet, and set a timeout to send out another
one after the right interval has expired. If we don't get an offer by
the time we reach the panic interval, call the panic function. */
-void send_discover (ipp)
- void *ipp;
+void send_discover (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
+ struct client_state *client = cpp;
int result;
int interval;
int increase = 1;
/* Figure out how long it's been since we started transmitting. */
- interval = cur_time - ip -> client -> first_sending;
+ interval = cur_time - client -> first_sending;
/* If we're past the panic timeout, call the script and tell it
we haven't found anything for this interface yet. */
- if (interval > ip -> client -> config -> timeout) {
- state_panic (ip);
+ if (interval > client -> config -> timeout) {
+ state_panic (client);
return;
}
/* If we're selecting media, try the whole list before doing
the exponential backoff, but if we've already received an
offer, stop looping, because we obviously have it right. */
- if (!ip -> client -> offered_leases &&
- ip -> client -> config -> media) {
+ if (!client -> offered_leases &&
+ client -> config -> media) {
int fail = 0;
again:
- if (ip -> client -> medium) {
- ip -> client -> medium =
- ip -> client -> medium -> next;
+ if (client -> medium) {
+ client -> medium = client -> medium -> next;
increase = 0;
}
- if (!ip -> client -> medium) {
+ if (!client -> medium) {
if (fail)
- error ("No valid media types for %s!",
- ip -> name);
- ip -> client -> medium =
- ip -> client -> config -> media;
+ log_fatal ("No valid media types for %s!",
+ client -> interface -> name);
+ client -> medium =
+ client -> config -> media;
increase = 1;
}
- note ("Trying medium \"%s\" %d",
- ip -> client -> medium -> string, increase);
- script_init (ip, "MEDIUM", ip -> client -> medium);
- if (script_go (ip)) {
+ log_info ("Trying medium \"%s\" %d",
+ client -> medium -> string, increase);
+ script_init (client, "MEDIUM", client -> medium);
+ if (script_go (client)) {
+ fail = 1;
goto again;
}
}
@@ -1042,54 +1382,52 @@ void send_discover (ipp)
zero and two times itself. On average, this means that it
will double with every transmission. */
if (increase) {
- if (!ip -> client -> interval)
- ip -> client -> interval =
- ip -> client -> config -> initial_interval;
- else {
- ip -> client -> interval +=
- ((random () >> 2) %
- (2 * ip -> client -> interval));
- }
+ if (!client -> interval)
+ client -> interval =
+ client -> config -> initial_interval;
+ else
+ client -> interval += ((random () >> 2) %
+ (2 * client -> interval));
/* Don't backoff past cutoff. */
- if (ip -> client -> interval >
- ip -> client -> config -> backoff_cutoff)
- ip -> client -> interval =
- ((ip -> client -> config -> backoff_cutoff / 2)
+ if (client -> interval >
+ client -> config -> backoff_cutoff)
+ client -> interval =
+ ((client -> config -> backoff_cutoff / 2)
+ ((random () >> 2) %
- ip -> client -> config -> backoff_cutoff));
- } else if (!ip -> client -> interval)
- ip -> client -> interval =
- ip -> client -> config -> initial_interval;
+ client -> config -> backoff_cutoff));
+ } else if (!client -> interval)
+ client -> interval = client -> config -> initial_interval;
/* If the backoff would take us to the panic timeout, just use that
as the interval. */
- if (cur_time + ip -> client -> interval >
- ip -> client -> first_sending + ip -> client -> config -> timeout)
- ip -> client -> interval =
- (ip -> client -> first_sending +
- ip -> client -> config -> timeout) - cur_time + 1;
+ if (cur_time + client -> interval >
+ client -> first_sending + client -> config -> timeout)
+ client -> interval =
+ (client -> first_sending +
+ client -> config -> timeout) - cur_time + 1;
/* Record the number of seconds since we started sending. */
if (interval < 65536)
- ip -> client -> packet.secs = htons (interval);
+ client -> packet.secs = htons (interval);
else
- ip -> client -> packet.secs = htons (65535);
- ip -> client -> secs = ip -> client -> packet.secs;
+ client -> packet.secs = htons (65535);
+ client -> secs = client -> packet.secs;
- note ("DHCPDISCOVER on %s to %s port %d interval %ld",
- ip -> name,
+ log_info ("DHCPDISCOVER on %s to %s port %d interval %ld",
+ client -> name ? client -> name : client -> interface -> name,
inet_ntoa (sockaddr_broadcast.sin_addr),
- ntohs (sockaddr_broadcast.sin_port), ip -> client -> interval);
+ ntohs (sockaddr_broadcast.sin_port), (long)(client -> interval));
/* Send out a packet. */
- result = send_packet (ip, (struct packet *)0,
- &ip -> client -> packet,
- ip -> client -> packet_length,
+ result = send_packet (client -> interface, (struct packet *)0,
+ &client -> packet,
+ client -> packet_length,
inaddr_any, &sockaddr_broadcast,
(struct hardware *)0);
- add_timeout (cur_time + ip -> client -> interval, send_discover, ip);
+ add_timeout (cur_time + client -> interval,
+ send_discover, client, 0, 0);
}
/* state_panic gets called if we haven't received any offers in a preset
@@ -1097,106 +1435,113 @@ void send_discover (ipp)
haven't yet expired, and failing that, we call the client script and
hope it can do something. */
-void state_panic (ipp)
- void *ipp;
+void state_panic (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
-
- struct client_lease *loop = ip -> client -> active;
+ struct client_state *client = cpp;
+ struct client_lease *loop;
struct client_lease *lp;
- note ("No DHCPOFFERS received.");
+ loop = lp = client -> active;
+
+ log_info ("No DHCPOFFERS received.");
/* We may not have an active lease, but we may have some
predefined leases that we can try. */
- if (!ip -> client -> active && ip -> client -> leases)
+ if (!client -> active && client -> leases)
goto activate_next;
/* Run through the list of leases and see if one can be used. */
- while (ip -> client -> active) {
- if (ip -> client -> active -> expiry > cur_time) {
- note ("Trying recorded lease %s",
- piaddr (ip -> client -> active -> address));
+ while (client -> active) {
+ if (client -> active -> expiry > cur_time) {
+ log_info ("Trying recorded lease %s",
+ piaddr (client -> active -> address));
/* Run the client script with the existing
parameters. */
- script_init (ip, "TIMEOUT",
- ip -> client -> active -> medium);
- script_write_params (ip, "new_",
- ip -> client -> active);
- if (ip -> client -> alias)
- script_write_params (ip, "alias_",
- ip -> client -> alias);
+ script_init (client, "TIMEOUT",
+ client -> active -> medium);
+ script_write_params (client, "new_", client -> active);
+ if (client -> alias)
+ script_write_params (client, "alias_",
+ client -> alias);
/* If the old lease is still good and doesn't
yet need renewal, go into BOUND state and
timeout at the renewal time. */
- if (!script_go (ip)) {
- if (cur_time <
- ip -> client -> active -> renewal) {
- ip -> client -> state = S_BOUND;
- note ("bound: renewal in %d seconds.",
- ip -> client -> active -> renewal
- - cur_time);
- add_timeout ((ip -> client ->
- active -> renewal),
- state_bound, ip);
- } else {
- ip -> client -> state = S_BOUND;
- note ("bound: immediate renewal.");
- state_bound (ip);
- }
- reinitialize_interfaces ();
- go_daemon ();
- return;
+ if (!script_go (client)) {
+ if (cur_time < client -> active -> renewal) {
+ client -> state = S_BOUND;
+ log_info ("bound: renewal in %ld %s.",
+ (long)(client -> active -> renewal -
+ cur_time), "seconds");
+ add_timeout (client -> active -> renewal,
+ state_bound, client, 0, 0);
+ } else {
+ client -> state = S_BOUND;
+ log_info ("bound: immediate renewal.");
+ state_bound (client);
+ }
+ reinitialize_interfaces ();
+ go_daemon ();
+ return;
}
}
/* If there are no other leases, give up. */
- if (!ip -> client -> leases) {
- ip -> client -> leases = ip -> client -> active;
- ip -> client -> active = (struct client_lease *)0;
+ if (!client -> leases) {
+ client -> leases = client -> active;
+ client -> active = (struct client_lease *)0;
break;
}
activate_next:
/* Otherwise, put the active lease at the end of the
lease list, and try another lease.. */
- for (lp = ip -> client -> leases; lp -> next; lp = lp -> next)
+ for (lp = client -> leases; lp -> next; lp = lp -> next)
;
- lp -> next = ip -> client -> active;
+ lp -> next = client -> active;
if (lp -> next) {
lp -> next -> next = (struct client_lease *)0;
}
- ip -> client -> active = ip -> client -> leases;
- ip -> client -> leases = ip -> client -> leases -> next;
+ client -> active = client -> leases;
+ client -> leases = client -> leases -> next;
/* If we already tried this lease, we've exhausted the
set of leases, so we might as well give up for
now. */
- if (ip -> client -> active == loop)
+ if (client -> active == loop)
break;
else if (!loop)
- loop = ip -> client -> active;
+ loop = client -> active;
}
/* No leases were available, or what was available didn't work, so
tell the shell script that we failed to allocate an address,
and try again later. */
- note ("No working leases in persistent database - sleeping.\n");
- script_init (ip, "FAIL", (struct string_list *)0);
- if (ip -> client -> alias)
- script_write_params (ip, "alias_", ip -> client -> alias);
- script_go (ip);
- ip -> client -> state = S_INIT;
- add_timeout (cur_time + ip -> client -> config -> retry_interval,
- state_init, ip);
+ if (onetry) {
+ if (!quiet)
+ log_info ("Unable to obtain a lease on first try.%s",
+ " Exiting.");
+ exit (2);
+ }
+
+ log_info ("No working leases in persistent database - sleeping.");
+ script_init (client, "FAIL", (struct string_list *)0);
+ if (client -> alias)
+ script_write_params (client, "alias_", client -> alias);
+ script_go (client);
+ client -> state = S_INIT;
+ add_timeout (cur_time +
+ ((client -> config -> retry_interval + 1) / 2 +
+ (random () % client -> config -> retry_interval)),
+ state_init, client, 0, 0);
go_daemon ();
}
-void send_request (ipp)
- void *ipp;
+void send_request (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
+ struct client_state *client = cpp;
int result;
int interval;
@@ -1204,7 +1549,7 @@ void send_request (ipp)
struct in_addr from;
/* Figure out how long it's been since we started transmitting. */
- interval = cur_time - ip -> client -> first_sending;
+ interval = cur_time - client -> first_sending;
/* If we're in the INIT-REBOOT or REQUESTING state and we're
past the reboot timeout, go to INIT and see if we can
@@ -1216,91 +1561,87 @@ void send_request (ipp)
us a new address, but we could also have successfully
reused our old address. In the former case, we're hosed
anyway. This is not a win-prone situation. */
- if ((ip -> client -> state == S_REBOOTING ||
- ip -> client -> state == S_REQUESTING) &&
- interval > ip -> client -> config -> reboot_timeout) {
+ if ((client -> state == S_REBOOTING ||
+ client -> state == S_REQUESTING) &&
+ interval > client -> config -> reboot_timeout) {
cancel:
- ip -> client -> state = S_INIT;
- cancel_timeout (send_request, ip);
- state_init (ip);
+ client -> state = S_INIT;
+ cancel_timeout (send_request, client);
+ state_init (client);
return;
}
/* If we're in the reboot state, make sure the media is set up
correctly. */
- if (ip -> client -> state == S_REBOOTING &&
- !ip -> client -> medium &&
- ip -> client -> active -> medium ) {
- script_init (ip, "MEDIUM", ip -> client -> active -> medium);
+ if (client -> state == S_REBOOTING &&
+ !client -> medium &&
+ client -> active -> medium ) {
+ script_init (client, "MEDIUM", client -> active -> medium);
/* If the medium we chose won't fly, go to INIT state. */
- if (script_go (ip))
+ if (script_go (client))
goto cancel;
/* Record the medium. */
- ip -> client -> medium = ip -> client -> active -> medium;
+ client -> medium = client -> active -> medium;
}
/* If the lease has expired, relinquish the address and go back
to the INIT state. */
- if (ip -> client -> state != S_REQUESTING &&
- cur_time > ip -> client -> active -> expiry) {
+ if (client -> state != S_REQUESTING &&
+ cur_time > client -> active -> expiry) {
/* Run the client script with the new parameters. */
- script_init (ip, "EXPIRE", (struct string_list *)0);
- script_write_params (ip, "old_", ip -> client -> active);
- if (ip -> client -> alias)
- script_write_params (ip, "alias_",
- ip -> client -> alias);
- script_go (ip);
+ script_init (client, "EXPIRE", (struct string_list *)0);
+ script_write_params (client, "old_", client -> active);
+ if (client -> alias)
+ script_write_params (client, "alias_",
+ client -> alias);
+ script_go (client);
/* Now do a preinit on the interface so that we can
discover a new address. */
- script_init (ip, "PREINIT", (struct string_list *)0);
- if (ip -> client -> alias)
- script_write_params (ip, "alias_",
- ip -> client -> alias);
- script_go (ip);
-
- ip -> client -> state = S_INIT;
- state_init (ip);
+ script_init (client, "PREINIT", (struct string_list *)0);
+ if (client -> alias)
+ script_write_params (client, "alias_",
+ client -> alias);
+ script_go (client);
+
+ client -> state = S_INIT;
+ state_init (client);
return;
}
/* Do the exponential backoff... */
- if (!ip -> client -> interval)
- ip -> client -> interval =
- ip -> client -> config -> initial_interval;
+ if (!client -> interval)
+ client -> interval = client -> config -> initial_interval;
else {
- ip -> client -> interval +=
- ((random () >> 2) %
- (2 * ip -> client -> interval));
+ client -> interval += ((random () >> 2) %
+ (2 * client -> interval));
}
/* Don't backoff past cutoff. */
- if (ip -> client -> interval >
- ip -> client -> config -> backoff_cutoff)
- ip -> client -> interval =
- ((ip -> client -> config -> backoff_cutoff / 2)
- + ((random () >> 2)
- % ip -> client -> interval));
+ if (client -> interval >
+ client -> config -> backoff_cutoff)
+ client -> interval =
+ ((client -> config -> backoff_cutoff / 2)
+ + ((random () >> 2) % client -> interval));
/* If the backoff would take us to the expiry time, just set the
timeout to the expiry time. */
- if (ip -> client -> state != S_REQUESTING &&
- cur_time + ip -> client -> interval >
- ip -> client -> active -> expiry)
- ip -> client -> interval =
- ip -> client -> active -> expiry - cur_time + 1;
+ if (client -> state != S_REQUESTING &&
+ cur_time + client -> interval > client -> active -> expiry)
+ client -> interval =
+ client -> active -> expiry - cur_time + 1;
/* If the lease T2 time has elapsed, or if we're not yet bound,
broadcast the DHCPREQUEST rather than unicasting. */
- if (ip -> client -> state == S_REQUESTING ||
- ip -> client -> state == S_REBOOTING ||
- cur_time > ip -> client -> active -> rebind)
- destination.sin_addr.s_addr = INADDR_BROADCAST;
+ if (client -> state == S_REQUESTING ||
+ client -> state == S_REBOOTING ||
+ cur_time > client -> active -> rebind)
+ destination.sin_addr = sockaddr_broadcast.sin_addr;
else
memcpy (&destination.sin_addr.s_addr,
- ip -> client -> destination.iabuf,
+ client -> destination.iabuf,
sizeof destination.sin_addr.s_addr);
destination.sin_port = remote_port;
destination.sin_family = AF_INET;
@@ -1308,23 +1649,25 @@ void send_request (ipp)
destination.sin_len = sizeof destination;
#endif
- if (ip -> client -> state != S_REQUESTING)
- memcpy (&from, ip -> client -> active -> address.iabuf,
+ if (client -> state == S_RENEWING ||
+ client -> state == S_REBINDING)
+ memcpy (&from, client -> active -> address.iabuf,
sizeof from);
else
from.s_addr = INADDR_ANY;
/* Record the number of seconds since we started sending. */
- if (ip -> client -> state == S_REQUESTING)
- ip -> client -> packet.secs = ip -> client -> secs;
+ if (client -> state == S_REQUESTING)
+ client -> packet.secs = client -> secs;
else {
if (interval < 65536)
- ip -> client -> packet.secs = htons (interval);
+ client -> packet.secs = htons (interval);
else
- ip -> client -> packet.secs = htons (65535);
+ client -> packet.secs = htons (65535);
}
- note ("DHCPREQUEST on %s to %s port %d", ip -> name,
+ log_info ("DHCPREQUEST on %s to %s port %d",
+ client -> name ? client -> name : client -> interface -> name,
inet_ntoa (destination.sin_addr),
ntohs (destination.sin_port));
@@ -1332,451 +1675,429 @@ void send_request (ipp)
fallback_interface)
result = send_packet (fallback_interface,
(struct packet *)0,
- &ip -> client -> packet,
- ip -> client -> packet_length,
+ &client -> packet,
+ client -> packet_length,
from, &destination,
(struct hardware *)0);
else
/* Send out a packet. */
- result = send_packet (ip, (struct packet *)0,
- &ip -> client -> packet,
- ip -> client -> packet_length,
+ result = send_packet (client -> interface, (struct packet *)0,
+ &client -> packet,
+ client -> packet_length,
from, &destination,
(struct hardware *)0);
- add_timeout (cur_time + ip -> client -> interval,
- send_request, ip);
+ add_timeout (cur_time + client -> interval,
+ send_request, client, 0, 0);
}
-void send_decline (ipp)
- void *ipp;
+void send_decline (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
+ struct client_state *client = cpp;
int result;
- note ("DHCPDECLINE on %s to %s port %d", ip -> name,
+ log_info ("DHCPDECLINE on %s to %s port %d",
+ client -> name ? client -> name : client -> interface -> name,
inet_ntoa (sockaddr_broadcast.sin_addr),
ntohs (sockaddr_broadcast.sin_port));
/* Send out a packet. */
- result = send_packet (ip, (struct packet *)0,
- &ip -> client -> packet,
- ip -> client -> packet_length,
+ result = send_packet (client -> interface, (struct packet *)0,
+ &client -> packet,
+ client -> packet_length,
inaddr_any, &sockaddr_broadcast,
(struct hardware *)0);
}
-void send_release (ipp)
- void *ipp;
+void send_release (cpp)
+ void *cpp;
{
- struct interface_info *ip = ipp;
+ struct client_state *client = cpp;
int result;
+ struct sockaddr_in destination;
+ struct in_addr from;
- note ("DHCPRELEASE on %s to %s port %d", ip -> name,
- inet_ntoa (sockaddr_broadcast.sin_addr),
- ntohs (sockaddr_broadcast.sin_port));
+ 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
- /* Send out a packet. */
- result = send_packet (ip, (struct packet *)0,
- &ip -> client -> packet,
- ip -> client -> packet_length,
- inaddr_any, &sockaddr_broadcast,
- (struct hardware *)0);
+ /* 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",
+ client -> name ? client -> name : client -> interface -> name,
+ inet_ntoa (destination.sin_addr),
+ ntohs (destination.sin_port));
+
+ if (fallback_interface)
+ result = send_packet (fallback_interface,
+ (struct packet *)0,
+ &client -> packet,
+ client -> packet_length,
+ 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_discover (ip, lease)
- struct interface_info *ip;
+void make_client_options (client, lease, type, sid, rip, prl, op)
+ struct client_state *client;
struct client_lease *lease;
+ u_int8_t *type;
+ struct option_cache *sid;
+ struct iaddr *rip;
+ u_int32_t *prl;
+ struct option_state **op;
{
- unsigned char discover = DHCPDISCOVER;
- int i;
-
- struct tree_cache *options [256];
- struct tree_cache option_elements [256];
-
- memset (option_elements, 0, sizeof option_elements);
- memset (options, 0, sizeof options);
- memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet));
-
- /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
- i = DHO_DHCP_MESSAGE_TYPE;
- options [i] = &option_elements [i];
- options [i] -> value = &discover;
- options [i] -> len = sizeof discover;
- options [i] -> buf_size = sizeof discover;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
-
- /* Request the options we want */
- i = DHO_DHCP_PARAMETER_REQUEST_LIST;
- options [i] = &option_elements [i];
- options [i] -> value = ip -> client -> config -> requested_options;
- options [i] -> len = ip -> client -> config -> requested_option_count;
- options [i] -> buf_size =
- ip -> client -> config -> requested_option_count;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
-
- /* If we had an address, try to get it again. */
- if (lease) {
- ip -> client -> requested_address = lease -> address;
- i = DHO_DHCP_REQUESTED_ADDRESS;
- options [i] = &option_elements [i];
- options [i] -> value = lease -> address.iabuf;
- options [i] -> len = lease -> address.len;
- options [i] -> buf_size = lease -> address.len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
+ unsigned i;
+ struct option_cache *oc;
+ struct buffer *bp = (struct buffer *)0;
+
+ /* If there are any leftover options, get rid of them. */
+ if (*op)
+ option_state_dereference (op, MDL);
+
+ /* Allocate space for options. */
+ option_state_allocate (op, MDL);
+
+ /* Send the server identifier if provided. */
+ if (sid)
+ save_option (&dhcp_universe, *op, sid);
+
+ oc = (struct option_cache *)0;
+
+ /* Send the requested address if provided. */
+ if (rip) {
+ client -> requested_address = *rip;
+ if (!(make_const_option_cache
+ (&oc, (struct buffer **)0, rip -> iabuf, rip -> len,
+ &dhcp_options [DHO_DHCP_REQUESTED_ADDRESS], MDL)))
+ log_error ("can't make requested address cache.");
+ else {
+ save_option (&dhcp_universe, *op, oc);
+ option_cache_dereference (&oc, MDL);
+ }
} else {
- ip -> client -> requested_address.len = 0;
- }
-
- /* Send any options requested in the config file. */
- for (i = 0; i < 256; i++) {
- if (!options [i] &&
- ip -> client -> config -> send_options [i].data) {
- options [i] = &option_elements [i];
- options [i] -> value = ip -> client -> config ->
- send_options [i].data;
- options [i] -> len = ip -> client -> config ->
- send_options [i].len;
- options [i] -> buf_size = ip -> client -> config ->
- send_options [i].len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
+ client -> requested_address.len = 0;
+ }
+
+ if (!(make_const_option_cache
+ (&oc, (struct buffer **)0,
+ type, 1, &dhcp_options [DHO_DHCP_MESSAGE_TYPE], MDL)))
+ log_error ("can't make message type.");
+ else {
+ save_option (&dhcp_universe, *op, oc);
+ option_cache_dereference (&oc, MDL);
+ }
+
+ if (prl) {
+ /* Figure out how many parameters were requested. */
+ for (i = 0; prl [i]; i++)
+ ;
+ if (!buffer_allocate (&bp, i, MDL))
+ log_error ("can't make parameter list buffer.");
+ else {
+ for (i = 0; prl [i]; i++)
+ bp -> data [i] = prl [i];
+ if (!(make_const_option_cache
+ (&oc, &bp, (u_int8_t *)0, i,
+ &dhcp_options [DHO_DHCP_PARAMETER_REQUEST_LIST],
+ MDL)))
+ log_error ("can't make option cache");
+ else {
+ save_option (&dhcp_universe, *op, oc);
+ option_cache_dereference (&oc, MDL);
+ }
}
}
+ /* Run statements that need to be run on transmission. */
+ if (client -> config -> on_transmission)
+ execute_statements_in_scope
+ ((struct binding_value **)0,
+ (struct packet *)0, (struct lease *)0, client,
+ (lease ? lease -> options : (struct option_state *)0),
+ *op, &global_scope,
+ client -> config -> on_transmission,
+ (struct group *)0);
+}
+
+void make_discover (client, lease)
+ struct client_state *client;
+ struct client_lease *lease;
+{
+ unsigned char discover = DHCPDISCOVER;
+ int i;
+ struct option_state *options = (struct option_state *)0;
+
+ memset (&client -> packet, 0, sizeof (client -> packet));
+
+ make_client_options (client,
+ lease, &discover, (struct option_cache *)0,
+ lease ? &lease -> address : (struct iaddr *)0,
+ client -> config -> requested_options,
+ &options);
+
/* Set up the option buffer... */
- ip -> client -> packet_length =
- cons_options ((struct packet *)0, &ip -> client -> packet, 0,
- options, 0, 0, 0, (u_int8_t *)0, 0);
- if (ip -> client -> packet_length < BOOTP_MIN_LEN)
- ip -> client -> packet_length = BOOTP_MIN_LEN;
-
- ip -> client -> packet.op = BOOTREQUEST;
- ip -> client -> packet.htype = ip -> hw_address.htype;
- ip -> client -> packet.hlen = ip -> hw_address.hlen;
- ip -> client -> packet.hops = 0;
- ip -> client -> packet.xid = random ();
- ip -> client -> packet.secs = 0; /* filled in by send_discover. */
-
- if (can_receive_unicast_unconfigured (ip))
- ip -> client -> packet.flags = 0;
+ client -> packet_length =
+ cons_options ((struct packet *)0, &client -> packet,
+ (struct lease *)0, client, 0,
+ (struct option_state *)0, options,
+ &global_scope, 0, 0, 0, (struct data_string *)0,
+ client -> config -> vendor_space_name);
+ if (client -> packet_length < BOOTP_MIN_LEN)
+ client -> packet_length = BOOTP_MIN_LEN;
+
+ client -> packet.op = BOOTREQUEST;
+ client -> packet.htype = client -> interface -> hw_address.hbuf [0];
+ client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
+ client -> packet.hops = 0;
+ client -> packet.xid = random ();
+ client -> packet.secs = 0; /* filled in by send_discover. */
+
+ if (can_receive_unicast_unconfigured (client -> interface))
+ client -> packet.flags = 0;
else
- ip -> client -> packet.flags = htons (BOOTP_BROADCAST);
-
- memset (&(ip -> client -> packet.ciaddr),
- 0, sizeof ip -> client -> packet.ciaddr);
- memset (&(ip -> client -> packet.yiaddr),
- 0, sizeof ip -> client -> packet.yiaddr);
- memset (&(ip -> client -> packet.siaddr),
- 0, sizeof ip -> client -> packet.siaddr);
- memset (&(ip -> client -> packet.giaddr),
- 0, sizeof ip -> client -> packet.giaddr);
- memcpy (ip -> client -> packet.chaddr,
- ip -> hw_address.haddr, ip -> hw_address.hlen);
+ client -> packet.flags = htons (BOOTP_BROADCAST);
+
+ memset (&(client -> packet.ciaddr),
+ 0, sizeof client -> packet.ciaddr);
+ memset (&(client -> packet.yiaddr),
+ 0, sizeof client -> packet.yiaddr);
+ memset (&(client -> packet.siaddr),
+ 0, sizeof client -> packet.siaddr);
+ client -> packet.giaddr = giaddr;
+ if (client -> interface -> hw_address.hlen > 0)
+ memcpy (client -> packet.chaddr,
+ &client -> interface -> hw_address.hbuf [1],
+ (unsigned)(client -> interface -> hw_address.hlen - 1));
#ifdef DEBUG_PACKET
- dump_packet (sendpkt);
- dump_raw ((unsigned char *)ip -> client -> packet,
- sendpkt->packet_length);
+ dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
#endif
}
-void make_request (ip, lease)
- struct interface_info *ip;
+void make_request (client, lease)
+ struct client_state *client;
struct client_lease *lease;
{
unsigned char request = DHCPREQUEST;
- int i;
+ int i, j;
+ unsigned char *tmp, *digest;
+ unsigned char *old_digest_loc;
+ struct option_cache *oc;
- struct tree_cache *options [256];
- struct tree_cache option_elements [256];
-
- memset (options, 0, sizeof options);
- memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet));
-
- /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
- i = DHO_DHCP_MESSAGE_TYPE;
- options [i] = &option_elements [i];
- options [i] -> value = &request;
- options [i] -> len = sizeof request;
- options [i] -> buf_size = sizeof request;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
-
- /* Request the options we want */
- i = DHO_DHCP_PARAMETER_REQUEST_LIST;
- options [i] = &option_elements [i];
- options [i] -> value = ip -> client -> config -> requested_options;
- options [i] -> len = ip -> client -> config -> requested_option_count;
- options [i] -> buf_size =
- ip -> client -> config -> requested_option_count;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
-
- /* If we are requesting an address that hasn't yet been assigned
- to us, use the DHCP Requested Address option. */
- if (ip -> client -> state == S_REQUESTING) {
- /* Send back the server identifier... */
- i = DHO_DHCP_SERVER_IDENTIFIER;
- options [i] = &option_elements [i];
- options [i] -> value = lease -> options [i].data;
- options [i] -> len = lease -> options [i].len;
- options [i] -> buf_size = lease -> options [i].len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
- }
- if (ip -> client -> state == S_REQUESTING ||
- ip -> client -> state == S_REBOOTING) {
- ip -> client -> requested_address = lease -> address;
- i = DHO_DHCP_REQUESTED_ADDRESS;
- options [i] = &option_elements [i];
- options [i] -> value = lease -> address.iabuf;
- options [i] -> len = lease -> address.len;
- options [i] -> buf_size = lease -> address.len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
- } else {
- ip -> client -> requested_address.len = 0;
- }
-
- /* Send any options requested in the config file. */
- for (i = 0; i < 256; i++) {
- if (!options [i] &&
- ip -> client -> config -> send_options [i].data) {
- options [i] = &option_elements [i];
- options [i] -> value = ip -> client -> config ->
- send_options [i].data;
- options [i] -> len = ip -> client -> config ->
- send_options [i].len;
- options [i] -> buf_size = ip -> client -> config ->
- send_options [i].len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
- }
- }
+ memset (&client -> packet, 0, sizeof (client -> packet));
+
+ if (client -> state == S_REQUESTING)
+ oc = lookup_option (&dhcp_universe, lease -> options,
+ DHO_DHCP_SERVER_IDENTIFIER);
+ else
+ oc = (struct option_cache *)0;
+
+ make_client_options (client, lease, &request, oc,
+ ((client -> state == S_REQUESTING ||
+ client -> state == S_REBOOTING)
+ ? &lease -> address
+ : (struct iaddr *)0),
+ client -> config -> requested_options,
+ &client -> sent_options);
/* Set up the option buffer... */
- ip -> client -> packet_length =
- cons_options ((struct packet *)0, &ip -> client -> packet, 0,
- options, 0, 0, 0, (u_int8_t *)0, 0);
- if (ip -> client -> packet_length < BOOTP_MIN_LEN)
- ip -> client -> packet_length = BOOTP_MIN_LEN;
-
- ip -> client -> packet.op = BOOTREQUEST;
- ip -> client -> packet.htype = ip -> hw_address.htype;
- ip -> client -> packet.hlen = ip -> hw_address.hlen;
- ip -> client -> packet.hops = 0;
- ip -> client -> packet.xid = ip -> client -> xid;
- ip -> client -> packet.secs = 0; /* Filled in by send_request. */
+ client -> packet_length =
+ cons_options ((struct packet *)0, &client -> packet,
+ (struct lease *)0, client, 0,
+ (struct option_state *)0, client -> sent_options,
+ &global_scope, 0, 0, 0, (struct data_string *)0,
+ client -> config -> vendor_space_name);
+ if (client -> packet_length < BOOTP_MIN_LEN)
+ client -> packet_length = BOOTP_MIN_LEN;
+
+ client -> packet.op = BOOTREQUEST;
+ client -> packet.htype = client -> interface -> hw_address.hbuf [0];
+ client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
+ client -> packet.hops = 0;
+ client -> packet.xid = client -> xid;
+ client -> packet.secs = 0; /* Filled in by send_request. */
/* If we own the address we're requesting, put it in ciaddr;
otherwise set ciaddr to zero. */
- if (ip -> client -> state == S_BOUND ||
- ip -> client -> state == S_RENEWING ||
- ip -> client -> state == S_REBINDING) {
- memcpy (&ip -> client -> packet.ciaddr,
+ if (client -> state == S_BOUND ||
+ client -> state == S_RENEWING ||
+ client -> state == S_REBINDING) {
+ memcpy (&client -> packet.ciaddr,
lease -> address.iabuf, lease -> address.len);
- ip -> client -> packet.flags = 0;
+ client -> packet.flags = 0;
} else {
- memset (&ip -> client -> packet.ciaddr, 0,
- sizeof ip -> client -> packet.ciaddr);
- if (can_receive_unicast_unconfigured (ip))
- ip -> client -> packet.flags = 0;
+ memset (&client -> packet.ciaddr, 0,
+ sizeof client -> packet.ciaddr);
+ if (can_receive_unicast_unconfigured (client -> interface))
+ client -> packet.flags = 0;
else
- ip -> client -> packet.flags = htons (BOOTP_BROADCAST);
+ client -> packet.flags = htons (BOOTP_BROADCAST);
}
- memset (&ip -> client -> packet.yiaddr, 0,
- sizeof ip -> client -> packet.yiaddr);
- memset (&ip -> client -> packet.siaddr, 0,
- sizeof ip -> client -> packet.siaddr);
- memset (&ip -> client -> packet.giaddr, 0,
- sizeof ip -> client -> packet.giaddr);
- memcpy (ip -> client -> packet.chaddr,
- ip -> hw_address.haddr, ip -> hw_address.hlen);
+ memset (&client -> packet.yiaddr, 0,
+ sizeof client -> packet.yiaddr);
+ memset (&client -> packet.siaddr, 0,
+ sizeof client -> packet.siaddr);
+ if (client -> state != S_BOUND &&
+ client -> state != S_RENEWING)
+ client -> packet.giaddr = giaddr;
+ else
+ memset (&client -> packet.giaddr, 0,
+ sizeof client -> packet.giaddr);
+ if (client -> interface -> hw_address.hlen > 0)
+ memcpy (client -> packet.chaddr,
+ &client -> interface -> hw_address.hbuf [1],
+ (unsigned)(client -> interface -> hw_address.hlen - 1));
#ifdef DEBUG_PACKET
- dump_packet (sendpkt);
- dump_raw ((unsigned char *)ip -> client -> packet, sendpkt->packet_length);
+ dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
#endif
}
-void make_decline (ip, lease)
- struct interface_info *ip;
+void make_decline (client, lease)
+ struct client_state *client;
struct client_lease *lease;
{
unsigned char decline = DHCPDECLINE;
int i;
+ struct option_cache *oc;
- struct tree_cache *options [256];
- struct tree_cache message_type_tree;
- struct tree_cache requested_address_tree;
- struct tree_cache server_id_tree;
- struct tree_cache client_id_tree;
-
- memset (options, 0, sizeof options);
- memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet));
-
- /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
- i = DHO_DHCP_MESSAGE_TYPE;
- options [i] = &message_type_tree;
- options [i] -> value = &decline;
- options [i] -> len = sizeof decline;
- options [i] -> buf_size = sizeof decline;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
-
- /* Send back the server identifier... */
- i = DHO_DHCP_SERVER_IDENTIFIER;
- options [i] = &server_id_tree;
- options [i] -> value = lease -> options [i].data;
- options [i] -> len = lease -> options [i].len;
- options [i] -> buf_size = lease -> options [i].len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
-
- /* Send back the address we're declining. */
- i = DHO_DHCP_REQUESTED_ADDRESS;
- options [i] = &requested_address_tree;
- options [i] -> value = lease -> address.iabuf;
- options [i] -> len = lease -> address.len;
- options [i] -> buf_size = lease -> address.len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
-
- /* Send the uid if the user supplied one. */
- i = DHO_DHCP_CLIENT_IDENTIFIER;
- if (ip -> client -> config -> send_options [i].len) {
- options [i] = &client_id_tree;
- options [i] -> value = ip -> client -> config ->
- send_options [i].data;
- options [i] -> len = ip -> client -> config ->
- send_options [i].len;
- options [i] -> buf_size = ip -> client -> config ->
- send_options [i].len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
- }
+ struct option_state *options = (struct option_state *)0;
+ oc = lookup_option (&dhcp_universe, lease -> options,
+ DHO_DHCP_SERVER_IDENTIFIER);
+ make_client_options (client, lease, &decline, oc,
+ &lease -> address, (u_int32_t *)0, &options);
/* Set up the option buffer... */
- ip -> client -> packet_length =
- cons_options ((struct packet *)0, &ip -> client -> packet, 0,
- options, 0, 0, 0, (u_int8_t *)0, 0);
- if (ip -> client -> packet_length < BOOTP_MIN_LEN)
- ip -> client -> packet_length = BOOTP_MIN_LEN;
-
- ip -> client -> packet.op = BOOTREQUEST;
- ip -> client -> packet.htype = ip -> hw_address.htype;
- ip -> client -> packet.hlen = ip -> hw_address.hlen;
- ip -> client -> packet.hops = 0;
- ip -> client -> packet.xid = ip -> client -> xid;
- ip -> client -> packet.secs = 0; /* Filled in by send_request. */
- ip -> client -> packet.flags = 0;
+ memset (&client -> packet, 0, sizeof (client -> packet));
+ client -> packet_length =
+ cons_options ((struct packet *)0, &client -> packet,
+ (struct lease *)0, client, 0,
+ (struct option_state *)0, options,
+ &global_scope, 0, 0, 0, (struct data_string *)0,
+ client -> config -> vendor_space_name);
+ if (client -> packet_length < BOOTP_MIN_LEN)
+ client -> packet_length = BOOTP_MIN_LEN;
+ option_state_dereference (&options, MDL);
+
+ client -> packet.op = BOOTREQUEST;
+ client -> packet.htype = client -> interface -> hw_address.hbuf [0];
+ client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
+ client -> packet.hops = 0;
+ client -> packet.xid = client -> xid;
+ client -> packet.secs = 0; /* Filled in by send_request. */
+ if (can_receive_unicast_unconfigured (client -> interface))
+ client -> packet.flags = 0;
+ else
+ client -> packet.flags = htons (BOOTP_BROADCAST);
/* ciaddr must always be zero. */
- memset (&ip -> client -> packet.ciaddr, 0,
- sizeof ip -> client -> packet.ciaddr);
- memset (&ip -> client -> packet.yiaddr, 0,
- sizeof ip -> client -> packet.yiaddr);
- memset (&ip -> client -> packet.siaddr, 0,
- sizeof ip -> client -> packet.siaddr);
- memset (&ip -> client -> packet.giaddr, 0,
- sizeof ip -> client -> packet.giaddr);
- memcpy (ip -> client -> packet.chaddr,
- ip -> hw_address.haddr, ip -> hw_address.hlen);
+ memset (&client -> packet.ciaddr, 0,
+ sizeof client -> packet.ciaddr);
+ memset (&client -> packet.yiaddr, 0,
+ sizeof client -> packet.yiaddr);
+ memset (&client -> packet.siaddr, 0,
+ sizeof client -> packet.siaddr);
+ client -> packet.giaddr = giaddr;
+ memcpy (client -> packet.chaddr,
+ &client -> interface -> hw_address.hbuf [1],
+ client -> interface -> hw_address.hlen);
#ifdef DEBUG_PACKET
- dump_packet (sendpkt);
- dump_raw ((unsigned char *)ip -> client -> packet, sendpkt->packet_length);
+ dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
#endif
}
-void make_release (ip, lease)
- struct interface_info *ip;
+void make_release (client, lease)
+ struct client_state *client;
struct client_lease *lease;
{
unsigned char request = DHCPRELEASE;
int i;
+ struct option_cache *oc;
+
+ struct option_state *options = (struct option_state *)0;
- struct tree_cache *options [256];
- struct tree_cache message_type_tree;
- struct tree_cache server_id_tree;
-
- memset (options, 0, sizeof options);
- memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet));
-
- /* Set DHCP_MESSAGE_TYPE to DHCPRELEASE */
- i = DHO_DHCP_MESSAGE_TYPE;
- options [i] = &message_type_tree;
- options [i] -> value = &request;
- options [i] -> len = sizeof request;
- options [i] -> buf_size = sizeof request;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
-
- /* Send back the server identifier... */
- i = DHO_DHCP_SERVER_IDENTIFIER;
- options [i] = &server_id_tree;
- options [i] -> value = lease -> options [i].data;
- options [i] -> len = lease -> options [i].len;
- options [i] -> buf_size = lease -> options [i].len;
- options [i] -> timeout = 0xFFFFFFFF;
- options [i] -> tree = (struct tree *)0;
+ memset (&client -> packet, 0, sizeof (client -> packet));
+
+ oc = lookup_option (&dhcp_universe, lease -> options,
+ DHO_DHCP_SERVER_IDENTIFIER);
+ make_client_options (client, lease, &request, oc,
+ (struct iaddr *)0, (u_int32_t *)0,
+ &options);
/* Set up the option buffer... */
- ip -> client -> packet_length =
- cons_options ((struct packet *)0, &ip -> client -> packet, 0,
- options, 0, 0, 0, (u_int8_t *)0, 0);
- if (ip -> client -> packet_length < BOOTP_MIN_LEN)
- ip -> client -> packet_length = BOOTP_MIN_LEN;
-
- ip -> client -> packet.op = BOOTREQUEST;
- ip -> client -> packet.htype = ip -> hw_address.htype;
- ip -> client -> packet.hlen = ip -> hw_address.hlen;
- ip -> client -> packet.hops = 0;
- ip -> client -> packet.xid = random ();
- ip -> client -> packet.secs = 0;
- ip -> client -> packet.flags = 0;
-
- memset (&ip -> client -> packet.ciaddr, 0,
- sizeof ip -> client -> packet.ciaddr);
- memset (&ip -> client -> packet.yiaddr, 0,
- sizeof ip -> client -> packet.yiaddr);
- memset (&ip -> client -> packet.siaddr, 0,
- sizeof ip -> client -> packet.siaddr);
- memset (&ip -> client -> packet.giaddr, 0,
- sizeof ip -> client -> packet.giaddr);
- memcpy (ip -> client -> packet.chaddr,
- ip -> hw_address.haddr, ip -> hw_address.hlen);
+ client -> packet_length =
+ cons_options ((struct packet *)0, &client -> packet,
+ (struct lease *)0, client, 0,
+ (struct option_state *)0, options,
+ &global_scope, 0, 0, 0, (struct data_string *)0,
+ client -> config -> vendor_space_name);
+ if (client -> packet_length < BOOTP_MIN_LEN)
+ client -> packet_length = BOOTP_MIN_LEN;
+ option_state_dereference (&options, MDL);
+
+ client -> packet.op = BOOTREQUEST;
+ client -> packet.htype = client -> interface -> hw_address.hbuf [0];
+ client -> packet.hlen = client -> interface -> hw_address.hlen - 1;
+ client -> packet.hops = 0;
+ client -> packet.xid = random ();
+ client -> packet.secs = 0;
+ client -> packet.flags = 0;
+ memcpy (&client -> packet.ciaddr,
+ lease -> address.iabuf, lease -> address.len);
+ memset (&client -> packet.yiaddr, 0,
+ sizeof client -> packet.yiaddr);
+ memset (&client -> packet.siaddr, 0,
+ sizeof client -> packet.siaddr);
+ client -> packet.giaddr = giaddr;
+ memcpy (client -> packet.chaddr,
+ &client -> interface -> hw_address.hbuf [1],
+ client -> interface -> hw_address.hlen);
#ifdef DEBUG_PACKET
- dump_packet (sendpkt);
- dump_raw ((unsigned char *)ip -> client -> packet,
- ip -> client -> packet_length);
+ dump_raw ((unsigned char *)&client -> packet, client -> packet_length);
#endif
}
-void free_client_lease (lease)
+void destroy_client_lease (lease)
struct client_lease *lease;
{
int i;
if (lease -> server_name)
- free (lease -> server_name);
+ dfree (lease -> server_name, MDL);
if (lease -> filename)
- free (lease -> filename);
- for (i = 0; i < 256; i++) {
- if (lease -> options [i].len)
- free (lease -> options [i].data);
- }
- free (lease);
+ dfree (lease -> filename, MDL);
+ option_state_dereference (&lease -> options, MDL);
+ free_client_lease (lease, MDL);
}
FILE *leaseFile;
@@ -1784,44 +2105,92 @@ FILE *leaseFile;
void rewrite_client_leases ()
{
struct interface_info *ip;
+ struct client_state *client;
struct client_lease *lp;
if (leaseFile)
fclose (leaseFile);
leaseFile = fopen (path_dhclient_db, "w");
- if (!leaseFile)
- error ("can't create %s: %m", path_dhclient_db);
+ if (!leaseFile) {
+ log_error ("can't create %s: %m", path_dhclient_db);
+ return;
+ }
/* Write out all the leases attached to configured interfaces that
we know about. */
for (ip = interfaces; ip; ip = ip -> next) {
- for (lp = ip -> client -> leases; lp; lp = lp -> next) {
- write_client_lease (ip, lp, 1);
+ for (client = ip -> client; client; client = client -> next) {
+ for (lp = client -> leases; lp; lp = lp -> next) {
+ write_client_lease (client, lp, 1, 0);
+ }
+ if (client -> active)
+ write_client_lease (client,
+ client -> active, 1, 0);
}
- if (ip -> client -> active)
- write_client_lease (ip, ip -> client -> active, 1);
}
/* Write out any leases that are attached to interfaces that aren't
currently configured. */
for (ip = dummy_interfaces; ip; ip = ip -> next) {
- for (lp = ip -> client -> leases; lp; lp = lp -> next) {
- write_client_lease (ip, lp, 1);
+ for (client = ip -> client; client; client = client -> next) {
+ for (lp = client -> leases; lp; lp = lp -> next) {
+ write_client_lease (client, lp, 1, 0);
+ }
+ if (client -> active)
+ write_client_lease (client,
+ client -> active, 1, 0);
}
- if (ip -> client -> active)
- write_client_lease (ip, ip -> client -> active, 1);
}
fflush (leaseFile);
}
-void write_client_lease (ip, lease, rewrite)
- struct interface_info *ip;
+void write_lease_option (struct option_cache *oc,
+ struct packet *packet, struct lease *lease,
+ struct client_state *client_state,
+ struct option_state *in_options,
+ struct option_state *cfg_options,
+ struct binding_scope **scope,
+ struct universe *u, void *stuff)
+{
+ const char *name, *dot;
+ struct data_string ds;
+ int status;
+ struct client_state *client;
+
+ memset (&ds, 0, sizeof ds);
+
+ if (u != &dhcp_universe) {
+ name = u -> name;
+ dot = ".";
+ } else {
+ name = "";
+ dot = "";
+ }
+ if (evaluate_option_cache (&ds, packet, lease, client_state,
+ in_options, cfg_options, scope, oc, MDL)) {
+ fprintf (leaseFile,
+ " option %s%s%s %s;\n",
+ name, dot, oc -> option -> name,
+ pretty_print_option (oc -> option,
+ ds.data, ds.len, 1, 1));
+ data_string_forget (&ds, MDL);
+ }
+}
+
+int write_client_lease (client, lease, rewrite, makesure)
+ struct client_state *client;
struct client_lease *lease;
int rewrite;
+ int makesure;
{
int i;
struct tm *t;
static int leases_written;
+ struct option_cache *oc;
+ struct data_string ds;
+ pair *hash;
+ int errors = 0;
+ char *s;
if (!rewrite) {
if (leases_written++ > 20) {
@@ -1833,38 +2202,94 @@ void write_client_lease (ip, lease, rewrite)
/* If the lease came from the config file, we don't need to stash
a copy in the lease database. */
if (lease -> is_static)
- return;
+ return 1;
if (!leaseFile) { /* XXX */
leaseFile = fopen (path_dhclient_db, "w");
- if (!leaseFile)
- error ("can't create %s: %m", path_dhclient_db);
+ if (!leaseFile) {
+ log_error ("can't create %s: %m", path_dhclient_db);
+ return 0;
+ }
}
+ errno = 0;
fprintf (leaseFile, "lease {\n");
- if (lease -> is_bootp)
+ if (lease -> is_bootp) {
fprintf (leaseFile, " bootp;\n");
- fprintf (leaseFile, " interface \"%s\";\n", ip -> name);
+ if (errno) {
+ ++errors;
+ errno = 0;
+ }
+ }
+ fprintf (leaseFile, " interface \"%s\";\n",
+ client -> interface -> name);
+ if (errno) {
+ ++errors;
+ errno = 0;
+ }
+ if (client -> name) {
+ fprintf (leaseFile, " name \"%s\";\n", client -> name);
+ if (errno) {
+ ++errors;
+ errno = 0;
+ }
+ }
fprintf (leaseFile, " fixed-address %s;\n",
piaddr (lease -> address));
- if (lease -> filename)
- fprintf (leaseFile, " filename \"%s\";\n",
- lease -> filename);
- if (lease -> server_name)
- fprintf (leaseFile, " server-name \"%s\";\n",
- lease -> server_name);
- if (lease -> medium)
- fprintf (leaseFile, " medium \"%s\";\n",
- lease -> medium -> string);
- for (i = 0; i < 256; i++) {
- if (lease -> options [i].len) {
- fprintf (leaseFile,
- " option %s %s;\n",
- dhcp_options [i].name,
- pretty_print_option
- (i, lease -> options [i].data,
- lease -> options [i].len, 1, 1));
- }
+ if (errno) {
+ ++errors;
+ errno = 0;
+ }
+ if (lease -> filename) {
+ s = quotify_string (lease -> filename, MDL);
+ if (s) {
+ fprintf (leaseFile, " filename \"%s\";\n", s);
+ if (errno) {
+ ++errors;
+ errno = 0;
+ }
+ dfree (s, MDL);
+ } else
+ errors++;
+
+ }
+ if (lease -> server_name) {
+ s = quotify_string (lease -> filename, MDL);
+ if (s) {
+ fprintf (leaseFile, " server-name \"%s\";\n", s);
+ if (errno) {
+ ++errors;
+ errno = 0;
+ }
+ dfree (s, MDL);
+ } else
+ ++errors;
+ }
+ if (lease -> medium) {
+ s = quotify_string (lease -> medium -> string, MDL);
+ if (s) {
+ fprintf (leaseFile, " medium \"%s\";\n", s);
+ if (errno) {
+ ++errors;
+ errno = 0;
+ }
+ dfree (s, MDL);
+ } else
+ errors++;
+ }
+ if (errno != 0) {
+ errors++;
+ errno = 0;
+ }
+
+ memset (&ds, 0, sizeof ds);
+
+ for (i = 0; i < lease -> options -> universe_count; i++) {
+ option_space_foreach ((struct packet *)0, (struct lease *)0,
+ client, (struct option_state *)0,
+ lease -> options, &global_scope,
+ universes [i],
+ client, write_lease_option);
}
/* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until
@@ -1876,20 +2301,47 @@ void write_client_lease (ip, lease, rewrite)
t -> tm_wday, t -> tm_year + 1900,
t -> tm_mon + 1, t -> tm_mday,
t -> tm_hour, t -> tm_min, t -> tm_sec);
+ if (errno != 0) {
+ errors++;
+ errno = 0;
+ }
t = gmtime (&lease -> rebind);
fprintf (leaseFile,
" rebind %d %d/%d/%d %02d:%02d:%02d;\n",
t -> tm_wday, t -> tm_year + 1900,
t -> tm_mon + 1, t -> tm_mday,
t -> tm_hour, t -> tm_min, t -> tm_sec);
+ if (errno != 0) {
+ errors++;
+ errno = 0;
+ }
t = gmtime (&lease -> expiry);
fprintf (leaseFile,
" expire %d %d/%d/%d %02d:%02d:%02d;\n",
t -> tm_wday, t -> tm_year + 1900,
t -> tm_mon + 1, t -> tm_mday,
t -> tm_hour, t -> tm_min, t -> tm_sec);
+ if (errno != 0) {
+ errors++;
+ errno = 0;
+ }
fprintf (leaseFile, "}\n");
+ if (errno != 0) {
+ errors++;
+ errno = 0;
+ }
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
@@ -1898,41 +2350,88 @@ void write_client_lease (ip, lease, rewrite)
char scriptName [256];
FILE *scriptFile;
-void script_init (ip, reason, medium)
- struct interface_info *ip;
- char *reason;
+void script_init (client, reason, medium)
+ struct client_state *client;
+ const char *reason;
struct string_list *medium;
{
struct string_list *sl, *next;
- if (ip) {
- for (sl = ip -> client -> env; sl; sl = next) {
+ if (client) {
+ for (sl = client -> env; sl; sl = next) {
next = sl -> next;
- dfree (sl, "script_init");
+ dfree (sl, MDL);
}
- ip -> client -> env = (struct string_list *)0;
- ip -> client -> envc = 0;
+ client -> env = (struct string_list *)0;
+ client -> envc = 0;
- client_envadd (ip -> client, "", "interface", "%s",
- ip -> name);
+ if (client -> interface) {
+ client_envadd (client, "", "interface", "%s",
+ client -> interface -> name);
+ }
+ if (client -> name)
+ client_envadd (client,
+ "", "client", "%s", client -> name);
if (medium)
- client_envadd (ip -> client,
+ client_envadd (client,
"", "medium", "%s", medium -> string);
- client_envadd (ip -> client, "", "reason", "%s", reason);
+ client_envadd (client, "", "reason", "%s", reason);
+ client_envadd (client, "", "pid", "%ld", (long int)getpid ());
}
}
-void script_write_params (ip, prefix, lease)
- struct interface_info *ip;
- char *prefix;
+struct envadd_state {
+ struct client_state *client;
+ const char *prefix;
+};
+
+void client_option_envadd (struct option_cache *oc,
+ struct packet *packet, struct lease *lease,
+ struct client_state *client_state,
+ struct option_state *in_options,
+ struct option_state *cfg_options,
+ struct binding_scope **scope,
+ struct universe *u, void *stuff)
+{
+ struct envadd_state *es = stuff;
+ struct data_string data;
+ memset (&data, 0, sizeof data);
+
+ if (evaluate_option_cache (&data, packet, lease, client_state,
+ in_options, cfg_options, scope, oc, MDL)) {
+ if (data.len) {
+ char name [256];
+ if (dhcp_option_ev_name (name, sizeof name,
+ oc -> option)) {
+ client_envadd (es -> client, es -> prefix,
+ name, "%s",
+ (pretty_print_option
+ (oc -> option,
+ data.data, data.len,
+ 0, 0)));
+ data_string_forget (&data, MDL);
+ }
+ }
+ }
+}
+
+void script_write_params (client, prefix, lease)
+ struct client_state *client;
+ const char *prefix;
struct client_lease *lease;
{
int i;
- u_int8_t dbuf [1500];
- int len;
+ struct data_string data;
+ struct option_cache *oc;
+ pair *hash;
+ char *s, *t;
+ struct envadd_state es;
- client_envadd (ip -> client,
+ es.client = client;
+ es.prefix = prefix;
+
+ client_envadd (client,
prefix, "ip_address", "%s", piaddr (lease -> address));
/* For the benefit of Linux (and operating systems which may
@@ -1942,125 +2441,66 @@ void script_write_params (ip, prefix, lease)
broadcast address, not the host address all zeroes
broadcast address). */
- if (lease -> options [DHO_SUBNET_MASK].len &&
- (lease -> options [DHO_SUBNET_MASK].len <
- sizeof lease -> address.iabuf)) {
- struct iaddr netmask, subnet, broadcast;
-
- memcpy (netmask.iabuf,
- lease -> options [DHO_SUBNET_MASK].data,
- lease -> options [DHO_SUBNET_MASK].len);
- netmask.len = lease -> options [DHO_SUBNET_MASK].len;
-
- subnet = subnet_number (lease -> address, netmask);
- if (subnet.len) {
- client_envadd (ip -> client, prefix, "network_number",
- "%s", piaddr (subnet));
-
- if (!lease -> options [DHO_BROADCAST_ADDRESS].len) {
+ memset (&data, 0, sizeof data);
+ oc = lookup_option (&dhcp_universe, lease -> options, DHO_SUBNET_MASK);
+ if (oc && evaluate_option_cache (&data, (struct packet *)0,
+ (struct lease *)0, client,
+ (struct option_state *)0,
+ lease -> options,
+ &global_scope, oc, MDL)) {
+ if (data.len > 3) {
+ struct iaddr netmask, subnet, broadcast;
+
+ memcpy (netmask.iabuf, data.data, data.len);
+ netmask.len = data.len;
+ data_string_forget (&data, MDL);
+
+ subnet = subnet_number (lease -> address, netmask);
+ if (subnet.len) {
+ client_envadd (client, prefix, "network_number",
+ "%s", piaddr (subnet));
+
+ oc = lookup_option (&dhcp_universe,
+ lease -> options,
+ DHO_BROADCAST_ADDRESS);
+ if (!oc ||
+ !(evaluate_option_cache
+ (&data, (struct packet *)0,
+ (struct lease *)0, client,
+ (struct option_state *)0,
+ lease -> options,
+ &global_scope, oc, MDL))) {
broadcast = broadcast_addr (subnet, netmask);
if (broadcast.len) {
- client_envadd (ip -> client,
+ client_envadd (client,
prefix, "broadcast_address",
"%s", piaddr (broadcast));
}
+ }
}
}
+ data_string_forget (&data, MDL);
}
if (lease -> filename)
- client_envadd (ip -> client,
+ client_envadd (client,
prefix, "filename", "%s", lease -> filename);
if (lease -> server_name)
- client_envadd (ip -> client, prefix, "server_name",
+ client_envadd (client, prefix, "server_name",
"%s", lease -> server_name);
- for (i = 0; i < 256; i++) {
- u_int8_t *dp;
-
- if (ip -> client -> config -> defaults [i].len) {
- if (lease -> options [i].len) {
- switch (ip -> client ->
- config -> default_actions [i]) {
- case ACTION_DEFAULT:
- dp = lease -> options [i].data;
- len = lease -> options [i].len;
- break;
- case ACTION_SUPERSEDE:
- supersede:
- dp = ip -> client ->
- config -> defaults [i].data;
- len = ip -> client ->
- config -> defaults [i].len;
- break;
- case ACTION_PREPEND:
- len = (ip -> client ->
- config -> defaults [i].len +
- lease -> options [i].len);
- if (len > sizeof dbuf) {
- warn ("no space to %s %s",
- "prepend option",
- dhcp_options [i].name);
- goto supersede;
- }
- dp = dbuf;
- memcpy (dp,
- ip -> client ->
- config -> defaults [i].data,
- ip -> client ->
- config -> defaults [i].len);
- memcpy (dp + ip -> client ->
- config -> defaults [i].len,
- lease -> options [i].data,
- lease -> options [i].len);
- break;
- case ACTION_APPEND:
- len = (ip -> client ->
- config -> defaults [i].len +
- lease -> options [i].len);
- if (len > sizeof dbuf) {
- warn ("no space to %s %s",
- "append option",
- dhcp_options [i].name);
- goto supersede;
- }
- dp = dbuf;
- memcpy (dp,
- lease -> options [i].data,
- lease -> options [i].len);
- memcpy (dp + lease -> options [i].len,
- ip -> client ->
- config -> defaults [i].data,
- ip -> client ->
- config -> defaults [i].len);
- }
- } else {
- dp = ip -> client ->
- config -> defaults [i].data;
- len = ip -> client ->
- config -> defaults [i].len;
- }
- } else if (lease -> options [i].len) {
- len = lease -> options [i].len;
- dp = lease -> options [i].data;
- } else {
- len = 0;
- }
- if (len) {
- char name [256];
- if (dhcp_option_ev_name (name, sizeof name,
- &dhcp_options [i])) {
- client_envadd (ip -> client, prefix, name, "%s",
- (pretty_print_option (i, dp,
- len, 0, 0)));
- }
- }
+
+ for (i = 0; i < lease -> options -> universe_count; i++) {
+ option_space_foreach ((struct packet *)0, (struct lease *)0,
+ client, (struct option_state *)0,
+ lease -> options, &global_scope,
+ universes [i],
+ &es, client_option_envadd);
}
- client_envadd (ip -> client,
- prefix, "expiry", "%d", (int)(lease -> expiry));
+ client_envadd (client, prefix, "expiry", "%d", (int)(lease -> expiry));
}
-int script_go (ip)
- struct interface_info *ip;
+int script_go (client)
+ struct client_state *client;
{
int rval;
char *scriptName;
@@ -2073,59 +2513,68 @@ int script_go (ip)
struct string_list *sp, *next;
int pid, wpid, wstatus;
- if (ip) {
- scriptName = ip -> client -> config -> script_name;
- envp = dmalloc ((ip -> client -> envc + 2) * sizeof (char *),
- "script_go");
- if (!envp) {
- error ("No memory for client script environment.");
- return 0;
- }
- i = 0;
- for (sp = ip -> client -> env; sp; sp = sp -> next) {
+ if (client)
+ scriptName = client -> config -> script_name;
+ else
+ scriptName = top_level_config.script_name;
+
+ envp = dmalloc (((client ? client -> envc : 2) +
+ client_env_count + 2) * sizeof (char *), MDL);
+ if (!envp) {
+ log_error ("No memory for client script environment.");
+ return 0;
+ }
+ i = 0;
+ /* Copy out the environment specified on the command line,
+ if any. */
+ for (sp = client_env; sp; sp = sp -> next) {
+ envp [i++] = sp -> string;
+ }
+ /* Copy out the environment specified by dhclient. */
+ if (client) {
+ for (sp = client -> env; sp; sp = sp -> next) {
envp [i++] = sp -> string;
}
- envp [i++] = client_path;
- envp [i] = (char *)0;
} else {
- scriptName = top_level_config.script_name;
- epp [0] = reason;
- epp [1] = client_path;
- epp [2] = (char *)0;
- envp = epp;
+ envp [i++] = reason;
}
+ /* Set $PATH. */
+ envp [i++] = client_path;
+ envp [i] = (char *)0;
argv [0] = scriptName;
argv [1] = (char *)0;
pid = fork ();
if (pid < 0) {
- error ("fork: %m");
+ log_error ("fork: %m");
wstatus = 0;
} else if (pid) {
do {
wpid = wait (&wstatus);
} while (wpid != pid && wpid > 0);
if (wpid < 0) {
- error ("wait: %m");
+ log_error ("wait: %m");
wstatus = 0;
}
} else {
execve (scriptName, argv, envp);
- error ("execve (%s, ...): %m", scriptName);
+ log_error ("execve (%s, ...): %m", scriptName);
exit (0);
}
- if (ip) {
- for (sp = ip -> client -> env; sp; sp = next) {
+ if (client) {
+ for (sp = client -> env; sp; sp = next) {
next = sp -> next;
- dfree (sp, "script_go");
+ dfree (sp, MDL);
}
- ip -> client -> env = (struct string_list *)0;
- ip -> client -> envc = 0;
- dfree (envp, "script_go");
+ client -> env = (struct string_list *)0;
+ client -> envc = 0;
}
- return wstatus & 0xff;
+ dfree (envp, MDL);
+ GET_TIME (&cur_time);
+ return (WIFEXITED (wstatus) ?
+ WEXITSTATUS (wstatus) : -WTERMSIG (wstatus));
}
void client_envadd (struct client_state *client,
@@ -2142,7 +2591,7 @@ void client_envadd (struct client_state *client,
va_end (list);
val = dmalloc (strlen (prefix) + strlen (name) + 1 /* = */ +
- len + sizeof *val, "client_envadd");
+ len + sizeof *val, MDL);
if (!val)
return;
s = val -> string;
@@ -2166,25 +2615,46 @@ int dhcp_option_ev_name (buf, buflen, option)
size_t buflen;
struct option *option;
{
- int i;
+ int i, j;
+ const char *s;
- for (i = 0; option -> name [i]; i++) {
- if (i + 1 == buflen)
- return 0;
- if (option -> name [i] == '-')
- buf [i] = '_';
- else
- buf [i] = option -> name [i];
+ j = 0;
+ if (option -> universe != &dhcp_universe) {
+ s = option -> universe -> name;
+ i = 0;
+ } else {
+ s = option -> name;
+ i = 1;
}
- buf [i] = 0;
+ do {
+ while (*s) {
+ if (j + 1 == buflen)
+ return 0;
+ if (*s == '-')
+ buf [j++] = '_';
+ else
+ buf [j++] = *s;
+ ++s;
+ }
+ if (!i) {
+ s = option -> name;
+ if (j + 1 == buflen)
+ return 0;
+ buf [j++] = '_';
+ }
+ ++i;
+ } while (i != 2);
+
+ buf [j] = 0;
return 1;
}
-
+
void go_daemon ()
{
static int state = 0;
int pid;
+ int i;
/* Don't become a daemon if the user requested otherwise. */
if (no_daemon) {
@@ -2202,7 +2672,7 @@ void go_daemon ()
/* Become a daemon... */
if ((pid = fork ()) < 0)
- error ("Can't fork daemon: %m");
+ log_fatal ("Can't fork daemon: %m");
else if (pid)
exit (0);
/* Become session leader and get pid... */
@@ -2213,6 +2683,16 @@ void go_daemon ()
close(1);
close(2);
+ /* Reopen them on /dev/null. */
+ i = open ("/dev/null", O_RDWR);
+ if (i == 0)
+ i = open ("/dev/null", O_RDWR);
+ if (i == 1) {
+ i = open ("/dev/null", O_RDWR);
+ log_perror = 0; /* No sense logging to /dev/null. */
+ } else if (i != -1)
+ close (i);
+
write_client_pid_file ();
}
@@ -2224,15 +2704,384 @@ void write_client_pid_file ()
pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY, 0644);
if (pfdesc < 0) {
- warn ("Can't create %s: %m", path_dhclient_pid);
+ log_error ("Can't create %s: %m", path_dhclient_pid);
return;
}
pf = fdopen (pfdesc, "w");
if (!pf)
- warn ("Can't fdopen %s: %m", path_dhclient_pid);
+ log_error ("Can't fdopen %s: %m", path_dhclient_pid);
else {
fprintf (pf, "%ld\n", (long)getpid ());
fclose (pf);
}
}
+
+void client_location_changed ()
+{
+ struct interface_info *ip;
+ struct client_state *client;
+
+ for (ip = interfaces; ip; ip = ip -> next) {
+ for (client = ip -> client; client; client = client -> next) {
+ switch (client -> state) {
+ case S_SELECTING:
+ cancel_timeout (send_discover, client);
+ break;
+
+ case S_BOUND:
+ cancel_timeout (state_bound, client);
+ break;
+
+ case S_REBOOTING:
+ case S_REQUESTING:
+ case S_RENEWING:
+ cancel_timeout (send_request, client);
+ break;
+
+ case S_INIT:
+ case S_REBINDING:
+ case S_STOPPED:
+ break;
+ }
+ client -> state = S_INIT;
+ state_reboot (client);
+ }
+ }
+}
+
+void do_release(client)
+ struct client_state *client;
+{
+ struct data_string ds;
+ struct option_cache *oc;
+
+ /* Pick a random xid. */
+ client -> xid = random ();
+
+ /* is there even a lease to release? */
+ if (client -> active) {
+ /* Make a DHCPRELEASE packet, and set appropriate per-interface
+ flags. */
+ make_release (client, client -> active);
+
+ 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, client,
+ (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 -> interval = client -> config -> initial_interval;
+
+ /* Zap the medium list... */
+ client -> medium = (struct string_list *)0;
+
+ /* Send out the first and only DHCPRELEASE packet. */
+ send_release (client);
+
+ /* Do the client script RELEASE operation. */
+ script_init (client,
+ "RELEASE", (struct string_list *)0);
+ if (client -> alias)
+ script_write_params (client, "alias_",
+ client -> alias);
+ script_write_params (client, "old_", client -> active);
+ script_go (client);
+ }
+
+ /* Cancel any timeouts. */
+ cancel_timeout (state_bound, client);
+ cancel_timeout (send_discover, client);
+ cancel_timeout (state_init, client);
+ cancel_timeout (send_request, client);
+ cancel_timeout (state_reboot, client);
+ client -> state = S_STOPPED;
+}
+
+int dhclient_interface_shutdown_hook (struct interface_info *interface)
+{
+ do_release (interface -> client);
+
+ return 1;
+}
+
+int dhclient_interface_discovery_hook (struct interface_info *tmp)
+{
+ struct interface_info *last, *ip;
+ /* See if we can find the client from dummy_interfaces */
+ last = 0;
+ for (ip = dummy_interfaces; ip; ip = ip -> next) {
+ if (!strcmp (ip -> name, tmp -> name)) {
+ /* Remove from dummy_interfaces */
+ if (last) {
+ ip = (struct interface_info *)0;
+ interface_reference (&ip, last -> next, MDL);
+ interface_dereference (&last -> next, MDL);
+ if (ip -> next) {
+ interface_reference (&last -> next,
+ ip -> next, MDL);
+ interface_dereference (&ip -> next,
+ MDL);
+ }
+ } else {
+ ip = (struct interface_info *)0;
+ interface_reference (&ip,
+ dummy_interfaces, MDL);
+ interface_dereference (&dummy_interfaces, MDL);
+ if (ip -> next) {
+ interface_reference (&dummy_interfaces,
+ ip -> next, MDL);
+ interface_dereference (&ip -> next,
+ MDL);
+ }
+ }
+ /* Copy "client" to tmp */
+ if (ip -> client) {
+ tmp -> client = ip -> client;
+ tmp -> client -> interface = tmp;
+ }
+ interface_dereference (&ip, MDL);
+ break;
+ }
+ last = ip;
+ }
+ return 1;
+}
+
+isc_result_t dhclient_interface_startup_hook (struct interface_info *interface)
+{
+ struct interface_info *ip;
+ struct client_state *client;
+
+ /* This code needs some rethinking. It doesn't test against
+ a signal name, and it just kind of bulls into doing something
+ that may or may not be appropriate. */
+
+ if (interfaces) {
+ interface_reference (&interface -> next, interfaces, MDL);
+ interface_dereference (&interfaces, MDL);
+ }
+ interface_reference (&interfaces, interface, MDL);
+
+ discover_interfaces (DISCOVER_UNCONFIGURED);
+
+ for (ip = interfaces; ip; ip = ip -> next) {
+ /* If interfaces were specified, don't configure
+ interfaces that weren't specified! */
+ if (ip -> flags & INTERFACE_RUNNING ||
+ (ip -> flags & (INTERFACE_REQUESTED |
+ INTERFACE_AUTOMATIC)) !=
+ INTERFACE_REQUESTED)
+ continue;
+ script_init (ip -> client,
+ "PREINIT", (struct string_list *)0);
+ if (ip -> client -> alias)
+ script_write_params (ip -> client, "alias_",
+ ip -> client -> alias);
+ script_go (ip -> client);
+ }
+
+ discover_interfaces (interfaces_requested
+ ? DISCOVER_REQUESTED
+ : DISCOVER_RUNNING);
+
+ for (ip = interfaces; ip; ip = ip -> next) {
+ if (ip -> flags & INTERFACE_RUNNING)
+ continue;
+ ip -> flags |= INTERFACE_RUNNING;
+ for (client = ip -> client; client; client = client -> next) {
+ client -> state = S_INIT;
+ /* Set up a timeout to start the initialization
+ process. */
+ add_timeout (cur_time + random () % 5,
+ state_reboot, client, 0, 0);
+ }
+ }
+ return ISC_R_SUCCESS;
+}
+
+/* The client should never receive a relay agent information option,
+ so if it does, log it and discard it. */
+
+int parse_agent_information_option (packet, len, data)
+ struct packet *packet;
+ int len;
+ u_int8_t *data;
+{
+ return 1;
+}
+
+/* The client never sends relay agent information options. */
+
+unsigned cons_agent_information_options (cfg_options, outpacket,
+ agentix, length)
+ struct option_state *cfg_options;
+ struct dhcp_packet *outpacket;
+ unsigned agentix;
+ unsigned length;
+{
+ return length;
+}
+
+static void shutdown_exit (void *foo)
+{
+ exit (0);
+}
+
+isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
+ control_object_state_t newstate)
+{
+ struct interface_info *ip;
+ struct client_state *client;
+
+ /* Do the right thing for each interface. */
+ for (ip = interfaces; ip; ip = ip -> next) {
+ for (client = ip -> client; client; client = client -> next) {
+ switch (newstate) {
+ case server_startup:
+ return ISC_R_SUCCESS;
+
+ case server_running:
+ return ISC_R_SUCCESS;
+
+ case server_shutdown:
+ if (client -> active &&
+ client -> active -> expiry > cur_time) {
+ client_dns_update (client, 0);
+ do_release (client);
+ }
+ break;
+
+ case server_hibernate:
+ state_stop (client);
+ break;
+
+ case server_awaken:
+ state_reboot (client);
+ break;
+ }
+ }
+ }
+ if (newstate == server_shutdown)
+ add_timeout (cur_time + 1, shutdown_exit, 0, 0, 0);
+ return ISC_R_SUCCESS;
+}
+
+/* See if we should do a DNS update, and if so, do it. */
+
+void client_dns_update (struct client_state *client, int addp)
+{
+ struct data_string ddns_fqdn, ddns_fwd_name,
+ ddns_dhcid, client_identifier;
+ struct option_cache *oc;
+ int ignorep;
+ int result;
+ isc_result_t rcode;
+
+ /* If we didn't send an FQDN option, we certainly aren't going to
+ be doing an update. */
+ if (!client -> sent_options)
+ return;
+
+ /* If we don't have a lease, we can't do an update. */
+ if (!client -> active)
+ return;
+
+ /* If we set the no client update flag, don't do the update. */
+ if ((oc = lookup_option (&fqdn_universe, client -> sent_options,
+ FQDN_NO_CLIENT_UPDATE)) &&
+ evaluate_boolean_option_cache (&ignorep, (struct packet *)0,
+ (struct lease *)0, client,
+ client -> sent_options,
+ (struct option_state *)0,
+ &global_scope, oc, MDL))
+ return;
+
+ /* If we set the "server, please update" flag, or didn't set it
+ to false, don't do the update. */
+ if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
+ FQDN_SERVER_UPDATE)) ||
+ evaluate_boolean_option_cache (&ignorep, (struct packet *)0,
+ (struct lease *)0, client,
+ client -> sent_options,
+ (struct option_state *)0,
+ &global_scope, oc, MDL))
+ return;
+
+ /* If no FQDN option was supplied, don't do the update. */
+ memset (&ddns_fwd_name, 0, sizeof ddns_fwd_name);
+ if (!(oc = lookup_option (&fqdn_universe, client -> sent_options,
+ FQDN_FQDN)) ||
+ !evaluate_option_cache (&ddns_fwd_name, (struct packet *)0,
+ (struct lease *)0, client,
+ client -> sent_options,
+ (struct option_state *)0,
+ &global_scope, oc, MDL))
+ return;
+
+ /* Make a dhcid string out of either the client identifier,
+ if we are sending one, or the interface's MAC address,
+ otherwise. */
+ memset (&ddns_dhcid, 0, sizeof ddns_dhcid);
+
+ memset (&client_identifier, 0, sizeof client_identifier);
+ if ((oc = lookup_option (&dhcp_universe, client -> sent_options,
+ DHO_DHCP_CLIENT_IDENTIFIER)) &&
+ evaluate_option_cache (&client_identifier, (struct packet *)0,
+ (struct lease *)0, client,
+ client -> sent_options,
+ (struct option_state *)0,
+ &global_scope, oc, MDL)) {
+ result = get_dhcid (&ddns_dhcid,
+ DHO_DHCP_CLIENT_IDENTIFIER,
+ client_identifier.data,
+ client_identifier.len);
+ data_string_forget (&client_identifier, MDL);
+ } else
+ result = get_dhcid (&ddns_dhcid, 0,
+ client -> interface -> hw_address.hbuf,
+ client -> interface -> hw_address.hlen);
+ if (!result) {
+ data_string_forget (&ddns_fwd_name, MDL);
+ return;
+ }
+
+ /* Start the resolver, if necessary. */
+ if (!resolver_inited) {
+ minires_ninit (&resolver_state);
+ resolver_inited = 1;
+ resolver_state.retrans = 1;
+ resolver_state.retry = 1;
+ }
+
+ /*
+ * Perform updates.
+ */
+ if (ddns_fwd_name.len && ddns_dhcid.len) {
+ if (addp)
+ rcode = ddns_update_a (&ddns_fwd_name,
+ client -> active -> address,
+ &ddns_dhcid, DEFAULT_DDNS_TTL,
+ 1);
+ else
+ rcode = ddns_remove_a (&ddns_fwd_name,
+ client -> active -> address,
+ &ddns_dhcid);
+ }
+
+ data_string_forget (&ddns_fwd_name, MDL);
+ data_string_forget (&ddns_dhcid, MDL);
+}
diff --git a/contrib/isc-dhcp/client/dhclient.conf.5 b/contrib/isc-dhcp/client/dhclient.conf.5
index 6919081..ecdd4eb 100644
--- a/contrib/isc-dhcp/client/dhclient.conf.5
+++ b/contrib/isc-dhcp/client/dhclient.conf.5
@@ -1,8 +1,6 @@
.\" dhclient.conf.5
.\"
-.\" Copyright (c) 1997 The Internet Software Consortium.
-.\" All rights reserved.
-.\"
+.\" Copyright (c) 1996-2001 Internet Software Consortium.
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
@@ -31,10 +29,11 @@
.\" SUCH DAMAGE.
.\"
.\" This software has been written for the Internet Software Consortium
-.\" by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
-.\" Enterprises. To learn more about the Internet Software Consortium,
-.\" see ``http://www.isc.org/isc''. To learn more about Vixie
-.\" Enterprises, see ``http://www.vix.com''.
+.\" by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+.\" To learn more about the Internet Software Consortium, see
+.\" ``http://www.isc.org/''. To learn more about Vixie Enterprises,
+.\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+.\" ``http://www.nominum.com''.
.TH dhclient.conf 5
.SH NAME
dhclient.conf - DHCP client configuration file
@@ -190,7 +189,17 @@ are called \fIDHCP Options\fR. DHCP Options are defined in
The request statement causes the client to request that any server
responding to the client send the client its values for the specified
options. Only the option names should be specified in the request
-statement - not option parameters.
+statement - not option parameters. By default, the DHCP server
+requests the subnet-mask, broadcast-address, time-offset, routers,
+domain-name, domain-name-servers and host-name options.
+.PP
+In some cases, it may be desirable to send no parameter request list
+at all. To do this, simply write the request statement but specify
+no parameters:
+.PP
+.nf
+ request;
+.fi
.PP
.I The
.B require
@@ -218,6 +227,26 @@ than the default requested lease time, which is two hours. The other
obvious use for this statement is to send information to the server
that will allow it to differentiate between this client and other
clients or kinds of clients.
+.SH DYNAMIC DNS
+The client now has some very limited support for doing DNS updates
+when a lease is acquired. This is prototypical, and probably doesn't
+do what you want. It also only works if you happen to have control
+over your DNS server, which isn't very likely.
+.PP
+To make it work, you have to declare a key and zone as in the DHCP
+server (see \fBdhcpd.conf\fR(5) for details). You also need to
+configure the fqdn option on the client, as follows:
+.PP
+.nf
+ send fqdn.fqdn "grosse.fugue.com.";
+ send fqdn.encoded on;
+ send fqdn.server-update off;
+.fi
+.PP
+The \fIfqdn.fqdn\fR option \fBMUST\fR be a fully-qualified domain
+name. You \fBMUST\fR define a zone statement for the zone to be
+updated. The \fIfqdn.encoded\fR option may need to be set to
+\fIon\fR or \fIoff\fR, depending on the DHCP server you are using.
.SH OPTION MODIFIERS
In some cases, a client may receive option data from the server which
is not really appropriate for that client, or may not receive
@@ -230,10 +259,9 @@ needs, several option modifiers are available.
.B default
.I statement
.PP
- \fBdefault { [ \fIoption declaration\fR ]
-[\fB,\fI ... \fIoption declaration\fR ]\fB}\fR
+ \fBdefault [ \fIoption declaration\fR ] \fB;\fR
.PP
-If for some set of options the client should use the value supplied by
+If for some option the client should use the value supplied by
the server, but needs to use some default value if no value was supplied
by the server, these values can be defined in the
.B default
@@ -243,12 +271,11 @@ statement.
.B supersede
.I statement
.PP
- \fBsupersede { [ \fIoption declaration\fR ]
-[\fB,\fI ... \fIoption declaration\fR ]\fB}\fR
+ \fBsupersede [ \fIoption declaration\fR ] \fB;\fR
.PP
-If for some set of options the client should always use its own value
-rather than any value supplied by the server, these values can be
-defined in the
+If for some option the client should always use a locally-configured
+value or values rather than whatever is supplied by the server, these
+values can be defined in the
.B supersede
statement.
.PP
@@ -256,8 +283,7 @@ statement.
.B prepend
.I statement
.PP
- \fBprepend { [ \fIoption declaration\fR ]
-[\fB,\fI ... \fIoption declaration\fR ]\fB}\fR
+ \fBprepend [ \fIoption declaration\fR ] \fB;\fR
.PP
If for some set of options the client should use a value you
supply, and then use the values supplied by
@@ -267,14 +293,13 @@ statement. The
.B prepend
statement can only be used for options which
allow more than one value to be given. This restriction is not
-enforced - if violated, the results are unpredictable.
+enforced - if you ignore it, the behaviour will be unpredictable.
.PP
.I The
.B append
.I statement
.PP
- \fBappend { [ \fIoption declaration\fR ]
-[\fB,\fI ... \fIoption declaration\fR ]\fB}\fR
+ \fBappend [ \fIoption declaration\fR ] \fB;\fR
.PP
If for some set of options the client should first use the values
supplied by the server, if any, and then use values you supply, these
@@ -380,7 +405,18 @@ interface's final configuration once a lease has been acquired. If
no lease is acquired, the script is used to test predefined leases, if
any, and also called once if no valid lease can be identified. For
more information, see
-.B dhclient-lease(8).
+.B dhclient-script(8).
+.PP
+ \fBvendor option space "\fIname\fB";\fR
+.PP
+The
+.B vendor option space
+statement is used to specify which option space should be used for
+decoding the vendor-encapsulate-options option if one is received.
+The \fIdhcp-vendor-identifier\fR can be used to request a specific
+class of vendor options from the server. See
+.B dhcp-options(5)
+for details.
.PP
\fBmedium "\fImedia setup\fB";\fR
.PP
@@ -432,8 +468,8 @@ specified as zero. The year is specified with the century, so it
should generally be four digits except for really long leases. The
month is specified as a number starting with 1 for January. The day
of the month is likewise specified starting with 1. The hour is a
-number between 0 and 23, the minute a number between 0 and 69, and the
-second also a number between 0 and 69.
+number between 0 and 23, the minute a number between 0 and 59, and the
+second also a number between 0 and 59.
.SH ALIAS DECLARATIONS
\fBalias { \fI declarations ... \fB}\fR
.PP
@@ -474,6 +510,36 @@ specified name. Interfaces for which there is no interface
declaration will use the parameters declared outside of any interface
declaration, or the default settings.
.PP
+ \fBpseudo "\fIname\fR" "\fIreal-name\fB" { \fIdeclarations ... \fB }
+.PP
+Under some circumstances it can be useful to declare a pseudo-interface
+and have the DHCP client acquire a configuration for that interface.
+Each interface that the DHCP client is supporting normally has a DHCP
+client state machine running on it to acquire and maintain its lease.
+A pseudo-interface is just another state machine running on the
+interface named \fIreal-name\fR, with its own lease and its own
+state. If you use this feature, you must provide a client identifier
+for both the pseudo-interface and the actual interface, and the two
+identifiers must be different. You must also provide a seperate
+client script for the pseudo-interface to do what you want with the IP
+address. For example:
+.PP
+.nf
+ interface "ep0" {
+ send dhcp-client-identifier "my-client-ep0";
+ }
+ pseudo "secondary" "ep0" {
+ send dhcp-client-identifier "my-client-ep0-secondary";
+ script "/etc/dhclient-secondary";
+ }
+.fi
+.PP
+The client script for the pseudo-interface should not configure the
+interface up or down - essentially, all it needs to handle are the
+states where a lease has been acquired or renewed, and the states
+where a lease has expired. See \fBdhclient-script(8)\fR for more
+information.
+.PP
\fBmedia "\fImedia setup\fB"\fI [ \fB, "\fImedia setup\fB", \fI... ]\fB;\fR
.PP
The
@@ -538,8 +604,8 @@ dhcp-options(5), dhclient.leases(5), dhcpd(8), dhcpd.conf(5), RFC2132,
RFC2131.
.SH AUTHOR
.B dhclient(8)
-was written by Ted Lemon <mellon@vix.com>
+was written by Ted Lemon
under a contract with Vixie Labs. Funding
-for this project was provided by the Internet Software Corporation.
+for this project was provided by the Internet Software Consortium.
Information about the Internet Software Consortium can be found at
-.B http://www.isc.org/isc.
+.B http://www.isc.org.
diff --git a/contrib/isc-dhcp/client/dhclient.leases.5 b/contrib/isc-dhcp/client/dhclient.leases.5
index e0da360..5f1418e 100644
--- a/contrib/isc-dhcp/client/dhclient.leases.5
+++ b/contrib/isc-dhcp/client/dhclient.leases.5
@@ -31,7 +31,7 @@
.\" SUCH DAMAGE.
.\"
.\" This software has been written for the Internet Software Consortium
-.\" by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
+.\" by Ted Lemon in cooperation with Vixie
.\" Enterprises. To learn more about the Internet Software Consortium,
.\" see ``http://www.isc.org/isc''. To learn more about Vixie
.\" Enterprises, see ``http://www.vix.com''.
@@ -55,8 +55,8 @@ dhclient(8), dhcp-options(5), dhclient.conf(5), dhcpd(8),
dhcpd.conf(5), RFC2132, RFC2131.
.SH AUTHOR
.B dhclient(8)
-was written by Ted Lemon <mellon@vix.com>
+was written by Ted Lemon
under a contract with Vixie Labs. Funding
-for this project was provided by the Internet Software Corporation.
+for this project was provided by the Internet Software Consortium.
Information about the Internet Software Consortium can be found at
-.B http://www.isc.org/isc.
+.B http://www.isc.org.
diff --git a/contrib/isc-dhcp/client/scripts/freebsd b/contrib/isc-dhcp/client/scripts/freebsd
index ce7a1bf..652d0d0 100755
--- a/contrib/isc-dhcp/client/scripts/freebsd
+++ b/contrib/isc-dhcp/client/scripts/freebsd
@@ -1,16 +1,24 @@
#!/bin/sh
+if [ -x /usr/bin/logger ]; then
+ LOGGER="/usr/bin/logger -s -p user.notice -t dhclient"
+else
+ LOGGER=echo
+fi
+
make_resolv_conf() {
- echo search $new_domain_name >/etc/resolv.conf
- for nameserver in $new_domain_name_servers; do
- echo nameserver $nameserver >>/etc/resolv.conf
- done
+ if [ "x$new_domain_name" != x ] && [ x"$new_domain_name_servers" != x ]; then
+ echo search $new_domain_name >/etc/resolv.conf
+ for nameserver in $new_domain_name_servers; do
+ echo nameserver $nameserver >>/etc/resolv.conf
+ done
+ fi
}
# Must be used on exit. Invokes the local dhcp client exit hooks, if any.
exit_with_hooks() {
exit_status=$1
- if [ -x /etc/dhclient-exit-hooks ]; then
+ if [ -f /etc/dhclient-exit-hooks ]; then
. /etc/dhclient-exit-hooks
fi
# probably should do something with exit status of the local script
@@ -18,7 +26,7 @@ exit_with_hooks() {
}
# Invoke the local dhcp client enter hooks, if they exist.
-if [ -x /etc/dhclient-enter-hooks ]; then
+if [ -f /etc/dhclient-enter-hooks ]; then
exit_status=0
. /etc/dhclient-enter-hooks
# allow the local script to abort processing of this state
@@ -29,11 +37,11 @@ if [ -x /etc/dhclient-enter-hooks ]; then
fi
if [ x$new_network_number != x ]; then
- echo New Network Number: $new_network_number
+ $LOGGER New Network Number: $new_network_number
fi
if [ x$new_broadcast_address != x ]; then
- echo New Broadcast Address: $new_broadcast_address
+ $LOGGER New Broadcast Address: $new_broadcast_address
new_broadcast_arg="broadcast $new_broadcast_address"
fi
if [ x$old_broadcast_address != x ]; then
@@ -50,8 +58,8 @@ if [ x$alias_subnet_mask != x ]; then
fi
if [ x$reason = xMEDIUM ]; then
- ifconfig $interface $medium
- ifconfig $interface inet -alias 0.0.0.0 $medium >/dev/null 2>&1
+ eval "ifconfig $interface $medium"
+ eval "ifconfig $interface inet -alias 0.0.0.0 $medium" >/dev/null 2>&1
sleep 1
exit_with_hooks 0
fi
@@ -72,36 +80,53 @@ fi
if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \
[ x$reason = xREBIND ] || [ x$reason = xREBOOT ]; then
+ current_hostname=`hostname`
+ if [ x$current_hostname = x ] || \
+ [ x$current_hostname = x$old_host_name ]; then
+ if [ x$current_hostname = x ] || \
+ [ x$new_host_name != x$old_host_name ]; then
+ $LOGGER "New Hostname: $new_host_name"
+ hostname $new_host_name
+ fi
+ fi
if [ x$old_ip_address != x ] && [ x$alias_ip_address != x ] && \
[ x$alias_ip_address != x$old_ip_address ]; then
ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1
route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1
fi
- if [ x$old_ip_address != x ] && [ x$old_ip_address != x$new_ip_address ]; then
- ifconfig $interface inet -alias $old_ip_address $medium
+ if [ x$old_ip_address != x ] && [ x$old_ip_address != x$new_ip_address ]
+ then
+ eval "ifconfig $interface inet -alias $old_ip_address $medium"
route delete $old_ip_address 127.1 >/dev/null 2>&1
for router in $old_routers; do
route delete default $router >/dev/null 2>&1
done
if [ "$old_static_routes" != "" ]; then
- set $old_static_routes
+ set -- $old_static_routes
while [ $# -gt 1 ]; do
route delete $1 $2
shift; shift
done
fi
- arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -n -d \1/p' |sh
+ arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -d \1/p' |sh
fi
if [ x$old_ip_address = x ] || [ x$old_ip_address != x$new_ip_address ] || \
[ x$reason = xBOUND ] || [ x$reason = xREBOOT ]; then
- ifconfig $interface inet $new_ip_address $new_netmask_arg \
- $new_broadcast_arg $medium
+ eval "ifconfig $interface inet $new_ip_address $new_netmask_arg \
+ $new_broadcast_arg $medium"
+ $LOGGER "New IP Address($interface): $new_ip_address"
+ $LOGGER "New Subnet Mask($interface): $new_subnet_mask"
+ $LOGGER "New Broadcast Address($interface): $new_broadcast_address"
+ if [ "$new_routers" != "" ]; then
+ $LOGGER "New Routers: $new_routers"
+ fi
route add $new_ip_address 127.1 >/dev/null 2>&1
for router in $new_routers; do
route add default $router >/dev/null 2>&1
done
if [ "$new_static_routes" != "" ]; then
- set $new_static_routes
+ $LOGGER "New Static Routes: $new_static_routes"
+ set -- $new_static_routes
while [ $# -gt 1 ]; do
route add $1 $2
shift; shift
@@ -113,26 +138,24 @@ if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \
ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg
route add $alias_ip_address 127.0.0.1
fi
- echo search $new_domain_name >/etc/resolv.conf
- for nameserver in $new_domain_name_servers; do
- echo nameserver $nameserver >>/etc/resolv.conf
- done
+ make_resolv_conf
exit_with_hooks 0
fi
-if [ x$reason = xEXPIRE ] || [ x$reason = xFAIL ]; then
+if [ x$reason = xEXPIRE ] || [ x$reason = xFAIL ] || [ x$reason = xRELEASE ] \
+ || [ x$reason = xSTOP ]; then
if [ x$alias_ip_address != x ]; then
ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1
route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1
fi
if [ x$old_ip_address != x ]; then
- ifconfig $interface inet -alias $old_ip_address $medium
+ eval "ifconfig $interface inet -alias $old_ip_address $medium"
route delete $old_ip_address 127.1 >/dev/null 2>&1
for router in $old_routers; do
route delete default $router >/dev/null 2>&1
done
if [ "$old_static_routes" != "" ]; then
- set $old_static_routes
+ set -- $old_static_routes
while [ $# -gt 1 ]; do
route delete $1 $2
shift; shift
@@ -153,11 +176,15 @@ if [ x$reason = xTIMEOUT ]; then
ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1
route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1
fi
- ifconfig $interface inet $new_ip_address $new_netmask_arg \
- $new_broadcast_arg $medium
+ eval "ifconfig $interface inet $new_ip_address $new_netmask_arg \
+ $new_broadcast_arg $medium"
+ $LOGGER "New IP Address($interface): $new_ip_address"
+ $LOGGER "New Subnet Mask($interface): $new_subnet_mask"
+ $LOGGER "New Broadcast Address($interface): $new_broadcast_address"
sleep 1
if [ "$new_routers" != "" ]; then
- set $new_routers
+ $LOGGER "New Routers: $new_routers"
+ set -- $new_routers
if ping -q -c 1 $1; then
if [ x$new_ip_address != x$alias_ip_address ] && \
[ x$alias_ip_address != x ]; then
@@ -168,34 +195,27 @@ if [ x$reason = xTIMEOUT ]; then
for router in $new_routers; do
route add default $router >/dev/null 2>&1
done
- set $new_static_routes
+ set -- $new_static_routes
while [ $# -gt 1 ]; do
- route add $0 $1
+ route add $1 $2
shift; shift
done
- echo search $new_domain_name >/etc/resolv.conf.std
- for nameserver in $new_domain_name_servers; do
- echo nameserver $nameserver >>/etc/resolv.conf.std
- done
- if [ -f /etc/resolv.conf ]; then
- rm -f /etc/resolv.conf
- fi
- mv /etc/resolv.conf.std /etc/resolv.conf
+ make_resolv_conf
exit_with_hooks 0
fi
fi
- ifconfig $interface inet -alias $new_ip_address $medium
+ eval "ifconfig $interface inet -alias $new_ip_address $medium"
for router in $old_routers; do
route delete default $router >/dev/null 2>&1
done
if [ "$old_static_routes" != "" ]; then
- set $old_static_routes
+ set -- $old_static_routes
while [ $# -gt 1 ]; do
route delete $1 $2
shift; shift
done
fi
- arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -n -d \1/p' \
+ arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -d \1/p' \
|sh >/dev/null 2>&1
exit_with_hooks 1
fi
OpenPOWER on IntegriCloud