/* 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 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.17 1996/08/27 09:43:01 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]; struct iaddr server_identifier; int server_identifier_matched; #ifdef USE_FALLBACK struct interface_info fallback_interface; #endif u_int16_t server_port; int log_priority; int lexline, lexchar; char *tlname; static void usage PROTO ((void)); int main (argc, argv, envp) int argc; char **argv, **envp; { struct in_addr addr; 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 (); 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 ]"); } 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); 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); 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"); }