aboutsummaryrefslogtreecommitdiff
path: root/contrib/isc-dhcp/client
diff options
context:
space:
mode:
authorDavid E. O'Brien <obrien@FreeBSD.org>1999-02-10 09:10:13 +0000
committerDavid E. O'Brien <obrien@FreeBSD.org>1999-02-10 09:10:13 +0000
commitcd2d014aab8332077aba9b0f6e0d06678fbe1aff (patch)
tree238471ef1d73dff2645de45ab083d2123bf56b83 /contrib/isc-dhcp/client
downloadsrc-cd2d014aab8332077aba9b0f6e0d06678fbe1aff.tar.gz
src-cd2d014aab8332077aba9b0f6e0d06678fbe1aff.zip
Virgin import of ISC-DHCP v2.0b1pl6vendor/isc-dhcp/2.0b1-pl.6
Notes
Notes: svn path=/vendor/isc-dhcp/dist/; revision=43829 svn path=/vendor/isc-dhcp/2.0b1-pl.6/; revision=43831; tag=vendor/isc-dhcp/2.0b1-pl.6
Diffstat (limited to 'contrib/isc-dhcp/client')
-rw-r--r--contrib/isc-dhcp/client/clparse.c1026
-rw-r--r--contrib/isc-dhcp/client/dhclient-script.8191
-rw-r--r--contrib/isc-dhcp/client/dhclient.8163
-rw-r--r--contrib/isc-dhcp/client/dhclient.c2052
-rw-r--r--contrib/isc-dhcp/client/dhclient.conf36
-rw-r--r--contrib/isc-dhcp/client/dhclient.conf.5543
-rw-r--r--contrib/isc-dhcp/client/dhclient.leases.562
-rwxr-xr-xcontrib/isc-dhcp/client/scripts/freebsd174
8 files changed, 4247 insertions, 0 deletions
diff --git a/contrib/isc-dhcp/client/clparse.c b/contrib/isc-dhcp/client/clparse.c
new file mode 100644
index 000000000000..37fafd378f97
--- /dev/null
+++ b/contrib/isc-dhcp/client/clparse.c
@@ -0,0 +1,1026 @@
+/* clparse.c
+
+ Parser for dhclient config and lease files... */
+
+/*
+ * Copyright (c) 1997 The 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
+ * are met:
+ *
+ * 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 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.vix.com/isc''. To learn more about Vixie
+ * Enterprises, see ``http://www.vix.com''.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: clparse.c,v 1.13.2.1 1998/06/25 21:11:27 mellon Exp $ Copyright (c) 1997 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+#include "dhctoken.h"
+
+static TIME parsed_time;
+
+struct client_config top_level_config;
+u_int32_t requested_lease_time;
+
+/* client-conf-file :== client-declarations EOF
+ client-declarations :== <nil>
+ | client-declaration
+ | client-declarations client-declaration */
+
+int read_client_conf ()
+{
+ FILE *cfile;
+ char *val;
+ int token;
+ int declaration = 0;
+ struct client_config *config;
+ struct client_state *state;
+ struct interface_info *ip;
+
+ new_parse (path_dhclient_conf);
+
+ /* Set up the initial dhcp option universe. */
+ initialize_universes ();
+
+ /* Initialize the top level client configuration. */
+ memset (&top_level_config, 0, sizeof top_level_config);
+
+ /* Set some defaults... */
+ top_level_config.timeout = 60;
+ top_level_config.select_interval = 0;
+ top_level_config.reboot_timeout = 10;
+ top_level_config.retry_interval = 300;
+ top_level_config.backoff_cutoff = 120;
+ top_level_config.initial_interval = 10;
+ top_level_config.bootp_policy = ACCEPT;
+ top_level_config.script_name = "/etc/dhclient-script";
+ 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;
+ requested_lease_time = 7200;
+ top_level_config.send_options [DHO_DHCP_LEASE_TIME].data
+ = (unsigned char *)&requested_lease_time;
+ top_level_config.send_options [DHO_DHCP_LEASE_TIME].len
+ = sizeof requested_lease_time;
+
+ if ((cfile = fopen (path_dhclient_conf, "r")) == NULL)
+ error ("Can't open %s: %m", path_dhclient_conf);
+ do {
+ token = peek_token (&val, cfile);
+ if (token == EOF)
+ break;
+ parse_client_statement (cfile, (struct interface_info *)0,
+ &top_level_config);
+ } while (1);
+ token = next_token (&val, cfile); /* Clear the peek buffer */
+
+ /* Set up state and config structures for clients that don't
+ have per-interface configuration declarations. */
+ 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));
+ if (!ip -> client)
+ error ("no memory for client state.");
+ memset (ip -> client, 0, sizeof *(ip -> client));
+ }
+ if (!ip -> client -> config) {
+ if (!config) {
+ config = (struct client_config *)
+ malloc (sizeof (struct client_config));
+ if (!config)
+ error ("no memory for client config.");
+ memcpy (config, &top_level_config,
+ sizeof top_level_config);
+ }
+ ip -> client -> config = config;
+ }
+ }
+
+ return !warnings_occurred;
+}
+
+/* lease-file :== client-lease-statements EOF
+ client-lease-statements :== <nil>
+ | client-lease-statements LEASE client-lease-statement */
+
+void read_client_leases ()
+{
+ FILE *cfile;
+ 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)
+ return;
+ do {
+ token = next_token (&val, cfile);
+ if (token == EOF)
+ break;
+ if (token != LEASE) {
+ warn ("Corrupt lease file - possible data loss!");
+ skip_to_semi (cfile);
+ break;
+ } else
+ parse_client_lease_statement (cfile, 0);
+
+ } while (1);
+}
+
+/* client-declaration :==
+ SEND option-decl |
+ DEFAULT option-decl |
+ SUPERSEDE option-decl |
+ PREPEND option-decl |
+ APPEND option-decl |
+ hardware-declaration |
+ REQUEST option-list |
+ REQUIRE option-list |
+ TIMEOUT number |
+ RETRY number |
+ REBOOT number |
+ SELECT_TIMEOUT number |
+ SCRIPT string |
+ interface-declaration |
+ LEASE client-lease-statement |
+ ALIAS client-lease-statement */
+
+void parse_client_statement (cfile, ip, config)
+ FILE *cfile;
+ struct interface_info *ip;
+ struct client_config *config;
+{
+ int token;
+ char *val;
+ struct option *option;
+
+ switch (next_token (&val, cfile)) {
+ case SEND:
+ parse_option_decl (cfile, &config -> send_options [0]);
+ return;
+
+ case DEFAULT:
+ option = parse_option_decl (cfile, &config -> defaults [0]);
+ if (option)
+ config -> default_actions [option -> code] =
+ ACTION_DEFAULT;
+ return;
+
+ case SUPERSEDE:
+ option = parse_option_decl (cfile, &config -> defaults [0]);
+ if (option)
+ config -> default_actions [option -> code] =
+ ACTION_SUPERSEDE;
+ return;
+
+ case APPEND:
+ option = parse_option_decl (cfile, &config -> defaults [0]);
+ if (option)
+ config -> default_actions [option -> code] =
+ ACTION_APPEND;
+ return;
+
+ case PREPEND:
+ option = parse_option_decl (cfile, &config -> defaults [0]);
+ if (option)
+ config -> default_actions [option -> code] =
+ ACTION_PREPEND;
+ return;
+
+ case MEDIA:
+ parse_string_list (cfile, &config -> media, 1);
+ return;
+
+ case HARDWARE:
+ if (ip) {
+ parse_hardware_param (cfile, &ip -> hw_address);
+ } else {
+ parse_warn ("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);
+ return;
+
+ case TIMEOUT:
+ parse_lease_time (cfile, &config -> timeout);
+ return;
+
+ case RETRY:
+ parse_lease_time (cfile, &config -> retry_interval);
+ return;
+
+ case SELECT_TIMEOUT:
+ parse_lease_time (cfile, &config -> select_interval);
+ return;
+
+ case REBOOT:
+ parse_lease_time (cfile, &config -> reboot_timeout);
+ return;
+
+ case BACKOFF_CUTOFF:
+ parse_lease_time (cfile, &config -> backoff_cutoff);
+ return;
+
+ case INITIAL_INTERVAL:
+ parse_lease_time (cfile, &config -> initial_interval);
+ return;
+
+ case SCRIPT:
+ config -> script_name = parse_string (cfile);
+ return;
+
+ case INTERFACE:
+ if (ip)
+ parse_warn ("nested interface declaration.");
+ parse_interface_declaration (cfile, config);
+ return;
+
+ case LEASE:
+ parse_client_lease_statement (cfile, 1);
+ return;
+
+ case ALIAS:
+ parse_client_lease_statement (cfile, 2);
+ return;
+
+ case REJECT:
+ 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;
+ u_int8_t *s;
+
+ 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.");
+ 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;
+ }
+ 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;
+ }
+ memcpy (buf, val, len + 1);
+ } else {
+ parse_warn ("expecting string or hexadecimal data");
+ skip_to_semi (cfile);
+ return 0;
+ }
+ return len;
+}
+
+/* option-list :== option_name |
+ option_list COMMA option_name */
+
+int parse_option_list (cfile, list)
+ FILE *cfile;
+ u_int8_t *list;
+{
+ int ix, i;
+ int token;
+ char *val;
+
+ ix = 0;
+ do {
+ token = next_token (&val, cfile);
+ if (!is_identifier (token)) {
+ parse_warn ("expected option name.");
+ skip_to_semi (cfile);
+ return 0;
+ }
+ 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);
+ skip_to_semi (cfile);
+ return 0;
+ }
+ token = next_token (&val, cfile);
+ } while (token == COMMA);
+ if (token != SEMI) {
+ parse_warn ("expecting semicolon.");
+ skip_to_semi (cfile);
+ return 0;
+ }
+ return ix;
+}
+
+/* interface-declaration :==
+ INTERFACE string LBRACE client-declarations RBRACE */
+
+void parse_interface_declaration (cfile, outer_config)
+ FILE *cfile;
+ struct client_config *outer_config;
+{
+ int token;
+ char *val;
+
+ struct interface_info dummy_interface, *ip;
+ struct client_state dummy_state;
+ struct client_config dummy_config;
+
+ token = next_token (&val, cfile);
+ if (token != STRING) {
+ parse_warn ("expecting interface name (in quotes).");
+ skip_to_semi (cfile);
+ return;
+ }
+
+ ip = interface_or_dummy (val);
+
+ if (!ip -> client)
+ make_client_state (ip);
+
+ if (!ip -> client -> config)
+ make_client_config (ip, outer_config);
+
+ ip -> flags &= ~INTERFACE_AUTOMATIC;
+ interfaces_requested = 1;
+
+ token = next_token (&val, cfile);
+ if (token != LBRACE) {
+ parse_warn ("expecting left brace.");
+ skip_to_semi (cfile);
+ return;
+ }
+
+ do {
+ token = peek_token (&val, cfile);
+ if (token == EOF) {
+ parse_warn ("unterminated interface declaration.");
+ return;
+ }
+ if (token == RBRACE)
+ break;
+ parse_client_statement (cfile, ip, ip -> client -> config);
+ } while (1);
+ token = next_token (&val, cfile);
+}
+
+struct interface_info *interface_or_dummy (name)
+ char *name;
+{
+ struct interface_info *ip;
+
+ /* Find the interface (if any) that matches the name. */
+ for (ip = interfaces; ip; ip = ip -> next) {
+ if (!strcmp (ip -> name, name))
+ 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))
+ 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);
+ strcpy (ip -> name, name);
+ ip -> next = dummy_interfaces;
+ dummy_interfaces = ip;
+ }
+ return ip;
+}
+
+void make_client_state (ip)
+ struct interface_info *ip;
+{
+ 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));
+}
+
+void make_client_config (ip, config)
+ struct interface_info *ip;
+ 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-lease-statement :==
+ RBRACE client-lease-declarations LBRACE
+
+ client-lease-declarations :==
+ <nil> |
+ client-lease-declaration |
+ client-lease-declarations client-lease-declaration */
+
+
+void parse_client_lease_statement (cfile, is_static)
+ FILE *cfile;
+ int is_static;
+{
+ struct client_lease *lease, *lp, *pl;
+ struct interface_info *ip;
+ int token;
+ char *val;
+
+ token = next_token (&val, cfile);
+ if (token != LBRACE) {
+ parse_warn ("expecting left brace.");
+ skip_to_semi (cfile);
+ return;
+ }
+
+ lease = (struct client_lease *)malloc (sizeof (struct client_lease));
+ if (!lease)
+ error ("no memory for lease.\n");
+ memset (lease, 0, sizeof *lease);
+ lease -> is_static = is_static;
+
+ ip = (struct interface_info *)0;
+
+ do {
+ token = peek_token (&val, cfile);
+ if (token == EOF) {
+ parse_warn ("unterminated lease declaration.");
+ return;
+ }
+ if (token == RBRACE)
+ break;
+ parse_client_lease_declaration (cfile, lease, &ip);
+ } while (1);
+ token = next_token (&val, 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);
+ return;
+ }
+
+ /* Make sure there's a client state structure... */
+ if (!ip -> client)
+ make_client_state (ip);
+
+ /* If this is an alias lease, it doesn't need to be sorted in. */
+ if (is_static == 2) {
+ ip -> client -> alias = lease;
+ return;
+ }
+
+ /* The new lease may supersede a lease that's not the
+ active lease but is still on the lease list, so scan the
+ 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) {
+ 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);
+ break;
+ }
+ }
+
+ /* 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;
+ return;
+ }
+
+ /* The last lease in the lease file on a particular interface is
+ the active lease for that interface. Of course, we don't know
+ what the last lease in the file is until we've parsed the whole
+ file, so at this point, we assume that the lease we just parsed
+ is the active lease for its interface. If there's already
+ an active lease for the interface, and this lease is for the same
+ ip address, then we just toss the old active lease and replace
+ it with this one. If this lease is for a different address,
+ 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 ==
+ lease -> address.len &&
+ !memcmp (ip -> client -> active -> address.iabuf,
+ lease -> address.iabuf,
+ lease -> address.len))
+ free_client_lease (ip -> client -> active);
+ else {
+ ip -> client -> active -> next =
+ ip -> client -> leases;
+ ip -> client -> leases = ip -> client -> active;
+ }
+ }
+ ip -> client -> active = lease;
+
+ /* phew. */
+}
+
+/* client-lease-declaration :==
+ BOOTP |
+ INTERFACE string |
+ FIXED_ADDR ip_address |
+ FILENAME string |
+ SERVER_NAME string |
+ OPTION option-decl |
+ RENEW time-decl |
+ REBIND time-decl |
+ EXPIRE time-decl */
+
+void parse_client_lease_declaration (cfile, lease, ipp)
+ FILE *cfile;
+ struct client_lease *lease;
+ struct interface_info **ipp;
+{
+ int token;
+ char *val;
+ char *t, *n;
+ struct interface_info *ip;
+
+ switch (next_token (&val, cfile)) {
+ case BOOTP:
+ lease -> is_bootp = 1;
+ break;
+
+ case INTERFACE:
+ token = next_token (&val, cfile);
+ if (token != STRING) {
+ parse_warn ("expecting interface name (in quotes).");
+ skip_to_semi (cfile);
+ break;
+ }
+ ip = interface_or_dummy (val);
+ *ipp = ip;
+ break;
+
+ case FIXED_ADDR:
+ if (!parse_ip_addr (cfile, &lease -> address))
+ return;
+ break;
+
+ case MEDIUM:
+ parse_string_list (cfile, &lease -> medium, 0);
+ return;
+
+ case FILENAME:
+ lease -> filename = parse_string (cfile);
+ return;
+
+ case SERVER_NAME:
+ lease -> server_name = parse_string (cfile);
+ return;
+
+ case RENEW:
+ lease -> renewal = parse_date (cfile);
+ return;
+
+ case REBIND:
+ lease -> rebind = parse_date (cfile);
+ return;
+
+ case EXPIRE:
+ lease -> expiry = parse_date (cfile);
+ return;
+
+ case OPTION:
+ parse_option_decl (cfile, lease -> options);
+ return;
+
+ default:
+ parse_warn ("expecting lease declaration.");
+ skip_to_semi (cfile);
+ break;
+ }
+ token = next_token (&val, cfile);
+ if (token != SEMI) {
+ parse_warn ("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 {
+ /* Set a flag if this is an array of a simple type (i.e.,
+ not an array of pairs of IP addresses, or something
+ like that. */
+ int uniform = option -> format [1] == 'A';
+
+ 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 string_list **lp;
+ int multiple;
+{
+ int token;
+ char *val;
+ struct string_list *cur, *tmp;
+
+ /* Find the last medium in the media list. */
+ if (*lp) {
+ for (cur = *lp; cur -> next; cur = cur -> next)
+ ;
+ } else {
+ cur = (struct string_list *)0;
+ }
+
+ do {
+ token = next_token (&val, cfile);
+ if (token != STRING) {
+ parse_warn ("Expecting media options.");
+ skip_to_semi (cfile);
+ return;
+ }
+
+ tmp = (struct string_list *)malloc (strlen (val) + 1 +
+ sizeof
+ (struct string_list *));
+ if (!tmp)
+ error ("no memory for string list entry.");
+
+ strcpy (tmp -> string, val);
+ tmp -> next = (struct string_list *)0;
+
+ /* Store this medium at the end of the media list. */
+ if (cur)
+ cur -> next = tmp;
+ else
+ *lp = tmp;
+ cur = tmp;
+
+ token = next_token (&val, cfile);
+ } while (multiple && token == COMMA);
+
+ if (token != SEMI) {
+ parse_warn ("expecting semicolon.");
+ skip_to_semi (cfile);
+ }
+}
+
+void parse_reject_statement (cfile, config)
+ FILE *cfile;
+ struct client_config *config;
+{
+ int token;
+ char *val;
+ struct iaddr addr;
+ struct iaddrlist *list;
+
+ do {
+ if (!parse_ip_addr (cfile, &addr)) {
+ parse_warn ("expecting IP address.");
+ skip_to_semi (cfile);
+ return;
+ }
+
+ list = (struct iaddrlist *)malloc (sizeof (struct iaddrlist));
+ if (!list)
+ error ("no memory for reject list!");
+
+ list -> addr = addr;
+ list -> next = config -> reject_list;
+ config -> reject_list = list;
+
+ token = next_token (&val, cfile);
+ } while (token == COMMA);
+
+ if (token != SEMI) {
+ parse_warn ("expecting semicolon.");
+ skip_to_semi (cfile);
+ }
+}
diff --git a/contrib/isc-dhcp/client/dhclient-script.8 b/contrib/isc-dhcp/client/dhclient-script.8
new file mode 100644
index 000000000000..bae59b4634ed
--- /dev/null
+++ b/contrib/isc-dhcp/client/dhclient-script.8
@@ -0,0 +1,191 @@
+.\" dhclient-script.8
+.\"
+.\" Copyright (c) 1997 The 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
+.\" are met:
+.\"
+.\" 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 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''.
+.TH dhclient 8
+.SH NAME
+dhclient-script - DHCP client network configuration script
+.SH DESCRIPTION
+The DHCP client network configuration script is invoked from time to
+time by \fBdhclient(8)\fR. This script is used by the dhcp client to
+set each interface's initial configuration prior to requesting an
+address, to test the address once it has been offered, and to set the
+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.
+.PP
+This script is not meant to be customized by the end user. However,
+the script may not work on particular versions of particular operating
+systems (indeed, no standard script exists for some operating
+systems), so a pioneering user may well need to create a new script or
+modify an existing one. In general, customizations specific to a
+particular computer should be done in the
+.B ETCDIR/dhclient.conf
+script. If you find that you can't make such a customization without
+customizing dhclient.conf, please submit a bug report.
+.SH OPERATION
+When dhclient needs to invoke the client configuration script, it
+writes a shell script into /tmp which defines a variety of variables.
+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.
+.PP
+.SH MEDIUM
+The DHCP client is requesting that an interface's media type
+be set. The interface name is passed in $interface, and the media
+type is passed in $medium.
+.SH PREINIT
+The DHCP client is requesting that an interface be configured as
+required in order to send packets prior to receiving an actual
+address. For clients which use the BSD socket library, this means
+configuring the interface with an IP address of 0.0.0.0 and a
+broadcast address of 255.255.255.255. For other clients, it may be
+possible to simply configure the interface up without actually giving
+it an IP address at all. The interface name is passed in $interface,
+and the media type in $medium.
+.PP
+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 ARPCHECK 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
+passed in $interface. The media type is passed in $medium. Any
+options acquired from the server are passed using the option name
+described in \fBdhcp-options\fR, except that dashes ('-') are replaced
+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
+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
+$new_domain_name_servers (which may list more than one server,
+seperated by spaces). A default route should be set using
+$new_routers, and static routes may need to be set up using
+$new_static_routes.
+.PP
+If an IP alias has been declared, it must be set up here. The alias
+IP address will be written as $alias_ip_address, and other DHCP
+options that are set for the alias (e.g., subnet mask) will be passed
+in variables named as described previously except starting with
+$alias_ instead of $new_. Care should be taken that the alias IP
+address not be used if it is identical to the bound IP address
+($new_ip_address), since the other alias parameters may be incorrect
+in this case.
+.SH RENEW
+When a binding has been renewed, the script is called as in BOUND,
+except that in addition to all the variables starting with $new_,
+there is another set of variables starting with $old_. Persistent
+settings that may have changed need to be deleted - for example, if a
+local route to the bound address is being configured, the old local
+route should be deleted. If the default route has changed, the old default
+route should be deleted. If the static routes have changed, the old
+ones should be deleted. Otherwise, processing can be done as with
+BOUND.
+.SH REBIND
+The DHCP client has rebound to a new DHCP server. This can be handled
+as with RENEW, except that if the IP address has changed, the ARP
+table should be cleared.
+.SH REBOOT
+The DHCP client has successfully reacquired its old address after a
+reboot. This can be processed as with BOUND.
+.SH EXPIRE
+The DHCP client has failed to renew its lease or acquire a new one,
+and the lease has expired. The IP address must be relinquished, and
+all related parameters should be deleted, as in RENEW and REBIND.
+.SH FAIL
+The DHCP client has been unable to contact any DHCP servers, and any
+leases that have been tested have not proved to be valid. The
+parameters from the last lease tested should be deconfigured. This
+can be handled in the same way as EXPIRE.
+.SH TIMEOUT
+The DHCP client has been unable to contact any DHCP servers.
+However, an old lease has been identified, and its parameters have
+been passed in as with BOUND. The client configuration script should
+test these parameters and, if it has reason to believe they are valid,
+should exit with a value of zero. If not, it should exit with a
+nonzero value.
+.PP
+The usual way to test a lease is to set up the network as with REBIND
+(since this may be called to test more than one lease) and then ping
+the first router defined in $routers. If a response is received, the
+lease must be valid for the network to which the interface is
+currently connected. It would be more complete to try to ping all of
+the routers listed in $new_routers, as well as those listed in
+$new_static_routes, but current scripts do not do this.
+.SH FILES
+Each operating system should generally have its own script file,
+although the script files for similar operating systems may be similar
+or even identical. The script files included in the Internet
+Software Consortium DHCP distribution appear in the distribution tree
+under client/scripts, and bear the names of the operating systems on
+which they are intended to work.
+.SH BUGS
+If more than one interface is being used, there's no obvious way to
+avoid clashes between server-supplied configuration parameters - for
+example, the stock dhclient-script rewrites /etc/resolv.conf. If
+more than one interface is being configured, /etc/resolv.conf will be
+repeatedly initialized to the values provided by one server, and then
+the other. Assuming the information provided by both servers is
+valid, this shouldn't cause any real problems, but it could be
+confusing.
+.SH SEE ALSO
+dhclient(8), dhcpd(8), dhcrelay(8), dhclient.conf(5) and
+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
+Enterprises. To learn more about the Internet Software Consortium,
+see
+.B http://www.vix.com/isc.
+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
new file mode 100644
index 000000000000..0406c49137ca
--- /dev/null
+++ b/contrib/isc-dhcp/client/dhclient.8
@@ -0,0 +1,163 @@
+.\" dhclient.8
+.\"
+.\" Copyright (c) 1997 The 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
+.\" are met:
+.\"
+.\" 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 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''.
+.TH dhclient 8
+.SH NAME
+dhclient - Dynamic Host Configuration Protocol Client
+.SH SYNOPSIS
+.B dhclient
+[
+.B -p
+.I port
+]
+[
+.B -d
+]
+[
+.I if0
+[
+.I ...ifN
+]
+]
+.SH DESCRIPTION
+The Internet Software Consortium DHCP Client, dhclient, provides a
+means for configuring one or more network interfaces using the Dynamic
+Host Configuration Protocol, BOOTP protocol, or if these protocols
+fail, by statically assigning an address.
+.SH OPERATION
+.PP
+The DHCP protocol allows a host to contact a central server which
+maintains a list of IP addresses which may be assigned on one or more
+subnets. A DHCP client may request an address from this pool, and
+then use it on a temporary basis for communication on network. The
+DHCP protocol also provides a mechanism whereby a client can learn
+important details about the network to which it is attached, such as
+the location of a default router, the location of a name server, and
+so on.
+.PP
+On startup, dhclient reads the
+.IR dhclient.conf
+for configuration instructions. It then gets a list of all the
+network interfaces that are configured in the current system. For
+each interface, it attempts to configure the interface using the DHCP
+protocol.
+.PP
+In order to keep track of leases across system reboots and server
+restarts, dhclient keeps a list of leases it has been assigned in the
+dhclient.leases(5) file. On startup, after reading the dhclient.conf
+file, dhclient reads the dhclient.leases file to refresh its memory
+about what leases it has been assigned.
+.PP
+When a new lease is acquired, it is appended to the end of the
+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~
+until the next time dhclient rewrites the database.
+.PP
+Old leases are kept around in case the DHCP server is unavailable when
+dhclient is first invoked (generally during the initial system boot
+process). In that event, old leases from the dhclient.leases file
+which have not yet expired are tested, and if they are determined to
+be valid, they are used until either they expire or the DHCP server
+becomes available.
+.PP
+A mobile host which may sometimes need to access a network on which no
+DHCP server exists may be preloaded with a lease for a fixed
+address on that network. When all attempts to contact a DHCP server
+have failed, dhclient will try to validate the static lease, and if it
+succeeds, will use that lease until it is restarted.
+.PP
+A mobile host may also travel to some networks on which DHCP is not
+available but BOOTP is. In that case, it may be advantageous to
+arrange with the network administrator for an entry on the BOOTP
+database, so that the host can boot quickly on that network rather
+than cycling through the list of old leases.
+.SH COMMAND LINE
+.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.
+.PP
+If dhclient 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.
+.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
+.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.
+.PP
+.SH CONFIGURATION
+The syntax of the dhclient.conf(8) file is discussed seperately.
+.SH FILES
+.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)
+.SH AUTHOR
+.B dhclient(8)
+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
+.B http://www.vix.com/isc.
+To learn more about Vixie
+Enterprises, see
+.B http://www.vix.com.
+.PP
+This client was substantially modified and enhanced by Elliot Poger
+for use on Linux while he was working on the MosquitoNet project at
+Stanford.
+.PP
+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.
+.PP
diff --git a/contrib/isc-dhcp/client/dhclient.c b/contrib/isc-dhcp/client/dhclient.c
new file mode 100644
index 000000000000..eb4d268f9768
--- /dev/null
+++ b/contrib/isc-dhcp/client/dhclient.c
@@ -0,0 +1,2052 @@
+/* dhclient.c
+
+ DHCP Client. */
+
+/*
+ * Copyright (c) 1995, 1996, 1997 The 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
+ * are met:
+ *
+ * 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 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.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.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: dhclient.c,v 1.44.2.1 1997/12/06 11:24:31 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+
+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;
+
+int interfaces_requested = 0;
+
+int log_perror = 1;
+
+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;
+
+/* ASSERT_STATE() does nothing now; it used to be
+ assert (state_is == state_shouldbe). */
+#define ASSERT_STATE(state_is, state_shouldbe) {}
+
+#ifdef USE_FALLBACK
+struct interface_info fallback_interface;
+#endif
+
+u_int16_t local_port;
+u_int16_t remote_port;
+int log_priority;
+int no_daemon;
+int save_scripts;
+
+static void usage PROTO ((void));
+
+int main (argc, argv, envp)
+ int argc;
+ char **argv, **envp;
+{
+ int i;
+ struct servent *ent;
+ struct interface_info *ip;
+ int seed;
+
+#ifdef SYSLOG_4_2
+ openlog ("dhclient", LOG_NDELAY);
+ log_priority = LOG_DAEMON;
+#else
+ openlog ("dhclient", LOG_NDELAY, LOG_DAEMON);
+#endif
+
+#if !(defined (DEBUG) || defined (SYSLOG_4_2) || defined (__CYGWIN32__))
+ setlogmask (LOG_UPTO (LOG_INFO));
+#endif
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp (argv [i], "-p")) {
+ if (++i == argc)
+ usage ();
+ local_port = htons (atoi (argv [i]));
+ 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 (argv [i][0] == '-') {
+ usage ();
+ } 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);
+ strcpy (tmp -> name, argv [i]);
+ tmp -> next = interfaces;
+ tmp -> flags = INTERFACE_REQUESTED;
+ interfaces_requested = 1;
+ interfaces = tmp;
+ }
+ }
+ /* 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;
+#ifndef __CYGWIN32__
+ endservent ();
+#endif
+ }
+ 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
+ inaddr_any.s_addr = INADDR_ANY;
+
+ /* Discover all the network interfaces. */
+ discover_interfaces (DISCOVER_UNCONFIGURED);
+
+ /* Parse the dhclient.conf file. */
+ read_client_conf ();
+
+ /* Parse the lease database. */
+ read_client_leases ();
+
+ /* Rewrite the lease database... */
+ rewrite_client_leases ();
+
+ /* If no broadcast interfaces were discovered, call the script
+ and tell it so. */
+ if (!interfaces) {
+ script_init ((struct interface_info *)0, "NBI",
+ (struct string_list *)0);
+ script_go ((struct interface_info *)0);
+
+ /* Nothing more to do. */
+ exit (0);
+ } else {
+ /* Call the script with the list of interfaces. */
+ for (ip = interfaces; ip; ip = ip -> next) {
+ script_init (ip, "PREINIT", (struct string_list *)0);
+ if (ip -> client -> alias)
+ script_write_params (ip, "alias_",
+ ip -> client -> alias);
+ script_go (ip);
+ }
+ }
+
+ /* At this point, all the interfaces that the script thinks
+ are relevant should be running, so now we once again call
+ discover_interfaces(), and this time ask it to actually set
+ up the interfaces. */
+ discover_interfaces (interfaces_requested
+ ? DISCOVER_REQUESTED
+ : DISCOVER_RUNNING);
+
+ /* Make up a seed for the random number generator from current
+ time plus the sum of the last four bytes of each
+ 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. :') */
+ for (ip = interfaces; ip; ip = ip -> next) {
+ int junk;
+ memcpy (&junk,
+ &ip -> hw_address.haddr [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);
+ }
+
+ /* Set up the bootp packet handler... */
+ bootp_packet_handler = do_packet;
+
+ /* Start dispatching packets and timeouts... */
+ dispatch ();
+
+ /*NOTREACHED*/
+ return 0;
+}
+
+static void usage ()
+{
+ error ("Usage: dhclient [-c] [-p <port>] [interface]");
+}
+
+void cleanup ()
+{
+}
+
+/* Individual States:
+ *
+ * Each routine is called from the dhclient_state_machine() in one of
+ * these conditions:
+ * -> entering INIT state
+ * -> recvpacket_flag == 0: timeout in this state
+ * -> otherwise: received a packet in this state
+ *
+ * Return conditions as handled by dhclient_state_machine():
+ * Returns 1, sendpacket_flag = 1: send packet, reset timer.
+ * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
+ * Returns 0: finish the nap which was interrupted for no good reason.
+ *
+ * Several per-interface variables are used to keep track of the process:
+ * active_lease: the lease that is being used on the interface
+ * (null pointer if not configured yet).
+ * offered_leases: leases corresponding to DHCPOFFER messages that have
+ * been sent to us by DHCP servers.
+ * acked_leases: leases corresponding to DHCPACK messages that have been
+ * sent to us by DHCP servers.
+ * sendpacket: DHCP packet we're trying to send.
+ * destination: IP address to send sendpacket to
+ * In addition, there are several relevant per-lease variables.
+ * T1_expiry, T2_expiry, lease_expiry: lease milestones
+ * In the active lease, these control the process of renewing the lease;
+ * In leases on the acked_leases list, this simply determines when we
+ * can no longer legitimately use the lease.
+ */
+
+void state_reboot (ipp)
+ void *ipp;
+{
+ struct interface_info *ip = ipp;
+
+ /* If we don't remember an active lease, go straight to INIT. */
+ if (!ip -> client -> active ||
+ ip -> client -> active -> is_bootp) {
+ state_init (ip);
+ return;
+ }
+
+ /* We are in the rebooting state. */
+ ip -> client -> state = S_REBOOTING;
+
+ /* Make a DHCPREQUEST packet, and set appropriate per-interface
+ flags. */
+ make_request (ip, ip -> client -> active);
+ ip -> client -> xid = ip -> client -> packet.xid;
+ ip -> client -> destination = iaddr_broadcast;
+ ip -> client -> first_sending = cur_time;
+ ip -> client -> interval = ip -> client -> config -> initial_interval;
+
+ /* Zap the medium list... */
+ ip -> client -> medium = (struct string_list *)0;
+
+ /* Send out the first DHCPREQUEST packet. */
+ send_request (ip);
+}
+
+/* Called when a lease has completely expired and we've been unable to
+ renew it. */
+
+void state_init (ipp)
+ void *ipp;
+{
+ struct interface_info *ip = ipp;
+
+ 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;
+
+ /* Add an immediate timeout to cause the first DHCPDISCOVER packet
+ to go out. */
+ send_discover (ip);
+}
+
+/* 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;
+{
+ struct interface_info *ip = ipp;
+
+ 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);
+
+ /* 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) {
+ 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);
+ }
+ }
+ ip -> 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);
+ 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;
+
+ /* 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;
+
+ ip -> client -> state = S_REQUESTING;
+
+ /* Bind to the address we received. */
+ bind_lease (ip);
+ 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;
+
+ /* Make a DHCPREQUEST packet from the lease we picked. */
+ make_request (ip, picked);
+ ip -> client -> xid = ip -> client -> packet.xid;
+
+ /* Toss the lease we picked - we'll get it back in a DHCPACK. */
+ free_client_lease (picked);
+
+ /* Add an immediate timeout to send the first DHCPREQUEST packet. */
+ send_request (ip);
+}
+
+/* state_requesting is called when we receive a DHCPACK message after
+ having sent out one or more DHCPREQUEST packets. */
+
+void dhcpack (packet)
+ struct packet *packet;
+{
+ struct interface_info *ip = packet -> interface;
+ struct client_lease *lease;
+ 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) {
+ debug ("DHCPACK in wrong transaction.");
+ return;
+ }
+
+ if (ip -> client -> state != S_REBOOTING &&
+ ip -> client -> state != S_REQUESTING &&
+ ip -> client -> state != S_RENEWING &&
+ ip -> client -> state != S_REBINDING) {
+ debug ("DHCPACK in wrong state.");
+ return;
+ }
+
+ note ("DHCPACK from %s", piaddr (packet -> client_addr));
+
+ lease = packet_to_lease (packet);
+ if (!lease) {
+ note ("packet_to_lease failed.");
+ return;
+ }
+
+ ip -> client -> new = lease;
+
+ /* Stop resending DHCPREQUEST. */
+ cancel_timeout (send_request, ip);
+
+ /* Figure out the lease time. */
+ ip -> client -> new -> expiry =
+ getULong (ip -> client ->
+ new -> options [DHO_DHCP_LEASE_TIME].data);
+
+ /* 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;
+
+ /* 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;
+
+ ip -> client -> new -> expiry += cur_time;
+ ip -> client -> new -> renewal += cur_time;
+ ip -> client -> new -> rebind += cur_time;
+
+ bind_lease (ip);
+}
+
+void bind_lease (ip)
+ struct interface_info *ip;
+{
+ /* Remember the medium. */
+ ip -> client -> new -> medium = ip -> client -> medium;
+
+ /* Write out the new lease. */
+ write_client_lease (ip, ip -> client -> new);
+
+ /* Run the client script with the new parameters. */
+ script_init (ip, (ip -> client -> state == S_REQUESTING
+ ? "BOUND"
+ : (ip -> client -> state == S_RENEWING
+ ? "RENEW"
+ : (ip -> 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);
+
+ /* 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;
+
+ /* Set up a timeout to start the renewal process. */
+ add_timeout (ip -> client -> active -> renewal,
+ state_bound, ip);
+
+ note ("bound to %s -- renewal in %d seconds.",
+ piaddr (ip -> client -> active -> address),
+ ip -> client -> active -> renewal - cur_time);
+ ip -> client -> state = S_BOUND;
+ reinitialize_interfaces ();
+ go_daemon ();
+}
+
+/* state_bound is called when we've successfully bound to a particular
+ lease, but the renewal time on that lease has expired. We are
+ expected to unicast a DHCPREQUEST to the server that gave us our
+ original lease. */
+
+void state_bound (ipp)
+ void *ipp;
+{
+ struct interface_info *ip = ipp;
+
+ 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;
+ } else
+ ip -> client -> destination = iaddr_broadcast;
+
+ ip -> client -> first_sending = cur_time;
+ ip -> client -> interval = ip -> client -> config -> initial_interval;
+ ip -> client -> state = S_RENEWING;
+
+ /* Send the first packet immediately. */
+ send_request (ip);
+}
+
+int commit_leases ()
+{
+ return 0;
+}
+
+int write_lease (lease)
+ struct lease *lease;
+{
+ return 0;
+}
+
+void db_startup ()
+{
+}
+
+void bootp (packet)
+ struct packet *packet;
+{
+ struct iaddrlist *ap;
+
+ if (packet -> raw -> op != BOOTREPLY)
+ return;
+
+ /* If there's a reject list, make sure this packet's sender isn't
+ on it. */
+ 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.",
+ piaddr (ap -> addr));
+ return;
+ }
+ }
+
+ dhcpoffer (packet);
+
+}
+
+void dhcp (packet)
+ struct packet *packet;
+{
+ struct iaddrlist *ap;
+ void (*handler) PROTO ((struct packet *));
+ char *type;
+
+ switch (packet -> packet_type) {
+ case DHCPOFFER:
+ handler = dhcpoffer;
+ type = "DHCPOFFER";
+ break;
+
+ case DHCPNAK:
+ handler = dhcpnak;
+ type = "DHCPNACK";
+ break;
+
+ case DHCPACK:
+ handler = dhcpack;
+ type = "DHCPACK";
+ break;
+
+ default:
+ return;
+ }
+
+ /* If there's a reject list, make sure this packet's sender isn't
+ on it. */
+ 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.",
+ type, piaddr (ap -> addr));
+ return;
+ }
+ }
+ (*handler) (packet);
+}
+
+void dhcpoffer (packet)
+ struct packet *packet;
+{
+ struct interface_info *ip = packet -> interface;
+ struct client_lease *lease, *lp;
+ int i;
+ int arp_timeout_needed, stop_selecting;
+ char *name = (packet -> options [DHO_DHCP_MESSAGE_TYPE].len
+ ? "DHCPOFFER" : "BOOTREPLY");
+ struct iaddrlist *ap;
+
+#ifdef DEBUG_PACKET
+ dump_packet (packet);
+#endif
+
+ /* 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) {
+ debug ("%s in wrong transaction.", name);
+ return;
+ }
+
+ note ("%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 we've already seen this lease, don't record it again. */
+ for (lease = ip -> 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);
+ return;
+ }
+ }
+
+ lease = packet_to_lease (packet);
+ if (!lease) {
+ note ("packet_to_lease failed.");
+ return;
+ }
+
+ /* If this lease was acquired through a BOOTREPLY, record that
+ fact. */
+ if (!packet -> options [DHO_DHCP_MESSAGE_TYPE].len)
+ 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;
+
+ /* Figure out when we're supposed to stop selecting. */
+ stop_selecting = (ip -> client -> first_sending +
+ ip -> 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 &&
+ !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;
+ } 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;
+ else {
+ for (lp = ip -> 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);
+ else {
+ add_timeout (stop_selecting, state_selecting, ip);
+ cancel_timeout (send_discover, ip);
+ }
+}
+
+/* Allocate a client_lease structure and initialize it from the parameters
+ in the specified packet. */
+
+struct client_lease *packet_to_lease (packet)
+ struct packet *packet;
+{
+ struct client_lease *lease;
+ int i;
+
+ lease = (struct client_lease *)malloc (sizeof (struct client_lease));
+
+ if (!lease) {
+ warn ("dhcpoffer: 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;
+ }
+ }
+ }
+
+ lease -> address.len = sizeof (packet -> raw -> yiaddr);
+ memcpy (lease -> address.iabuf, &packet -> raw -> yiaddr,
+ lease -> address.len);
+
+ /* 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;
+ /* 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);
+ if (!lease -> server_name) {
+ warn ("dhcpoffer: no memory for filename.\n");
+ free_client_lease (lease);
+ return (struct client_lease *)0;
+ } else {
+ memcpy (lease -> server_name,
+ packet -> raw -> sname, len);
+ lease -> server_name [len] = 0;
+ }
+ }
+
+ /* 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;
+ /* Don't count on the NUL terminator. */
+ for (len = 0; len < 64; len++)
+ if (!packet -> raw -> file [len])
+ break;
+ lease -> filename = malloc (len + 1);
+ if (!lease -> filename) {
+ warn ("dhcpoffer: no memory for filename.\n");
+ free_client_lease (lease);
+ return (struct client_lease *)0;
+ } else {
+ memcpy (lease -> filename,
+ packet -> raw -> file, len);
+ lease -> filename [len] = 0;
+ }
+ }
+ return lease;
+}
+
+void dhcpnak (packet)
+ struct packet *packet;
+{
+ struct interface_info *ip = packet -> interface;
+
+ /* 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) {
+ debug ("DHCPNAK in wrong transaction.");
+ return;
+ }
+
+ if (ip -> client -> state != S_REBOOTING &&
+ ip -> client -> state != S_REQUESTING &&
+ ip -> client -> state != S_RENEWING &&
+ ip -> client -> state != S_REBINDING) {
+ debug ("DHCPNAK in wrong state.");
+ return;
+ }
+
+ note ("DHCPNAK from %s", piaddr (packet -> client_addr));
+
+ if (!ip -> client -> active) {
+ note ("DHCPNAK with no active lease.\n");
+ return;
+ }
+
+ free_client_lease (ip -> client -> active);
+ ip -> client -> active = (struct client_lease *)0;
+
+ /* Stop sending DHCPREQUEST packets... */
+ cancel_timeout (send_request, ip);
+
+ ip -> client -> state = S_INIT;
+ state_init (ip);
+}
+
+/* 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;
+{
+ struct interface_info *ip = ipp;
+
+ 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;
+
+ /* 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);
+ 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) {
+ int fail = 0;
+ again:
+ if (ip -> client -> medium) {
+ ip -> client -> medium =
+ ip -> client -> medium -> next;
+ increase = 0;
+ }
+ if (!ip -> client -> medium) {
+ if (fail)
+ error ("No valid media types for %s!",
+ ip -> name);
+ ip -> client -> medium =
+ ip -> 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)) {
+ goto again;
+ }
+ }
+
+ /* If we're supposed to increase the interval, do so. If it's
+ currently zero (i.e., we haven't sent any packets yet), set
+ it to one; otherwise, add to it a random number between
+ 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));
+ }
+
+ /* 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));
+ } else if (!ip -> client -> interval)
+ ip -> client -> interval =
+ ip -> 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;
+
+ /* Record the number of seconds since we started sending. */
+ if (interval < 255)
+ ip -> client -> packet.secs = interval;
+ else
+ ip -> client -> packet.secs = 255;
+
+ note ("DHCPDISCOVER on %s to %s port %d interval %ld",
+ ip -> name,
+ inet_ntoa (sockaddr_broadcast.sin_addr),
+ ntohs (sockaddr_broadcast.sin_port), ip -> client -> interval);
+
+ /* 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);
+ if (result < 0)
+ warn ("send_packet: %m");
+
+ add_timeout (cur_time + ip -> client -> interval, send_discover, ip);
+}
+
+/* state_panic gets called if we haven't received any offers in a preset
+ amount of time. When this happens, we try to use existing leases that
+ haven't yet expired, and failing that, we call the client script and
+ hope it can do something. */
+
+void state_panic (ipp)
+ void *ipp;
+{
+ struct interface_info *ip = ipp;
+
+ struct client_lease *loop = ip -> client -> active;
+ struct client_lease *lp;
+
+ note ("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)
+ 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));
+ /* 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);
+
+ /* 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 there are no other leases, give up. */
+ if (!ip -> client -> leases) {
+ ip -> client -> leases = ip -> client -> active;
+ ip -> 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)
+ ;
+ lp -> next = ip -> 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;
+
+ /* 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)
+ break;
+ else if (!loop)
+ loop = ip -> 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);
+ go_daemon ();
+}
+
+void send_request (ipp)
+ void *ipp;
+{
+ struct interface_info *ip = ipp;
+
+ int result;
+ int interval;
+ struct sockaddr_in destination;
+ struct in_addr from;
+
+ /* Figure out how long it's been since we started transmitting. */
+ interval = cur_time - ip -> 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
+ DISCOVER an address... */
+ /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
+ means either that we're on a network with no DHCP server,
+ or that our server is down. In the latter case, assuming
+ that there is a backup DHCP server, DHCPDISCOVER will get
+ 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) {
+ cancel:
+ ip -> client -> state = S_INIT;
+ cancel_timeout (send_request, ip);
+ state_init (ip);
+ 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 the medium we chose won't fly, go to INIT state. */
+ if (script_go (ip))
+ goto cancel;
+
+ /* Record the medium. */
+ ip -> client -> medium = ip -> 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) {
+ /* 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);
+
+ ip -> client -> state = S_INIT;
+ state_init (ip);
+ return;
+ }
+
+ /* Do the exponential backoff... */
+ if (!ip -> client -> interval)
+ ip -> client -> interval =
+ ip -> client -> config -> initial_interval;
+ else {
+ ip -> client -> interval +=
+ ((random () >> 2) %
+ (2 * ip -> 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 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 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 ||
+ cur_time > ip -> client -> active -> rebind)
+ destination.sin_addr.s_addr = INADDR_BROADCAST;
+ else
+ memcpy (&destination.sin_addr.s_addr,
+ ip -> 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
+
+ if (ip -> client -> state != S_REQUESTING)
+ memcpy (&from, ip -> client -> active -> address.iabuf,
+ sizeof from);
+ else
+ from.s_addr = INADDR_ANY;
+
+ /* Record the number of seconds since we started sending. */
+ if (interval < 255)
+ ip -> client -> packet.secs = interval;
+ else
+ ip -> client -> packet.secs = 255;
+
+ note ("DHCPREQUEST on %s to %s port %d", ip -> name,
+ inet_ntoa (destination.sin_addr),
+ ntohs (destination.sin_port));
+
+#ifdef USE_FALLBACK
+ if (destination.sin_addr.s_addr != INADDR_BROADCAST)
+ result = send_fallback (&fallback_interface,
+ (struct packet *)0,
+ &ip -> client -> packet,
+ ip -> client -> packet_length,
+ from, &destination,
+ (struct hardware *)0);
+ else
+#endif /* USE_FALLBACK */
+ /* Send out a packet. */
+ result = send_packet (ip, (struct packet *)0,
+ &ip -> client -> packet,
+ ip -> client -> packet_length,
+ from, &destination,
+ (struct hardware *)0);
+
+ if (result < 0)
+ warn ("send_packet: %m");
+
+ add_timeout (cur_time + ip -> client -> interval,
+ send_request, ip);
+}
+
+void send_decline (ipp)
+ void *ipp;
+{
+ struct interface_info *ip = ipp;
+
+ int result;
+
+ note ("DHCPDECLINE on %s to %s port %d", ip -> 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,
+ inaddr_any, &sockaddr_broadcast,
+ (struct hardware *)0);
+ if (result < 0)
+ warn ("send_packet: %m");
+}
+
+void send_release (ipp)
+ void *ipp;
+{
+ struct interface_info *ip = ipp;
+
+ int result;
+
+ note ("DHCPRELEASE on %s to %s port %d", ip -> 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,
+ inaddr_any, &sockaddr_broadcast,
+ (struct hardware *)0);
+ if (result < 0)
+ warn ("send_packet: %m");
+}
+
+void make_discover (ip, lease)
+ struct interface_info *ip;
+ struct client_lease *lease;
+{
+ struct dhcp_packet *raw;
+ 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;
+ } 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;
+ }
+ }
+
+ /* Set up the option buffer... */
+ ip -> client -> packet_length =
+ cons_options ((struct packet *)0, &ip -> client -> packet,
+ options, 0, 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. */
+ ip -> client -> packet.flags = htons (BOOTP_BROADCAST); /* XXX */
+ 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);
+
+#ifdef DEBUG_PACKET
+ dump_packet (sendpkt);
+ dump_raw ((unsigned char *)ip -> client -> packet,
+ sendpkt->packet_length);
+#endif
+}
+
+
+void make_request (ip, lease)
+ struct interface_info *ip;
+ struct client_lease *lease;
+{
+ unsigned char request = DHCPREQUEST;
+ int i;
+
+ 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;
+ }
+ }
+
+ /* Set up the option buffer... */
+ ip -> client -> packet_length =
+ cons_options ((struct packet *)0, &ip -> client -> packet,
+ options, 0, 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 = htons (BOOTP_BROADCAST);
+
+ /* 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,
+ lease -> address.iabuf, lease -> address.len);
+ else
+ 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);
+
+#ifdef DEBUG_PACKET
+ dump_packet (sendpkt);
+ dump_raw ((unsigned char *)ip -> client -> packet, sendpkt->packet_length);
+#endif
+}
+
+void make_decline (ip, lease)
+ struct interface_info *ip;
+ struct client_lease *lease;
+{
+ unsigned char decline = DHCPDECLINE;
+ int i;
+
+ 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;
+ }
+
+
+ /* Set up the option buffer... */
+ ip -> client -> packet_length =
+ cons_options ((struct packet *)0, &ip -> client -> packet,
+ options, 0, 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 = 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);
+
+#ifdef DEBUG_PACKET
+ dump_packet (sendpkt);
+ dump_raw ((unsigned char *)ip -> client -> packet, sendpkt->packet_length);
+#endif
+}
+
+void make_release (ip, lease)
+ struct interface_info *ip;
+ struct client_lease *lease;
+{
+ unsigned char request = DHCPRELEASE;
+ int i;
+
+ struct tree_cache *options [256];
+ struct tree_cache message_type_tree;
+ struct tree_cache requested_address_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;
+
+ /* Set up the option buffer... */
+ ip -> client -> packet_length =
+ cons_options ((struct packet *)0, &ip -> client -> packet,
+ options, 0, 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 -> packet.xid;
+ ip -> client -> packet.secs = 0;
+ ip -> client -> packet.flags = 0;
+ memcpy (&ip -> client -> packet.ciaddr,
+ lease -> address.iabuf, lease -> address.len);
+ 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);
+
+#ifdef DEBUG_PACKET
+ dump_packet (sendpkt);
+ dump_raw ((unsigned char *)ip -> client -> packet,
+ ip -> client -> packet_length);
+#endif
+}
+
+void free_client_lease (lease)
+ struct client_lease *lease;
+{
+ int i;
+
+ if (lease -> server_name)
+ free (lease -> server_name);
+ if (lease -> filename)
+ free (lease -> filename);
+ for (i = 0; i < 256; i++) {
+ if (lease -> options [i].len)
+ free (lease -> options [i].data);
+ }
+ free (lease);
+}
+
+FILE *leaseFile;
+
+void rewrite_client_leases ()
+{
+ struct interface_info *ip;
+ struct client_lease *lp;
+
+ if (leaseFile)
+ fclose (leaseFile);
+ leaseFile = fopen (path_dhclient_db, "w");
+ if (!leaseFile)
+ error ("can't create /var/db/dhclient.leases: %m");
+
+ /* 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);
+ }
+ if (ip -> client -> active)
+ write_client_lease (ip, ip -> client -> active);
+ }
+
+ /* 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);
+ }
+ if (ip -> client -> active)
+ write_client_lease (ip, ip -> client -> active);
+ }
+ fflush (leaseFile);
+}
+
+void write_client_lease (ip, lease)
+ struct interface_info *ip;
+ struct client_lease *lease;
+{
+ int i;
+ struct tm *t;
+
+ /* 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;
+
+ if (!leaseFile) { /* XXX */
+ leaseFile = fopen (path_dhclient_db, "w");
+ if (!leaseFile)
+ error ("can't create /var/db/dhclient.leases: %m");
+ }
+
+ fprintf (leaseFile, "lease {\n");
+ if (lease -> is_bootp)
+ fprintf (leaseFile, " bootp;\n");
+ fprintf (leaseFile, " interface \"%s\";\n", ip -> name);
+ 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 -> filename);
+ 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));
+ }
+ }
+ t = gmtime (&lease -> renewal);
+ fprintf (leaseFile,
+ " renew %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);
+ 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);
+ 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);
+ fprintf (leaseFile, "}\n");
+ fflush (leaseFile);
+}
+
+/* Variables holding name of script and file pointer for writing to
+ script. Needless to say, this is not reentrant - only one script
+ can be invoked at a time. */
+char scriptName [256];
+FILE *scriptFile;
+
+void script_init (ip, reason, medium)
+ struct interface_info *ip;
+ char *reason;
+ struct string_list *medium;
+{
+ int fd;
+#ifndef HAVE_MKSTEMP
+
+ do {
+#endif
+ strcpy (scriptName, "/tmp/dcsXXXXXX");
+#ifdef HAVE_MKSTEMP
+ fd = mkstemp (scriptName);
+#else
+ mktemp (scriptName);
+ fd = creat (scriptName, 0600);
+ } while (fd < 0);
+#endif
+
+ scriptFile = fdopen (fd, "w");
+ if (!scriptFile)
+ error ("can't write script file: %m");
+ fprintf (scriptFile, "#!/bin/sh\n\n");
+ if (ip) {
+ fprintf (scriptFile, "interface=\"%s\"\n", ip -> name);
+ fprintf (scriptFile, "export interface\n");
+ }
+ if (medium) {
+ fprintf (scriptFile, "medium=\"%s\"\n", medium -> string);
+ fprintf (scriptFile, "export medium\n");
+ }
+ fprintf (scriptFile, "reason=\"%s\"\n", reason);
+ fprintf (scriptFile, "export reason\n");
+}
+
+void script_write_params (ip, prefix, lease)
+ struct interface_info *ip;
+ char *prefix;
+ struct client_lease *lease;
+{
+ int i;
+ u_int8_t dbuf [1500];
+ int len;
+
+ fprintf (scriptFile, "%sip_address=\"%s\"\n",
+ prefix, piaddr (lease -> address));
+ fprintf (scriptFile, "export %sip_address\n", prefix);
+
+ /* For the benefit of Linux (and operating systems which may
+ have similar needs), compute the network address based on
+ the supplied ip address and netmask, if provided. Also
+ compute the broadcast address (the host address all ones
+ 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) {
+ fprintf (scriptFile, "%snetwork_number=\"%s\";\n",
+ prefix, piaddr (subnet));
+ fprintf (scriptFile, "export %snetwork_number\n",
+ prefix);
+
+ if (!lease -> options [DHO_BROADCAST_ADDRESS].len) {
+ broadcast = broadcast_addr (subnet, netmask);
+ if (broadcast.len) {
+ fprintf (scriptFile,
+ "%s%s=\"%s\";\n", prefix,
+ "broadcast_address",
+ piaddr (broadcast));
+ fprintf (scriptFile,
+ "export %s%s\n", prefix,
+ "broadcast_address");
+ }
+ }
+ }
+ }
+
+ if (lease -> filename) {
+ fprintf (scriptFile, "%sfilename=\"%s\";\n",
+ prefix, lease -> filename);
+ fprintf (scriptFile, "export %sfilename\n", prefix);
+ }
+ if (lease -> server_name) {
+ fprintf (scriptFile, "%sserver_name=\"%s\";\n",
+ prefix, lease -> server_name);
+ fprintf (scriptFile, "export %sserver_name\n", prefix);
+ }
+ 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",
+ "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);
+ }
+ } 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 *s = dhcp_option_ev_name (&dhcp_options [i]);
+
+ fprintf (scriptFile, "%s%s=\"%s\"\n", prefix, s,
+ pretty_print_option (i, dp, len, 0, 0));
+ fprintf (scriptFile, "export %s%s\n", prefix, s);
+ }
+ }
+ fprintf (scriptFile, "%sexpiry=\"%d\"\n",
+ prefix, (int)lease -> expiry); /* XXX */
+ fprintf (scriptFile, "export %sexpiry\n", prefix);
+}
+
+int script_go (ip)
+ struct interface_info *ip;
+{
+ int rval;
+
+ if (ip)
+ fprintf (scriptFile, "%s\n",
+ ip -> client -> config -> script_name);
+ else
+ fprintf (scriptFile, "%s\n",
+ top_level_config.script_name);
+ fprintf (scriptFile, "exit $?\n");
+ fclose (scriptFile);
+ chmod (scriptName, 0700);
+ rval = system (scriptName);
+ if (!save_scripts)
+ unlink (scriptName);
+ return rval;
+}
+
+char *dhcp_option_ev_name (option)
+ struct option *option;
+{
+ static char evbuf [256];
+ int i;
+
+ if (strlen (option -> name) + 1 > sizeof evbuf)
+ error ("option %s name is larger than static buffer.");
+ for (i = 0; option -> name [i]; i++) {
+ if (option -> name [i] == '-')
+ evbuf [i] = '_';
+ else
+ evbuf [i] = option -> name [i];
+ }
+
+ evbuf [i] = 0;
+ return evbuf;
+}
+
+void go_daemon ()
+{
+ static int state = 0;
+ int pid;
+
+ /* Don't become a daemon if the user requested otherwise. */
+ if (no_daemon) {
+ write_client_pid_file ();
+ return;
+ }
+
+ /* Only do it once. */
+ if (state)
+ return;
+ state = 1;
+
+ /* Stop logging to stderr... */
+ log_perror = 0;
+
+ /* Become a daemon... */
+ if ((pid = fork ()) < 0)
+ error ("Can't fork daemon: %m");
+ else if (pid)
+ exit (0);
+ /* Become session leader and get pid... */
+ pid = setsid ();
+
+ write_client_pid_file ();
+}
+
+void write_client_pid_file ()
+{
+ FILE *pf;
+ int pfdesc;
+
+ pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY, 0644);
+
+ if (pfdesc < 0) {
+ warn ("Can't create %s: %m", path_dhclient_pid);
+ return;
+ }
+
+ pf = fdopen (pfdesc, "w");
+ if (!pf)
+ warn ("Can't fdopen %s: %m", path_dhclient_pid);
+ else {
+ fprintf (pf, "%ld\n", (long)getpid ());
+ fclose (pf);
+ }
+}
diff --git a/contrib/isc-dhcp/client/dhclient.conf b/contrib/isc-dhcp/client/dhclient.conf
new file mode 100644
index 000000000000..147e0045a5d8
--- /dev/null
+++ b/contrib/isc-dhcp/client/dhclient.conf
@@ -0,0 +1,36 @@
+send host-name "andare.fugue.com";
+send dhcp-client-identifier 1:0:a0:24:ab:fb:9c;
+send dhcp-lease-time 3600;
+supersede domain-name "fugue.com home.vix.com";
+prepend domain-name-servers 127.0.0.1;
+request subnet-mask, broadcast-address, time-offset, routers,
+ domain-name, domain-name-servers, host-name;
+require subnet-mask, domain-name-servers;
+timeout 60;
+retry 60;
+reboot 10;
+select-timeout 5;
+initial-interval 2;
+script "/etc/dhclient-script";
+media "-link0 -link1 -link2", "link0 link1";
+reject 192.33.137.209;
+
+alias {
+ interface "ep0";
+ fixed-address 192.5.5.213;
+ option subnet-mask 255.255.255.255;
+}
+
+lease {
+ interface "ep0";
+ fixed-address 192.33.137.200;
+ medium "link0 link1";
+ option host-name "andare.swiftmedia.com";
+ option subnet-mask 255.255.255.0;
+ option broadcast-address 192.33.137.255;
+ option routers 192.33.137.250;
+ option domain-name-servers 127.0.0.1;
+ renew 2 2000/1/12 00:00:01;
+ rebind 2 2000/1/12 00:00:01;
+ expire 2 2000/1/12 00:00:01;
+}
diff --git a/contrib/isc-dhcp/client/dhclient.conf.5 b/contrib/isc-dhcp/client/dhclient.conf.5
new file mode 100644
index 000000000000..c5af648cf912
--- /dev/null
+++ b/contrib/isc-dhcp/client/dhclient.conf.5
@@ -0,0 +1,543 @@
+.\" dhclient.conf.5
+.\"
+.\" Copyright (c) 1997 The 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
+.\" are met:
+.\"
+.\" 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 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''.
+.TH dhclient.conf 5
+.SH NAME
+dhclient.conf - DHCP client configuration file
+.SH DESCRIPTION
+The dhclient.conf file contains configuration information for
+.IR dhclient,
+the Internet Software Consortium DHCP Client.
+.PP
+The dhclient.conf file is a free-form ASCII text file. It is parsed by
+the recursive-descent parser built into dhclient. The file may contain
+extra tabs and newlines for formatting purposes. Keywords in the file
+are case-insensitive. Comments may be placed anywhere within the
+file (except within quotes). Comments begin with the # character and
+end at the end of the line.
+.PP
+The dhclient.conf file can be used to configure the behaviour of the
+client in a wide variety of ways: protocol timing, information
+requested from the server, information required of the server,
+defaults to use if the server does not provide certain information,
+values with which to override information provided by the server, or
+values to prepend or append to information provided by the server.
+The configuration file can also be preinitialized with addresses to
+use on networks that don't have DHCP servers.
+.SH PROTOCOL TIMING
+The timing behaviour of the client need not be configured by the user.
+If no timing configuration is provided by the user, a fairly
+reasonable timing behaviour will be used by default - one which
+results in fairly timely updates without placing an inordinate load on
+the server.
+.PP
+The following statements can be used to adjust the timing behaviour of
+the DHCP client if required, however:
+.PP
+.I The
+.B timeout
+.I statement
+.PP
+.B timeout
+.I time
+.B ;
+.PP
+The
+.I timeout
+statement determines the amount of time that must pass between the
+time that the client begins to try to determine its address and the
+time that it decides that it's not going to be able to contact a
+server. By default, this timeout is sixty seconds. After the
+timeout has passed, if there are any static leases defined in the
+configuration file, or any leases remaining in the lease database that
+have not yet expired, the client will loop through these leases
+attempting to validate them, and if it finds one that appears to be
+valid, it will use that lease's address. If there are no valid
+static leases or unexpired leases in the lease database, the client
+will restart the protocol after the defined retry interval.
+.PP
+.I The
+.B retry
+.I statement
+.PP
+ \fBretry \fItime\fR\fB;\fR
+.PP
+The
+.I retry
+statement determines the time that must pass after the client has
+determined that there is no DHCP server present before it tries again
+to contact a DHCP server. By default, this is five minutes.
+.PP
+.I The
+.B select-timeout
+.I statement
+.PP
+ \fBselect-timeout \fItime\fR\fB;\fR
+.PP
+It is possible (some might say desirable) for there to be more than
+one DHCP server serving any given network. In this case, it is
+possible that a client may be sent more than one offer in response to
+its initial lease discovery message. It may be that one of these
+offers is preferable to the other (e.g., one offer may have the
+address the client previously used, and the other may not).
+.PP
+The
+.I select-timeout
+is the time after the client sends its first lease discovery request
+at which it stops waiting for offers from servers, assuming that it
+has received at least one such offer. If no offers have been
+received by the time the
+.I select-timeout
+has expired, the client will accept the first offer that arrives.
+.PP
+By default, the select-timeout is zero seconds - that is, the client
+will take the first offer it sees.
+.PP
+.I The
+.B reboot
+.I statement
+.PP
+ \fBreboot \fItime\fR\fB;\fR
+.PP
+When the client is restarted, it first tries to reacquire the last
+address it had. This is called the INIT-REBOOT state. If it is
+still attached to the same network it was attached to when it last
+ran, this is the quickest way to get started. The
+.I reboot
+statement sets the time that must elapse after the client first tries
+to reacquire its old address before it gives up and tries to discover
+a new address. By default, the reboot timeout is ten seconds.
+.PP
+.I The
+.B backoff-cutoff
+.I statement
+.PP
+ \fBbackoff-cutoff \fItime\fR\fB;\fR
+.PP
+The client uses an exponential backoff algorithm with some randomness,
+so that if many clients try to configure themselves at the same time,
+they will not make their requests in lockstep. The
+.I backoff-cutoff
+statement determines the maximum amount of time that the client is
+allowed to back off. It defaults to two minutes.
+.PP
+.I The
+.B initial-interval
+.I statement
+.PP
+ \fBinitial-interval \fItime\fR\fB;\fR
+.PP
+The
+.I initial-interval
+statement sets the amount of time between the first attempt to reach a
+server and the second attempt to reach a server. Each time a message
+is sent, the interval between messages is incremented by twice the
+current interval multiplied by a random number between zero and one.
+If it is greater than the backoff-cutoff amount, it is set to that
+amount. It defaults to ten seconds.
+.SH LEASE REQUIREMENTS AND REQUESTS
+The DHCP protocol allows the client to request that the server send it
+specific information, and not send it other information that it is not
+prepared to accept. The protocol also allows the client to reject
+offers from servers if they don't contain information the client
+needs, or if the information provided is not satisfactory.
+.PP
+There is a variety of data contained in offers that DHCP servers send
+to DHCP clients. The data that can be specifically requested is what
+are called \fIDHCP Options\fR. DHCP Options are defined in
+ \fBdhcp-options(5)\fR.
+.PP
+.I The
+.B request
+.I statement
+.PP
+ \fBrequest [ \fIoption\fR ] [\fB,\fI ... \fIoption\fR ]\fB;\fR
+.PP
+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.
+.PP
+.I The
+.B require
+.I statement
+.PP
+ \fBrequire [ \fIoption\fR ] [\fB,\fI ... \fIoption ]\fB;\fR
+.PP
+The require statement lists options that must be sent in order for an
+offer to be accepted. Offers that do not contain all the listed
+options will be ignored.
+.PP
+.I The
+.B send
+.I statement
+.PP
+ \fBsend { [ \fIoption declaration\fR ]
+[\fB,\fI ... \fIoption declaration\fR ]\fB}\fR
+.PP
+The send statement causes the client to send the specified options to
+the server with the specified values. These are full option
+declarations as described in \fBdhcp-options(5)\fR. Options that are
+always sent in the DHCP protocol should not be specified here, except
+that the client can specify a \fBrequested-lease-time\fR option other
+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 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
+information that it needs, and for which a useful default value
+exists. It may also receive information which is useful, but which
+needs to be supplemented with local information. To handle these
+needs, several option modifiers are available.
+.PP
+.I The
+.B default
+.I statement
+.PP
+ \fBdefault { [ \fIoption declaration\fR ]
+[\fB,\fI ... \fIoption declaration\fR ]\fB}\fR
+.PP
+If for some set of options 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
+statement.
+.PP
+.I The
+.B supersede
+.I statement
+.PP
+ \fBsupersede { [ \fIoption declaration\fR ]
+[\fB,\fI ... \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
+.B supersede
+statement.
+.PP
+.I The
+.B prepend
+.I statement
+.PP
+ \fBprepend { [ \fIoption declaration\fR ]
+[\fB,\fI ... \fIoption declaration\fR ]\fB}\fR
+.PP
+If for some set of options the client should first a value it
+supplies, and then use the values supplied by
+the server, if any, these values can be defined in the
+.B prepend
+statement. The
+.B prepend
+statement can only be used for options which
+allow more than one value to be given.
+.PP
+.I The
+.B append
+.I statement
+.PP
+ \fBappend { [ \fIoption declaration\fR ]
+[\fB,\fI ... \fIoption declaration\fR ]\fB}\fR
+.PP
+If for some set of options the client should first a value it
+supplies, and then use the values supplied by
+the server, if any, these values can be defined in the
+.B append
+statement. The
+.B append
+statement can only be used for options which
+allow more than one value to be given.
+.SH LEASE DECLARATIONS
+.PP
+.I The
+.B lease
+.I declaration
+.PP
+ \fBlease {\fR \fIlease-declaration\fR [ ... \fIlease-declaration ] \fB}\fR
+.PP
+The DHCP client may decide after some period of time (see \fBPROTOCOL
+TIMING\fR) decide that it is not going to succeed in contacting a
+server. At that time, it consults its own database of old leases and
+tests each one that has not yet timed out by pinging the listed router
+for that lease to see if that lease could work. It is possible to
+define one or more \fIfixed\fR leases in the client configuration file
+for networks where there is no DHCP or BOOTP service, so that the
+client can still automatically configure its address. This is done
+with the
+.B lease
+statement.
+.PP
+NOTE: the lease statement is also used in the dhclient.leases file in
+order to record leases that have been received from DHCP servers.
+Some of the syntax for leases as described below is only needed in the
+dhclient.leases file. Such syntax is documented here for
+completeness.
+.PP
+A lease statement consists of the lease keyword, followed by a left
+curly brace, followed by one or more lease declaration statements,
+followed by a right curly brace. The following lease declarations
+are possible:
+.PP
+ \fBbootp;\fR
+.PP
+The
+.B bootp
+statement is used to indicate that the lease was acquired using the
+BOOTP protocol rather than the DHCP protocol. It is never necessary
+to specify this in the client configuration file. The client uses
+this syntax in its lease database file.
+.PP
+ \fBinterface\fR \fB"\fR\fIstring\fR\fB";\fR
+.PP
+The
+.B interface
+lease statement is used to indicate the interface on which the lease
+is valid. If set, this lease will only be tried on a particular
+interface. When the client receives a lease from a server, it always
+records the interface number on which it received that lease.
+If predefined leases are specified in the dhclient.conf file, the
+interface should also be specified, although this is not required.
+.PP
+ \fBfixed-address\fR \fIip-address\fR\fB;\fR
+.PP
+The
+.B fixed-address
+statement is used to set the ip address of a particular lease. This
+is required for all lease statements. The IP address must be
+specified as a dotted quad (e.g., 12.34.56.78).
+.PP
+ \fBfilename "\fR\fIstring\fR\fB";\fR
+.PP
+The
+.B filename
+statement specifies the name of the boot filename to use. This is
+not used by the standard client configuration script, but is included
+for completeness.
+.PP
+ \fBserver-name "\fR\fIstring\fR\fB";\fR
+.PP
+The
+.B server-name
+statement specifies the name of the boot server name to use. This is
+also not used by the standard client configuration script.
+.PP
+ \fBoption\fR \fIoption-declaration\fR\fB;\fR
+.PP
+The
+.B option
+statement is used to specify the value of an option supplied by the
+server, or, in the case of predefined leases declared in
+dhclient.conf, the value that the user wishes the client configuration
+script to use if the predefined lease is used.
+.PP
+ \fBscript "\fIscript-name\fB";\fR
+.PP
+The
+.B script
+statement is used to specify the pathname of the dhcp client
+configuration script. This script is used by the dhcp client to set
+each interface's initial configuration prior to requesting an address,
+to test the address once it has been offered, and to set the
+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).
+.PP
+ \fBmedium "\fImedia setup\fB";\fR
+.PP
+The
+.B medium
+statement can be used on systems where network interfaces cannot
+automatically determine the type of network to which they are
+connected. The media setup string is a system-dependent parameter
+which is passed to the dhcp client configuration script when
+initializing the interface. On Unix and Unix-like systems, the
+argument is passed on the ifconfig command line when configuring te
+interface.
+.PP
+The dhcp client automatically declares this parameter if it used a
+media type (see the
+.B media
+statement) when configuring the interface in order to obtain a lease.
+This statement should be used in predefined leases only if the network
+interface requires media type configuration.
+.PP
+ \fBrenew\fR \fIdate\fB;\fR
+.PP
+ \fBrebind\fR \fIdate\fB;\fR
+.PP
+ \fBexpire\fR \fIdate\fB;\fR
+.PP
+The \fBrenew\fR statement defines the time at which the dhcp client
+should begin trying to contact its server to renew a lease that it is
+using. The \fBrebind\fR statement defines the time at which the dhcp
+client should begin to try to contact \fIany\fR dhcp server in order
+to renew its lease. The \fBexpire\fR statement defines the time at
+which the dhcp client must stop using a lease if it has not been able
+to contact a server in order to renew it.
+.PP
+These declarations are automatically set in leases acquired by the
+DHCP client, but must also be configured in predefined leases - a
+predefined lease whose expiry time has passed will not be used by the
+DHCP client.
+.PP
+Dates are specified as follows:
+.PP
+ \fI<weekday> <year>\fB/\fI<month>\fB/\fI<day>
+<hour>\fB:\fI<minute>\fB:\fI<second>\fR
+.PP
+The weekday is present to make it easy for a human to tell when a
+lease expires - it's specified as a number from zero to six, with zero
+being Sunday. When declaring a predefined lease, it can always be
+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.
+.SH ALIAS DECLARATIONS
+ \fBalias { \fI declarations ... \fB}\fR
+.PP
+Some DHCP clients running TCP/IP roaming protocols may require that in
+addition to the lease they may acquire via DHCP, their interface also
+be configured with a predefined IP alias so that they can have a
+permanent IP address even while roaming. The Internet Software
+Consortium DHCP client doesn't support roaming with fixed addresses
+directly, but in order to facilitate such experimentation, the dhcp
+client can be set up to configure an IP alias using the
+.B alias
+declaration.
+.PP
+The alias declaration resembles a lease declaration, except that
+options other than the subnet-mask option are ignored by the standard
+client configuration script, and expiry times are ignored. A typical
+alias declaration includes an interface declaration, a fixed-address
+declaration for the IP alias address, and a subnet-mask option
+declaration. A medium statement should never be included in an alias
+declaration.
+.SH OTHER DECLARATIONS
+ \fBreject \fIip-address\fB;\fR
+.PP
+The reject statement causes the DHCP client to reject offers from
+servers who use the specified address as a server identifier. This
+can be used to avoid being configured by rogue or misconfigured dhcp
+servers, although it should be a last resort - better to track down
+the bad DHCP server and fix it.
+.PP
+ \fBinterface "\fIname\fB" { \fIdeclarations ... \fB }
+.PP
+A client with more than one network interface may require different
+behaviour depending on which interface is being configured. All
+timing parameters and declarations other than lease and alias
+declarations can be enclosed in an interface declaration, and those
+parameters will then be used only for the interface that matches the
+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
+ \fBmedia "\fImedia setup\fB"\fI [ \fB, "\fImedia setup\fB", \fI... ]\fB;\fR
+.PP
+The
+.B media
+statement defines one or more media configuration parameters which may
+be tried while attempting to acquire an IP address. The dhcp client
+will cycle through each media setup string on the list, configuring
+the interface using that setup and attempting to boot, and then trying
+the next one. This can be used for network interfaces which aren't
+capable of sensing the media type unaided - whichever media type
+succeeds in getting a request to the server and hearing the reply is
+probably right (no guarantees).
+.PP
+The media setup is only used for the initial phase of address
+acquisition (the DHCPDISCOVER and DHCPOFFER packtes). Once an
+address has been acquired, the dhcp client will record it in its lease
+database and will record the media type used to acquire the address.
+Whenever the client tries to renew the lease, it will use that same
+media type. The lease must expire before the client will go back to
+cycling through media types.
+.SH SAMPLE
+The following configuration file is used on a laptop running NetBSD
+1.3. The laptop has an IP alias of 192.5.5.213, and has one
+interface, ep0 (a 3com 3C589C). Booting intervals have been
+shortened somewhat from the default, because the client is known to
+spend most of its time on networks with little DHCP activity. The
+laptop does roam to multiple networks.
+
+.nf
+
+timeout 60;
+retry 60;
+reboot 10;
+select-timeout 5;
+initial-interval 2;
+reject 192.33.137.209;
+
+interface "ep0" {
+ send host-name "andare.fugue.com";
+ send dhcp-client-identifier 1:0:a0:24:ab:fb:9c;
+ send dhcp-lease-time 3600;
+ supersede domain-name "fugue.com rc.vix.com home.vix.com";
+ prepend domain-name-servers 127.0.0.1;
+ request subnet-mask, broadcast-address, time-offset, routers,
+ domain-name, domain-name-servers, host-name;
+ require subnet-mask, domain-name-servers;
+ script "/etc/dhclient-script";
+ media "media 10baseT/UTP", "media 10base2/BNC";
+}
+
+alias {
+ interface "ep0";
+ fixed-address 192.5.5.213;
+ option subnet-mask 255.255.255.255;
+}
+.fi
+This is a very complicated dhclient.conf file - in general, yours
+should be much simpler. In many cases, it's sufficient to just
+create an empty dhclient.conf file - the defaults are usually fine.
+.SH SEE ALSO
+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>
+under a contract with Vixie Labs. Funding
+for this project was provided by the Internet Software Corporation.
+Information about the Internet Software Consortium can be found at
+.B http://www.isc.org/isc.
diff --git a/contrib/isc-dhcp/client/dhclient.leases.5 b/contrib/isc-dhcp/client/dhclient.leases.5
new file mode 100644
index 000000000000..e0da360524a8
--- /dev/null
+++ b/contrib/isc-dhcp/client/dhclient.leases.5
@@ -0,0 +1,62 @@
+.\" dhclient.conf.5
+.\"
+.\" Copyright (c) 1997 The 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
+.\" are met:
+.\"
+.\" 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 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''.
+.TH dhclient.leases 5
+.SH NAME
+dhclient.leases - DHCP client lease database
+.SH DESCRIPTION
+The Internet Software Consortium DHCP client keeps a persistent
+database of leases that it has acquired that are still valid. The
+database is a free-form ASCII file containing one valid declaration
+per lease. If more than one declaration appears for a given lease,
+the last one in the file is used. The file is written as a log, so
+this is not an unusual occurrance.
+.PP
+The format of the lease declarations is described in
+.B dhclient.conf(5).
+.SH FILES
+.B DBDIR/dhclient.leases
+.SH SEE ALSO
+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>
+under a contract with Vixie Labs. Funding
+for this project was provided by the Internet Software Corporation.
+Information about the Internet Software Consortium can be found at
+.B http://www.isc.org/isc.
diff --git a/contrib/isc-dhcp/client/scripts/freebsd b/contrib/isc-dhcp/client/scripts/freebsd
new file mode 100755
index 000000000000..7236a67a9a9a
--- /dev/null
+++ b/contrib/isc-dhcp/client/scripts/freebsd
@@ -0,0 +1,174 @@
+#!/bin/sh
+
+if [ x$new_network_number != x ]; then
+ echo New Network Number: $new_network_number
+fi
+
+if [ x$new_broadcast_address != x ]; then
+ echo New Broadcast Address: $new_broadcast_address
+ new_broadcast_arg="broadcast $new_broadcast_address"
+fi
+if [ x$old_broadcast_address != x ]; then
+ old_broadcast_arg="broadcast $old_broadcast_address"
+fi
+if [ x$new_subnet_mask != x ]; then
+ new_netmask_arg="netmask $new_subnet_mask"
+fi
+if [ x$old_subnet_mask != x ]; then
+ old_netmask_arg="netmask $old_subnet_mask"
+fi
+if [ x$alias_subnet_mask != x ]; then
+ alias_subnet_arg="netmask $alias_subnet_mask"
+fi
+
+if [ x$reason = xMEDIUM ]; then
+ ifconfig $interface $medium
+ ifconfig $interface inet -alias 0.0.0.0 $medium >/dev/null 2>&1
+ sleep 1
+ exit 0
+fi
+
+if [ x$reason = xPREINIT ]; 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
+ ifconfig $interface inet 0.0.0.0 netmask 0.0.0.0 \
+ broadcast 255.255.255.255 up
+ exit 0
+fi
+
+if [ x$reason = xARPCHECK ] || [ x$reason = xARPSEND ]; then
+ exit 0;
+fi
+
+if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \
+ [ x$reason = xREBIND ] || [ x$reason = xREBOOT ]; then
+ 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
+ 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
+ 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
+ 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
+ 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
+ while [ $# -gt 1 ]; do
+ route add $1 $2
+ shift; shift
+ done
+ fi
+ fi
+ if [ x$new_ip_address != x$alias_ip_address ] && [ x$alias_ip_address != x ];
+ then
+ 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
+ exit 0
+fi
+
+if [ x$reason = xEXPIRE ] || [ x$reason = xFAIL ]; 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
+ 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
+ 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 >/dev/null 2>&1
+ fi
+ if [ x$alias_ip_address != x ]; then
+ ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg
+ route add $alias_ip_address 127.0.0.1
+ fi
+ exit 0
+fi
+
+if [ x$reason = xTIMEOUT ]; 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
+ ifconfig $interface inet $new_ip_address $new_netmask_arg \
+ $new_broadcast_arg $medium
+ sleep 1
+ if [ "$new_routers" != "" ]; then
+ set $new_routers
+ if ping -q -c 1 -w 1 $1; then
+ if [ x$new_ip_address != x$alias_ip_address ] && \
+ [ x$alias_ip_address != x ]; then
+ ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg
+ route add $alias_ip_address 127.0.0.1
+ 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
+ set $new_static_routes
+ while [ $# -gt 1 ]; do
+ route add $0 $1
+ 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
+ exit 0
+ fi
+ 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
+ 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 >/dev/null 2>&1
+ exit 1
+fi
+
+exit 0