📄 dhclient.c
字号:
/* $OpenBSD: dhclient.c,v 1.62 2004/12/05 18:35:51 deraadt Exp $ */
/*
* Copyright 2004 Henning Brauer <henning@openbsd.org>
* Copyright (c) 1995, 1996, 1997, 1998, 1999
* 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.
*/
#include "rosdhcp.h"
#include <winsock2.h>
#include "dhcpd.h"
#include "privsep.h"
#define PERIOD 0x2e
#define hyphenchar(c) ((c) == 0x2d)
#define bslashchar(c) ((c) == 0x5c)
#define periodchar(c) ((c) == PERIOD)
#define asterchar(c) ((c) == 0x2a)
#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
((c) >= 0x61 && (c) <= 0x7a))
#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
#define borderchar(c) (alphachar(c) || digitchar(c))
#define middlechar(c) (borderchar(c) || hyphenchar(c))
#define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
unsigned long debug_trace_level = 0; /* DEBUG_ULTRA */
time_t cur_time;
time_t default_lease_time = 43200; /* 12 hours... */
char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
char *path_dhclient_db = NULL;
int log_perror = 1;
int privfd;
//int nullfd = -1;
struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
struct in_addr inaddr_any;
struct sockaddr_in sockaddr_broadcast;
unsigned long old_default_route = 0;
/*
* ASSERT_STATE() does nothing now; it used to be
* assert (state_is == state_shouldbe).
*/
#define ASSERT_STATE(state_is, state_shouldbe) {}
#define TIME_MAX 2147483647
int log_priority;
int no_daemon;
int unknown_ok = 1;
int routefd;
struct interface_info *ifi = NULL;
void usage(void);
int check_option(struct client_lease *l, int option);
int ipv4addrs(char * buf);
int res_hnok(const char *dn);
char *option_as_string(unsigned int code, unsigned char *data, int len);
int fork_privchld(int, int);
int check_arp( struct interface_info *ip, struct client_lease *lp );
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
time_t scripttime;
/* XXX Added this since it's not in the NDK ;0/ */
ULONG
NTAPI
RtlRandom(
IN OUT PULONG Seed
);
/* XXX Implement me */
int check_arp( struct interface_info *ip, struct client_lease *lp ) {
return 1;
}
static VOID CALLBACK
DispatchMain(DWORD argc, LPTSTR *argv)
{
dispatch();
}
static SERVICE_TABLE_ENTRY ServiceTable[2] =
{
{TEXT("DHCP"), DispatchMain},
{NULL, NULL}
};
int
main(int argc, char *argv[])
{
int i = 0;
ApiInit();
AdapterInit();
PipeInit();
tzset();
time(&cur_time);
memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast));
sockaddr_broadcast.sin_family = AF_INET;
sockaddr_broadcast.sin_port = htons(REMOTE_PORT);
sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
inaddr_any.s_addr = INADDR_ANY;
DH_DbgPrint(MID_TRACE,("DHCP Service Started\n"));
read_client_conf();
if (!interface_link_status(ifi->name)) {
DH_DbgPrint(MID_TRACE,("%s: no link ", ifi->name));
Sleep(1000);
while (!interface_link_status(ifi->name)) {
DH_DbgPrint(MID_TRACE,("."));
if (++i > 10) {
DH_DbgPrint(MID_TRACE,("Giving up for now on adapter [%s]\n", ifi->name));
}
Sleep(1000);
}
DH_DbgPrint(MID_TRACE,("Got link on [%s]\n", ifi->name));
}
DH_DbgPrint(MID_TRACE,("Discover Interfaces\n"));
/* If no adapters were found, just idle for now ... If any show up,
* then we'll start it later */
if( ifi ) {
/* set up the interface */
discover_interfaces(ifi);
DH_DbgPrint
(MID_TRACE,
("Setting init state and restarting interface %p\n",ifi));
}
bootp_packet_handler = do_packet;
DH_DbgPrint(MID_TRACE,("Going into dispatch()\n"));
StartServiceCtrlDispatcher(ServiceTable);
/* not reached */
return (0);
}
void
usage(void)
{
// extern char *__progname;
// fprintf(stderr, "usage: %s [-dqu] ", __progname);
fprintf(stderr, "usage: dhclient [-dqu] ");
fprintf(stderr, "[-c conffile] [-l leasefile] interface\n");
exit(1);
}
/*
* 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(void *ipp)
{
struct interface_info *ip = ipp;
ULONG foo = (ULONG) GetTickCount();
/* 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_request doesn't initialize xid because it normally comes
from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
so pick an xid now. */
ip->client->xid = RtlRandom(&foo);
/* Make a DHCPREQUEST packet, and set appropriate per-interface
flags. */
make_request(ip, ip->client->active);
ip->client->destination = iaddr_broadcast;
ip->client->first_sending = cur_time;
ip->client->interval = ip->client->config->initial_interval;
/* Zap the medium list... */
ip->client->medium = NULL;
/* 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(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(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 = NULL;
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) {
if( !check_arp(ip,lp) ) goto freeit;
picked = lp;
picked->next = NULL;
} else {
freeit:
free_client_lease(lp);
}
}
ip->client->offered_leases = NULL;
/* 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(struct packet *packet)
{
struct interface_info *ip = packet->interface;
struct client_lease *lease;
/* If we're not receptive to an offer right now, or if the offer
has an unrecognizable transaction id, then just drop it. */
if (packet->interface->client->xid != packet->raw->xid ||
(packet->interface->hw_address.hlen != packet->raw->hlen) ||
(memcmp(packet->interface->hw_address.haddr,
packet->raw->chaddr, packet->raw->hlen)))
return;
if (ip->client->state != S_REBOOTING &&
ip->client->state != S_REQUESTING &&
ip->client->state != S_RENEWING &&
ip->client->state != S_REBINDING)
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. */
if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data)
ip->client->new->expiry = getULong(
ip->client->new->options[DHO_DHCP_LEASE_TIME].data);
else
ip->client->new->expiry = default_lease_time;
/* A number that looks negative here is really just very large,
because the lease expiry offset is unsigned. */
if (ip->client->new->expiry < 0)
ip->client->new->expiry = TIME_MAX;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -