NetBSD/usr.sbin/dhcpd/dhclient.c

403 lines
11 KiB
C

/* dhcp.c
DHCP Client (really lame DHCP client). */
/*
* Copyright (c) 1995, 1996 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: dhclient.c,v 1.1.1.1 1996/10/03 06:33:25 mrg 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];
struct iaddr server_identifier;
int server_identifier_matched;
int log_perror = 1;
#ifdef USE_FALLBACK
struct interface_info fallback_interface;
#endif
u_int16_t server_port;
int log_priority;
int lexline, lexchar;
char *tlname, *token_line;
static void usage PROTO ((void));
int main (argc, argv, envp)
int argc;
char **argv, **envp;
{
int i;
struct servent *ent;
struct interface_info *interface;
#ifdef SYSLOG_4_2
openlog ("dhclient", LOG_NDELAY);
log_priority = LOG_DAEMON;
#else
openlog ("dhclient", LOG_NDELAY, LOG_DAEMON);
#endif
#ifndef NO_PUTENV
/* ensure mktime() calls are processed in UTC */
putenv("TZ=GMT0");
#endif /* !NO_PUTENV */
#if !(defined (DEBUG) || defined (SYSLOG_4_2))
setlogmask (LOG_UPTO (LOG_INFO));
#endif
for (i = 1; i < argc; i++) {
if (!strcmp (argv [i], "-p")) {
if (++i == argc)
usage ();
server_port = htons (atoi (argv [i]));
debug ("binding to user-specified port %d",
ntohs (server_port));
} else
usage ();
}
/* Default to the DHCP/BOOTP port. */
if (!server_port)
{
ent = getservbyname ("dhcpc", "udp");
if (!ent)
server_port = htons (68);
else
server_port = ent -> s_port;
endservent ();
}
/* Get the current time... */
GET_TIME (&cur_time);
/* Discover all the network interfaces and initialize them. */
discover_interfaces (0);
for (interface = interfaces; interface; interface = interface -> next)
send_discover (interface);
/* Receive packets and dispatch them... */
dispatch ();
/* Not reached */
return 0;
}
static void usage ()
{
error ("Usage: dhclient [-p <port>]");
}
void cleanup ()
{
}
int commit_leases ()
{
return 0;
}
int write_lease (lease)
struct lease *lease;
{
return 0;
}
void db_startup ()
{
}
void bootp (packet)
struct packet *packet;
{
note ("BOOTREPLY from %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr));
}
void dhcp (packet)
struct packet *packet;
{
switch (packet -> packet_type) {
case DHCPOFFER:
dhcpoffer (packet);
break;
case DHCPNAK:
dhcpnak (packet);
break;
case DHCPACK:
dhcpack (packet);
break;
default:
break;
}
}
void dhcpoffer (packet)
struct packet *packet;
{
note ("DHCPOFFER from %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr));
dump_packet (packet);
send_request (packet);
}
void dhcpack (packet)
struct packet *packet;
{
note ("DHCPACK from %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr));
dump_packet (packet);
}
void dhcpnak (packet)
struct packet *packet;
{
note ("DHCPNAK from %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr));
}
static u_int8_t requested_options [] = {
DHO_DHCP_REQUESTED_ADDRESS,
DHO_SUBNET_MASK,
DHO_ROUTERS,
DHO_DOMAIN_NAME_SERVERS,
DHO_HOST_NAME,
DHO_DOMAIN_NAME,
DHO_BROADCAST_ADDRESS };
void send_discover (interface)
struct interface_info *interface;
{
struct sockaddr_in to;
int result;
struct dhcp_packet raw;
unsigned char discover = DHCPDISCOVER;
struct packet outgoing;
struct tree_cache *options [256];
struct tree_cache dhcpdiscover_tree;
struct tree_cache dhcprqo_tree;
memset (options, 0, sizeof options);
memset (&outgoing, 0, sizeof outgoing);
memset (&raw, 0, sizeof raw);
outgoing.raw = &raw;
/* Set DHCP_MESSAGE_TYPE to DHCPNAK */
options [DHO_DHCP_MESSAGE_TYPE] = &dhcpdiscover_tree;
options [DHO_DHCP_MESSAGE_TYPE] -> value = &discover;
options [DHO_DHCP_MESSAGE_TYPE] -> len = sizeof discover;
options [DHO_DHCP_MESSAGE_TYPE] -> buf_size = sizeof discover;
options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF;
options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0;
/* Set DHCP_MESSAGE to whatever the message is */
options [DHO_DHCP_MESSAGE] = &dhcprqo_tree;
options [DHO_DHCP_MESSAGE] -> value = requested_options;
options [DHO_DHCP_MESSAGE] -> len = sizeof requested_options;
options [DHO_DHCP_MESSAGE] -> buf_size = sizeof requested_options;
options [DHO_DHCP_MESSAGE] -> timeout = 0xFFFFFFFF;
options [DHO_DHCP_MESSAGE] -> tree = (struct tree *)0;
/* Set up the option buffer... */
cons_options ((struct packet *)0, &outgoing, options, 0, 0);
memset (&raw.ciaddr, 0, sizeof raw.ciaddr);
memset (&raw.siaddr, 0, sizeof raw.siaddr);
memset (&raw.giaddr, 0, sizeof raw.giaddr);
memcpy (raw.chaddr,
interface -> hw_address.haddr, interface -> hw_address.hlen);
raw.hlen = interface -> hw_address.hlen;
raw.htype = interface -> hw_address.htype;
raw.xid = random ();
raw.secs = 1;
raw.flags = htons (BOOTP_BROADCAST);
raw.hops = 0;
raw.op = BOOTREQUEST;
/* Report what we're sending... */
note ("DHCPDISCOVER to %s", interface -> name);
#ifdef DEBUG_PACKET
dump_packet (&outgoing);
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
#endif
/* Set up the common stuff... */
to.sin_family = AF_INET;
#ifdef HAVE_SA_LEN
to.sin_len = sizeof to;
#endif
memset (to.sin_zero, 0, sizeof to.sin_zero);
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
to.sin_port = htons (ntohs (server_port) - 1); /* XXX */
errno = 0;
result = send_packet (interface, (struct packet *)0,
&raw, outgoing.packet_length,
raw.siaddr, &to, (struct hardware *)0);
if (result < 0)
warn ("send_packet: %m");
}
void send_request (packet)
struct packet *packet;
{
struct sockaddr_in to;
int result;
struct dhcp_packet raw;
unsigned char request = DHCPREQUEST;
struct packet outgoing;
struct tree_cache *options [256];
struct tree_cache dhcprequest_tree;
struct tree_cache dhcprqo_tree;
struct tree_cache dhcprqa_tree;
struct tree_cache dhcpsid_tree;
memset (options, 0, sizeof options);
memset (&outgoing, 0, sizeof outgoing);
memset (&raw, 0, sizeof raw);
outgoing.raw = &raw;
/* Set DHCP_MESSAGE_TYPE to DHCPNAK */
options [DHO_DHCP_MESSAGE_TYPE] = &dhcprequest_tree;
options [DHO_DHCP_MESSAGE_TYPE] -> value = &request;
options [DHO_DHCP_MESSAGE_TYPE] -> len = sizeof request;
options [DHO_DHCP_MESSAGE_TYPE] -> buf_size = sizeof request;
options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF;
options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0;
/* Set DHCP_MESSAGE to whatever the message is */
options [DHO_DHCP_MESSAGE] = &dhcprqo_tree;
options [DHO_DHCP_MESSAGE] -> value = requested_options;
options [DHO_DHCP_MESSAGE] -> len = sizeof requested_options;
options [DHO_DHCP_MESSAGE] -> buf_size = sizeof requested_options;
options [DHO_DHCP_MESSAGE] -> timeout = 0xFFFFFFFF;
options [DHO_DHCP_MESSAGE] -> tree = (struct tree *)0;
/* Request the address we were offered... */
options [DHO_DHCP_REQUESTED_ADDRESS] = &dhcprqa_tree;
options [DHO_DHCP_REQUESTED_ADDRESS] -> value =
(unsigned char *)&packet -> raw -> yiaddr;
options [DHO_DHCP_REQUESTED_ADDRESS] -> len = 4;
options [DHO_DHCP_REQUESTED_ADDRESS] -> buf_size = 4;
options [DHO_DHCP_REQUESTED_ADDRESS] -> timeout = 0xFFFFFFFF;
options [DHO_DHCP_REQUESTED_ADDRESS] -> tree = (struct tree *)0;
/* Send back the server identifier... */
options [DHO_DHCP_SERVER_IDENTIFIER] = &dhcpsid_tree;
options [DHO_DHCP_SERVER_IDENTIFIER] -> value =
packet -> options [DHO_DHCP_SERVER_IDENTIFIER].data;
options [DHO_DHCP_SERVER_IDENTIFIER] -> len =
packet -> options [DHO_DHCP_SERVER_IDENTIFIER].len;
options [DHO_DHCP_SERVER_IDENTIFIER] -> buf_size =
packet -> options [DHO_DHCP_SERVER_IDENTIFIER].len;
options [DHO_DHCP_SERVER_IDENTIFIER] -> timeout = 0xFFFFFFFF;
options [DHO_DHCP_SERVER_IDENTIFIER] -> tree = (struct tree *)0;
/* Set up the option buffer... */
cons_options ((struct packet *)0, &outgoing, options, 0, 0);
memset (&raw.ciaddr, 0, sizeof raw.ciaddr);
raw.siaddr = packet -> raw -> siaddr;
raw.giaddr = packet -> raw -> giaddr;
memcpy (raw.chaddr,
packet -> interface -> hw_address.haddr,
packet -> interface -> hw_address.hlen);
raw.hlen = packet -> interface -> hw_address.hlen;
raw.htype = packet -> interface -> hw_address.htype;
raw.xid = packet -> raw -> xid;
raw.secs = packet -> raw -> secs;
raw.flags = htons (BOOTP_BROADCAST);
raw.hops = packet -> raw -> hops;
raw.op = BOOTREQUEST;
/* Report what we're sending... */
note ("DHCPREQUEST to %s", packet -> interface -> name);
#ifdef DEBUG_PACKET
dump_packet (&outgoing);
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
#endif
/* Set up the common stuff... */
to.sin_family = AF_INET;
#ifdef HAVE_SA_LEN
to.sin_len = sizeof to;
#endif
memset (to.sin_zero, 0, sizeof to.sin_zero);
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
to.sin_port = htons (ntohs (server_port) - 1); /* XXX */
errno = 0;
result = send_packet (packet -> interface, (struct packet *)0,
&raw, outgoing.packet_length,
raw.siaddr, &to, (struct hardware *)0);
if (result < 0)
warn ("send_packet: %m");
}