📄 dhclient.c
字号:
/* XXX should be fixed by resetting the client state */
if (ip->client->new->expiry < 60)
ip->client->new->expiry = 60;
/* 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;
#ifdef _REACTOS_
ip->client->new->obtained = cur_time;
#endif
ip->client->new->expiry += cur_time;
/* Lease lengths can never be negative. */
if (ip->client->new->expiry < cur_time)
ip->client->new->expiry = TIME_MAX;
ip->client->new->renewal += cur_time;
if (ip->client->new->renewal < cur_time)
ip->client->new->renewal = TIME_MAX;
ip->client->new->rebind += cur_time;
if (ip->client->new->rebind < cur_time)
ip->client->new->rebind = TIME_MAX;
bind_lease(ip);
}
void set_name_servers( struct client_lease *new_lease ) {
if( new_lease->options[DHO_DOMAIN_NAME_SERVERS].len ) {
HKEY RegKey;
struct iaddr nameserver;
char *nsbuf;
int i, addrs =
new_lease->options[DHO_DOMAIN_NAME_SERVERS].len / sizeof(ULONG);
/* XXX I'm setting addrs to 1 until we are ready up the chain */
addrs = 1;
nsbuf = malloc( addrs * sizeof(IP_ADDRESS_STRING) );
nsbuf[0] = 0;
if( nsbuf && !RegOpenKeyEx
( HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
0, KEY_WRITE, &RegKey ) ) {
for( i = 0; i < addrs; i++ ) {
nameserver.len = sizeof(ULONG);
memcpy( nameserver.iabuf,
new_lease->options[DHO_DOMAIN_NAME_SERVERS].data +
(i * sizeof(ULONG)), sizeof(ULONG) );
strcat( nsbuf, piaddr(nameserver) );
if( i != addrs-1 ) strcat( nsbuf, "," );
}
DH_DbgPrint(MID_TRACE,("Setting Nameservers: %s\n", nsbuf));
/* XXX Fixme: I think this may be wrong and that we might have
* a problem somewhere else (in iphlpapi for example).
*
* Recheck the +1 below.
*/
RegSetValueEx( RegKey, "NameServer", 0, REG_SZ,
(LPBYTE)nsbuf, strlen(nsbuf) + 1 );
free( nsbuf );
}
}
}
void setup_adapter( PDHCP_ADAPTER Adapter, struct client_lease *new_lease ) {
struct iaddr netmask;
if( Adapter->NteContext )
DeleteIPAddress( Adapter->NteContext );
/* Set up our default router if we got one from the DHCP server */
if( new_lease->options[DHO_SUBNET_MASK].len ) {
NTSTATUS Status;
memcpy( netmask.iabuf,
new_lease->options[DHO_SUBNET_MASK].data,
new_lease->options[DHO_SUBNET_MASK].len );
Status = AddIPAddress
( *((ULONG*)new_lease->address.iabuf),
*((ULONG*)netmask.iabuf),
Adapter->IfMib.dwIndex,
&Adapter->NteContext,
&Adapter->NteInstance );
if( !NT_SUCCESS(Status) )
warning("AddIPAddress: %lx\n", Status);
}
if( new_lease->options[DHO_ROUTERS].len ) {
MIB_IPFORWARDROW RouterMib;
NTSTATUS Status;
RouterMib.dwForwardDest = 0; /* Default route */
RouterMib.dwForwardMask = 0;
RouterMib.dwForwardMetric1 = 1;
if( old_default_route ) {
/* If we set a default route before, delete it before continuing */
RouterMib.dwForwardDest = old_default_route;
DeleteIpForwardEntry( &RouterMib );
}
RouterMib.dwForwardNextHop =
*((ULONG*)new_lease->options[DHO_ROUTERS].data);
Status = CreateIpForwardEntry( &RouterMib );
if( !NT_SUCCESS(Status) )
warning("CreateIpForwardEntry: %lx\n", Status);
else
old_default_route = RouterMib.dwForwardNextHop;
}
}
void
bind_lease(struct interface_info *ip)
{
PDHCP_ADAPTER Adapter;
struct client_lease *new_lease = ip->client->new;
/* Remember the medium. */
ip->client->new->medium = ip->client->medium;
ip->client->active = ip->client->new;
ip->client->new = NULL;
/* Set up a timeout to start the renewal process. */
/* Timeout of zero means no timeout (some implementations seem to use
* one day).
*/
if( ip->client->active->renewal - cur_time )
add_timeout(ip->client->active->renewal, state_bound, ip);
note("bound to %s -- renewal in %ld seconds.",
piaddr(ip->client->active->address),
ip->client->active->renewal - cur_time);
ip->client->state = S_BOUND;
Adapter = AdapterFindInfo( ip );
if( Adapter ) setup_adapter( Adapter, new_lease );
else warning("Could not find adapter for info %p\n", ip);
set_name_servers( new_lease );
reinitialize_interfaces();
}
/*
* 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(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);
}
void
bootp(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(struct packet *packet)
{
struct iaddrlist *ap;
void (*handler)(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(struct packet *packet)
{
struct interface_info *ip = packet->interface;
struct client_lease *lease, *lp;
int i;
int arp_timeout_needed = 0, stop_selecting;
char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
"DHCPOFFER" : "BOOTREPLY";
/* 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 ||
(packet->interface->hw_address.hlen != packet->raw->hlen) ||
(memcmp(packet->interface->hw_address.haddr,
packet->raw->chaddr, packet->raw->hlen)))
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. */
if( !check_arp( ip, lease ) ) {
note("Arp check failed\n");
return;
}
/* 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 = NULL;
if (!ip->client->offered_leases)
ip->client->offered_leases = lease;
else {
for (lp = ip->client->offered_leases; lp->next;
lp = lp->next)
; /* nothing */
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(struct packet *packet)
{
struct client_lease *lease;
int i;
lease = malloc(sizeof(struct client_lease));
if (!lease) {
warning("dhcpoffer: no memory to record lease.");
return (NULL);
}
memset(lease, 0, sizeof(*lease));
/* Copy the lease options. */
for (i = 0; i < 256; i++) {
if (packet->options[i].len) {
lease->options[i].data =
malloc(packet->options[i].len + 1);
if (!lease->options[i].data) {
warning("dhcpoffer: no memory for option %d", i);
free_client_lease(lease);
return (NULL);
} 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;
}
if (!check_option(lease,i)) {
/* ignore a bogus lease offer */
warning("Invalid lease option - ignoring offer");
free_client_lease(lease);
return (NULL);
}
}
}
lease->address.len = sizeof(packet->raw->yiaddr);
memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
#ifdef _REACTOS_
lease->serveraddress.len = sizeof(packet->raw->siaddr);
memcpy(lease->serveraddress.iabuf, &packet->raw->siaddr, lease->address.len);
#endif
/* 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]) {
lease->server_name = malloc(DHCP_SNAME_LEN + 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -