예제 #1
0
/* ARGSUSED */
void
dhcp_renew(iu_tq_t *tqp, void *arg)
{
	dhcp_lease_t *dlp = arg;
	dhcp_smach_t *dsmp = dlp->dl_smach;
	uint32_t	t2;

	dhcpmsg(MSG_VERBOSE, "dhcp_renew: T1 timer expired on %s",
	    dsmp->dsm_name);

	dlp->dl_t1.dt_id = -1;

	if (dsmp->dsm_state == RENEWING || dsmp->dsm_state == REBINDING) {
		dhcpmsg(MSG_DEBUG, "dhcp_renew: already renewing");
		release_lease(dlp);
		return;
	}

	/*
	 * Sanity check: don't send packets if we're past T2, or if we're
	 * extremely close.
	 */

	t2 = dsmp->dsm_curstart_monosec + dlp->dl_t2.dt_start;
	if (monosec() + TOO_CLOSE >= t2) {
		dhcpmsg(MSG_DEBUG, "dhcp_renew: %spast T2 on %s",
		    monosec() > t2 ? "" : "almost ", dsmp->dsm_name);
		release_lease(dlp);
		return;
	}

	/*
	 * If there isn't an async event pending, or if we can cancel the one
	 * that's there, then try to renew by sending an extension request.  If
	 * that fails, we'll try again when the next timer fires.
	 */
	if (!async_cancel(dsmp) || !async_start(dsmp, DHCP_EXTEND, B_FALSE) ||
	    !dhcp_extending(dsmp)) {
		if (monosec() + RETRY_DELAY < t2) {
			/*
			 * Try again in RETRY_DELAY seconds; user command
			 * should be gone.
			 */
			init_timer(&dlp->dl_t1, RETRY_DELAY);
			(void) set_smach_state(dsmp, BOUND);
			if (!schedule_lease_timer(dlp, &dlp->dl_t1,
			    dhcp_renew)) {
				dhcpmsg(MSG_INFO, "dhcp_renew: unable to "
				    "reschedule renewal around user command "
				    "on %s; will wait for rebind",
				    dsmp->dsm_name);
			}
		} else {
			dhcpmsg(MSG_DEBUG, "dhcp_renew: user busy on %s; will "
			    "wait for rebind", dsmp->dsm_name);
		}
	}
	release_lease(dlp);
}
예제 #2
0
파일: dhcpd.c 프로젝트: appleorange1/bitrig
void
periodic_scan(void *p)
{
	time_t x, y;
	struct subnet		*n;
	struct group		*g;
	struct shared_network	*s;
	struct lease		*l;

	/* find the shortest lease this server gives out */
	x = MIN(root_group.default_lease_time, root_group.max_lease_time);
	for (n = subnets; n; n = n->next_subnet)
		for (g = n->group; g; g = g->next)
			x = MIN(x, g->default_lease_time);

	/* use half of the shortest lease as the scan interval */
	y = x / 2;
	if (y < 1)
		y = 1;

	/* walk across all leases to find the exired ones */
	for (n = subnets; n; n = n->next_subnet)
		for (g = n->group; g; g = g->next)
			for (s = g->shared_network; s; s = s->next)
				for (l = s->leases; l && l->ends; l = l->next)
					if (cur_time >= l->ends){
						release_lease(l);
						pfmsg('R', l);
					}

	add_timeout(cur_time + y, periodic_scan, NULL);
}
예제 #3
0
파일: dhcpd.c 프로젝트: appleorange1/bitrig
void
lease_ping_timeout(void *vlp)
{
	struct lease	*lp = vlp;

	--outstanding_pings;
	if (lp->releasing) {
		lp->releasing = 0;
		release_lease(lp);
	} else
		dhcp_reply(lp);
}
예제 #4
0
파일: leases.c 프로젝트: hoangduit/reactos
int find_lease( DHCPLEASE *dhcpl, u32b xid, u8b chaddr[] )
{
  int result = -2;
  DHCPLIST *temp;

  if( !dhcpl )
    return -1;

  for( temp = list; temp; temp=temp->next )
    if( !maccmp( temp->chaddr, chaddr ) )
      release_lease( dhcpl, xid, chaddr);

  for( temp = list; temp; temp=temp->next )
    if( ( !maccmp( temp->chaddr, chaddr )) && ( temp->type == STATIC ))
      {
	dhcpl->ip = temp->data.ip;
	dhcpl->router = temp->data.router;
	dhcpl->mask = temp->data.mask;
	dhcpl->lease = temp->data.lease;
	dhcpl->siaddr = temp->data.siaddr;
	fprintf( stdout, "Assigning Static IP! \n");
	temp->available = PROCESSING;
	temp->xid = xid;
	temp->ltime = MAX_PROCESS_TIME;
	maccpy( temp->chaddr, chaddr);
	result = 0;
	return result;
      }
    else if( ( temp->available & FREE )  && ( temp->type == DYNAMIC ))
      {
	dhcpl->ip = temp->data.ip;
	dhcpl->router = temp->data.router;
	dhcpl->mask = temp->data.mask;
	dhcpl->lease = temp->data.lease;
	dhcpl->siaddr = temp->data.siaddr;
	fprintf( stdout, "Assigning Dynamic IP! \n");
	temp->available = PROCESSING;
	temp->xid = xid;
	temp->ltime = MAX_PROCESS_TIME;
	maccpy( temp->chaddr, chaddr);
	result = 0;
	return result;
      }
  return result;
}
예제 #5
0
/* ARGSUSED */
void
dhcp_rebind(iu_tq_t *tqp, void *arg)
{
	dhcp_lease_t	*dlp = arg;
	dhcp_smach_t	*dsmp = dlp->dl_smach;
	int		nlifs;
	dhcp_lif_t	*lif;
	boolean_t	some_valid;
	uint32_t	expiremax;
	DHCPSTATE	oldstate;

	dhcpmsg(MSG_VERBOSE, "dhcp_rebind: T2 timer expired on %s",
	    dsmp->dsm_name);

	dlp->dl_t2.dt_id = -1;

	if ((oldstate = dsmp->dsm_state) == REBINDING) {
		dhcpmsg(MSG_DEBUG, "dhcp_renew: already rebinding");
		release_lease(dlp);
		return;
	}

	/*
	 * Sanity check: don't send packets if we've already expired on all of
	 * the addresses.  We compute the maximum expiration time here, because
	 * it won't matter for v4 (there's only one lease) and for v6 we need
	 * to know when the last lease ages away.
	 */

	some_valid = B_FALSE;
	expiremax = monosec();
	lif = dlp->dl_lifs;
	for (nlifs = dlp->dl_nlifs; nlifs > 0; nlifs--, lif = lif->lif_next) {
		uint32_t expire;

		expire = dsmp->dsm_curstart_monosec + lif->lif_expire.dt_start;
		if (expire > expiremax) {
			expiremax = expire;
			some_valid = B_TRUE;
		}
	}
	if (!some_valid) {
		dhcpmsg(MSG_DEBUG, "dhcp_rebind: all leases expired on %s",
		    dsmp->dsm_name);
		release_lease(dlp);
		return;
	}

	/*
	 * This is our first venture into the REBINDING state, so reset the
	 * server address.  We know the renew timer has already been cancelled
	 * (or we wouldn't be here).
	 */
	if (dsmp->dsm_isv6) {
		dsmp->dsm_server = ipv6_all_dhcp_relay_and_servers;
	} else {
		IN6_IPADDR_TO_V4MAPPED(htonl(INADDR_BROADCAST),
		    &dsmp->dsm_server);
	}

	/* {Bound,Renew}->rebind transitions cannot fail */
	(void) set_smach_state(dsmp, REBINDING);

	/*
	 * If there isn't an async event pending, or if we can cancel the one
	 * that's there, then try to rebind by sending an extension request.
	 * If that fails, we'll clean up when the lease expires.
	 */
	if (!async_cancel(dsmp) || !async_start(dsmp, DHCP_EXTEND, B_FALSE) ||
	    !dhcp_extending(dsmp)) {
		if (monosec() + RETRY_DELAY < expiremax) {
			/*
			 * Try again in RETRY_DELAY seconds; user command
			 * should be gone.
			 */
			init_timer(&dlp->dl_t2, RETRY_DELAY);
			(void) set_smach_state(dsmp, oldstate);
			if (!schedule_lease_timer(dlp, &dlp->dl_t2,
			    dhcp_rebind)) {
				dhcpmsg(MSG_INFO, "dhcp_rebind: unable to "
				    "reschedule rebind around user command on "
				    "%s; lease may expire", dsmp->dsm_name);
			}
		} else {
			dhcpmsg(MSG_WARNING, "dhcp_rebind: user busy on %s; "
			    "will expire", dsmp->dsm_name);
		}
	}
	release_lease(dlp);
}
예제 #6
0
파일: bootp.c 프로젝트: appleorange1/bitrig
void
bootp(struct packet *packet)
{
	struct host_decl *hp, *host = NULL;
	struct packet outgoing;
	struct dhcp_packet raw;
	struct sockaddr_in to;
	struct in_addr from;
	struct tree_cache *options[256];
	struct subnet *subnet = NULL;
	struct lease *lease;
	struct iaddr ip_address;
	int i;

	if (packet->raw->op != BOOTREQUEST)
		return;

	note("BOOTREQUEST from %s via %s%s", print_hw_addr(packet->raw->htype,
	    packet->raw->hlen, packet->raw->chaddr),
	    packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) :
	    packet->interface->name,
	    packet->options_valid ? "" : " (non-rfc1048)");

	if (!locate_network(packet))
		return;

	hp = find_hosts_by_haddr(packet->raw->htype, packet->raw->chaddr,
	    packet->raw->hlen);

	lease = find_lease(packet, packet->shared_network, 0);

	/*
	 * Find an IP address in the host_decl that matches the specified
	 * network.
	 */
	if (hp)
		subnet = find_host_for_network(&hp, &ip_address,
		    packet->shared_network);

	if (!subnet) {
		/*
		 * We didn't find an applicable host declaration. Just in case
		 * we may be able to dynamically assign an address, see if
		 * there's a host declaration that doesn't have an ip address
		 * associated with it.
		 */
		if (hp)
			for (; hp; hp = hp->n_ipaddr)
				if (!hp->fixed_addr) {
					host = hp;
					break;
				}

		if (host && (!host->group->allow_booting)) {
			note("Ignoring excluded BOOTP client %s", host->name ?
			    host->name : print_hw_addr (packet->raw->htype,
			    packet->raw->hlen, packet->raw->chaddr));
			return;
		}

		if (host && (!host->group->allow_bootp)) {
			note("Ignoring BOOTP request from client %s",
			    host->name ? host->name :
			    print_hw_addr(packet->raw->htype,
			    packet->raw->hlen, packet->raw->chaddr));
			return;
		}

		/*
		 * If we've been told not to boot unknown clients, and we didn't
		 * find any host record for this client, ignore it.
		 */
		if (!host &&
		    !(packet->shared_network->group->boot_unknown_clients)) {
			note("Ignoring unknown BOOTP client %s via %s",
			    print_hw_addr(packet->raw->htype,
			    packet->raw->hlen, packet->raw->chaddr),
			    packet->raw->giaddr.s_addr ?
			    inet_ntoa(packet->raw->giaddr) :
			    packet->interface->name);
			return;
		}

		/*
		 * If we've been told not to boot with bootp on this network,
		 * ignore it.
		 */
		if (!host &&
		    !(packet->shared_network->group->allow_bootp)) {
			note("Ignoring BOOTP request from client %s via %s",
			    print_hw_addr(packet->raw->htype,
			    packet->raw->hlen, packet->raw->chaddr),
			    packet->raw->giaddr.s_addr ?
			    inet_ntoa(packet->raw->giaddr) :
			    packet->interface->name);
			return;
		}

		/*
		 * If the packet is from a host we don't know and there are no
		 * dynamic bootp addresses on the network it came in on, drop
		 * it on the floor.
		 */
		if (!(packet->shared_network->group->dynamic_bootp)) {
lose:
			note("No applicable record for BOOTP host %s via %s",
			    print_hw_addr(packet->raw->htype,
			    packet->raw->hlen, packet->raw->chaddr),
			    packet->raw->giaddr.s_addr ?
			    inet_ntoa(packet->raw->giaddr) :
			    packet->interface->name);
			return;
		}

		/*
		 * If a lease has already been assigned to this client and it's
		 * still okay to use dynamic bootp on that lease, reassign it.
		 */
		if (lease) {
			/*
			 * If this lease can be used for dynamic bootp, do so.
			 */
			if ((lease->flags & DYNAMIC_BOOTP_OK)) {
				/*
				 * If it's not a DYNAMIC_BOOTP lease, release it
				 * before reassigning it so that we don't get a
				 * lease conflict.
				 */
				if (!(lease->flags & BOOTP_LEASE))
					release_lease(lease);

				lease->host = host;
				ack_lease(packet, lease, 0, 0);
				return;
			}

			 /*
			  * If dynamic BOOTP is no longer allowed for this
			  * lease, set it free.
			  */
			release_lease(lease);
		}

		/*
		 * If there are dynamic bootp addresses that might be
		 * available, try to snag one.
		 */
		for (lease = packet->shared_network->last_lease;
		    lease && lease->ends <= cur_time;
		    lease = lease->prev) {
			if ((lease->flags & DYNAMIC_BOOTP_OK)) {
				lease->host = host;
				ack_lease(packet, lease, 0, 0);
				return;
			}
		}
		goto lose;
	}

	/* Make sure we're allowed to boot this client. */
	if (hp && (!hp->group->allow_booting)) {
		note("Ignoring excluded BOOTP client %s", hp->name);
		return;
	}

	/* Make sure we're allowed to boot this client with bootp. */
	if (hp && (!hp->group->allow_bootp)) {
		note("Ignoring BOOTP request from client %s", hp->name);
		return;
	}

	/* Set up the outgoing packet... */
	memset(&outgoing, 0, sizeof outgoing);
	memset(&raw, 0, sizeof raw);
	outgoing.raw = &raw;

	/*
	 * If we didn't get a known vendor magic number on the way in, just
	 * copy the input options to the output.
	 */
	if (!packet->options_valid && !subnet->group->always_reply_rfc1048 &&
	    (!hp || !hp->group->always_reply_rfc1048)) {
		memcpy(outgoing.raw->options, packet->raw->options,
		    DHCP_OPTION_LEN);
		outgoing.packet_length = BOOTP_MIN_LEN;
	} else {
		struct tree_cache netmask_tree;   /*  -- RBF */

		/*
		 * Come up with a list of options that we want to send to this
		 * client. Start with the per-subnet options, and then override
		 * those with client-specific options.
		 */

		memcpy(options, subnet->group->options, sizeof(options));

		for (i = 0; i < 256; i++)
			if (hp->group->options[i])
				options[i] = hp->group->options[i];

		/*
		 * Use the subnet mask from the subnet declaration if no other
		 * mask has been provided.
		 */
		if (!options[DHO_SUBNET_MASK]) {
			options[DHO_SUBNET_MASK] = &netmask_tree;
			netmask_tree.flags = TC_TEMPORARY;
			netmask_tree.value = lease->subnet->netmask.iabuf;
			netmask_tree.len = lease->subnet->netmask.len;
			netmask_tree.buf_size = lease->subnet->netmask.len;
			netmask_tree.timeout = -1;
			netmask_tree.tree = NULL;
		}

		/*
		 * Pack the options into the buffer. Unlike DHCP, we can't pack
		 * options into the filename and server name buffers.
		 */

		outgoing.packet_length = cons_options(packet, outgoing.raw,
		    0, options, 0, 0, 1, NULL, 0);

		if (outgoing.packet_length < BOOTP_MIN_LEN)
			outgoing.packet_length = BOOTP_MIN_LEN;
	}

	/* Take the fields that we care about... */
	raw.op = BOOTREPLY;
	raw.htype = packet->raw->htype;
	raw.hlen = packet->raw->hlen;
	memcpy(raw.chaddr, packet->raw->chaddr, sizeof(raw.chaddr));
	raw.hops = packet->raw->hops;
	raw.xid = packet->raw->xid;
	raw.secs = packet->raw->secs;
	raw.flags = packet->raw->flags;
	raw.ciaddr = packet->raw->ciaddr;
	memcpy(&raw.yiaddr, ip_address.iabuf, sizeof(raw.yiaddr));

	/* Figure out the address of the next server. */
	if (hp && hp->group->next_server.len)
		memcpy(&raw.siaddr, hp->group->next_server.iabuf, 4);
	else if (subnet->group->next_server.len)
		memcpy(&raw.siaddr, subnet->group->next_server.iabuf, 4);
	else if (subnet->interface_address.len)
		memcpy(&raw.siaddr, subnet->interface_address.iabuf, 4);
	else
		raw.siaddr = packet->interface->primary_address;

	raw.giaddr = packet->raw->giaddr;
	if (hp->group->server_name)
		strncpy(raw.sname, hp->group->server_name, sizeof(raw.sname));
	else if (subnet->group->server_name)
		strncpy(raw.sname, subnet->group->server_name,
		    sizeof(raw.sname));

	if (hp->group->filename)
		strncpy(raw.file, hp->group->filename, sizeof(raw.file));
	else if (subnet->group->filename)
		strncpy(raw.file, subnet->group->filename, sizeof(raw.file));
	else
		memcpy(raw.file, packet->raw->file, sizeof(raw.file));

	from = packet->interface->primary_address;

	/* Report what we're doing... */
	note("BOOTREPLY for %s to %s (%s) via %s", piaddr(ip_address),
	    hp->name, print_hw_addr(packet->raw->htype, packet->raw->hlen,
	    packet->raw->chaddr), packet->raw->giaddr.s_addr ?
	    inet_ntoa(packet->raw->giaddr) : packet->interface->name);

	/* Set up the parts of the address that are in common. */
	memset(&to, 0, sizeof(to));
	to.sin_family = AF_INET;
#ifdef HAVE_SA_LEN
	to.sin_len = sizeof(to);
#endif

	/* If this was gatewayed, send it back to the gateway... */
	if (raw.giaddr.s_addr) {
		to.sin_addr = raw.giaddr;
		to.sin_port = server_port;

		(void) send_packet(packet->interface, &raw,
		    outgoing.packet_length, from, &to, packet->haddr);
		return;
	}

	/*
	 * If it comes from a client that already knows its address and is not
	 * requesting a broadcast response, and we can unicast to a client
	 * without using the ARP protocol, sent it directly to that client.
	 */
	else if (!(raw.flags & htons(BOOTP_BROADCAST))) {
		to.sin_addr = raw.yiaddr;
		to.sin_port = client_port;
	} else {
		/* Otherwise, broadcast it on the local network. */
		to.sin_addr.s_addr = INADDR_BROADCAST;
		to.sin_port = client_port; /* XXX */
	}

	errno = 0;
	(void) send_packet(packet->interface, &raw,
	    outgoing.packet_length, from, &to, packet->haddr);
}