📄 dhclient.c
字号:
if (!lease->server_name) {
warning("dhcpoffer: no memory for server name.");
free_client_lease(lease);
return (NULL);
}
memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
lease->server_name[DHCP_SNAME_LEN]='\0';
if (!res_hnok(lease->server_name) ) {
warning("Bogus server name %s", lease->server_name );
free_client_lease(lease);
return (NULL);
}
}
/* 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]) {
/* Don't count on the NUL terminator. */
lease->filename = malloc(DHCP_FILE_LEN + 1);
if (!lease->filename) {
warning("dhcpoffer: no memory for filename.");
free_client_lease(lease);
return (NULL);
}
memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
lease->filename[DHCP_FILE_LEN]='\0';
}
return lease;
}
void
dhcpnak(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 ||
(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("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 = NULL;
/* 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(void *ipp)
{
struct interface_info *ip = ipp;
int interval, increase = 1;
DH_DbgPrint(MID_TRACE,("Doing discover on interface %p\n",ip));
/* 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;
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);
/* XXX Support other media types eventually */
}
/*
* 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 += (rand() >> 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)
+ ((rand() >> 2) %
ip->client->config->backoff_cutoff));
} 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 < 65536)
ip->client->packet.secs = htons(interval);
else
ip->client->packet.secs = htons(65535);
ip->client->secs = ip->client->packet.secs;
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. */
(void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
inaddr_any, &sockaddr_broadcast, NULL);
DH_DbgPrint(MID_TRACE,("discover timeout: now %x -> then %x\n",
cur_time, cur_time + ip->client->interval));
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(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("TIMEOUT",
ip->client->active->medium);
script_write_params("new_", ip->client->active);
if (ip->client->alias)
script_write_params("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 (cur_time <
ip->client->active->renewal) {
ip->client->state = S_BOUND;
note("bound: renewal in %ld 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();
return;
}
/* If there are no other leases, give up. */
if (!ip->client->leases) {
ip->client->leases = ip->client->active;
ip->client->active = NULL;
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 = NULL;
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");
ip->client->state = S_INIT;
add_timeout(cur_time + ip->client->config->retry_interval, state_init,
ip);
/* XXX Take any failure actions necessary */
}
void
send_request(void *ipp)
{
struct interface_info *ip = ipp;
struct sockaddr_in destination;
struct in_addr from;
int interval;
/* 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) {
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("MEDIUM", ip->client->active->medium);
/* If the medium we chose won't fly, go to INIT state. */
/* XXX Nothing for now */
/* 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) {
PDHCP_ADAPTER Adapter = AdapterFindInfo( ip );
/* Run the client script with the new parameters. */
/* No script actions necessary in the expiry case */
/* Now do a preinit on the interface so that we can
discover a new address. */
if( Adapter )
DeleteIPAddress( Adapter->NteContext );
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 += ((rand() >> 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) +
((rand() >> 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. */
memset(&destination, 0, sizeof(destination));
if (ip->client->state == S_REQUESTING ||
ip->client->state == S_REBOOTING ||
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 = htons(REMOTE_PORT);
destination.sin_family = AF_INET;
// destination.sin_len = sizeof(destination);
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 (ip->client->state == S_REQUESTING)
ip->client->packet.secs = ip->client->secs;
else {
if (interval < 65536)
ip->client->packet.secs = htons(interval);
else
ip->client->packet.secs = htons(65535);
}
note("DHCPREQUEST on %s to %s port %d", ip->name,
inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
/* Send out a packet. */
(void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
from, &destination, NULL);
add_timeout(cur_time + ip->client->interval, send_request, ip);
}
void
send_decline(void *ipp)
{
struct interface_info *ip = ipp;
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. */
(void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
inaddr_any, &sockaddr_broadcast, NULL);
}
void
make_discover(struct interface_info *ip, struct client_lease *lease)
{
unsigned char discover = DHCPDISCOVER;
struct tree_cache *options[256];
struct tree_cache option_elements[256];
int i;
ULONG foo = (ULONG) GetTickCount();
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;
/* Request the options we want */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -