📄 dhcps.c
字号:
return (NULL); }/********************************************************************************* select_wreqip - retrieve resource matching IP address** This routine retrieves the dhcp_resource structure which provides the IP* address requested by the client. The requested IP address must be on the* same subnet as the requesting client. The client must also provide a* matching client identifier, if included in the server's database entry.** RETURNS: Matching resource, or NULL if none or not available.** ERRNO: N/A** NOMANUAL*/ static struct dhcp_resource * select_wreqip ( int msgtype, /* DHCP message type */ struct client_id *cid, /* pointer to client ID */ time_t curr_epoch /* current time, in seconds */ ) { char *option = NULL; /* pointer to access options field */ char tmp [INET_ADDR_LEN]; /* temp IP address storage */ struct dhcp_resource *res = NULL; /* access to lease descriptor data */ struct in_addr reqip; /* value of desired IP address */ bzero (tmp, sizeof (tmp)); bzero ( (char *)&reqip, sizeof (reqip)); option = pickup_opt (dhcpsMsgIn.dhcp, rdhcplen, _DHCP_REQUEST_IPADDR_TAG); if (option != NULL) { reqip.s_addr = htonl (GETHL (OPTBODY (option))); res = (struct dhcp_resource *)hash_find (&iphashtable, (char *)&reqip.s_addr, sizeof (u_long), resipcmp, &reqip); if (res == NULL) {#ifdef DHCPS_DEBUG inet_ntoa_b (reqip, tmp); logMsg ("IP address %s is not in address pool", tmp, 0, 0, 0, 0, 0);#endif return (NULL); } else { /* check the subnet number */ if (cid->subnet.s_addr != (res->ip_addr.s_addr & res->subnet_mask.s_addr)) {#ifdef DHCPS_DEBUG inet_ntoa_b (reqip, tmp); logMsg ( "DHCP%s(cid:\"%s\"): subnet mismatch for requested IP address %s.\n", (int)((msgtype == DHCPDISCOVER) ? "DISCOVER" : "REQUEST"), (int)cidtos (cid, 1), (int)tmp, 0, 0, 0);#endif return (NULL); } /* is it manual allocation ? */ if (ISSET (res->valid, S_CLIENT_ID)) { /* is there corresponding binding ? */ if (res->binding == NULL) {#ifdef DHCPS_DEBUG inet_ntoa_b (reqip, tmp); logMsg ( "DHCP%s(cid:\"%s\"): No corresponding binding for %s", (int)((msgtype == DHCPDISCOVER) ? "DISCOVER" : "REQUEST"), (int)cidtos (cid, 1), (int)tmp, 0, 0, 0);#endif return (NULL); } /* Check for matching client identifiers. */ if (cidcmp (&res->binding->cid, cid) != TRUE) {#ifdef DHCPS_DEBUG inet_ntoa_b (reqip, tmp); logMsg ( "DHCP%s(cid:\"%s\"): Client ID mismatch for requested IP address %s.\n", (int)((msgtype == DHCPDISCOVER) ? "DISCOVER" : "REQUEST"), (int)cidtos (cid, 1), (int)tmp, 0, 0, 0);#endif return (NULL); } /* Check if the address is already in use. */ if (icmp_check (msgtype, &res->ip_addr) == GOOD) return (res); else { turnoff_bind (res->binding); return (NULL); } } /* If not manual allocation, is the requested lease available? */ else if (available_res (res, cid, curr_epoch)) { if (icmp_check (msgtype, &res->ip_addr) == GOOD) return (res); else { turnoff_bind (res->binding); return (NULL); } } } } return (NULL); /* No requested IP address present in option list. */ }/********************************************************************************* select_newone - choose an entry from the available resources** This routine retrieves a dhcp_resource structure for a client if no entry* was found based on the requested IP address, if any, or the client * identifier. No addresses which are in use or on a different subnet than * the client are considered. For the remaining entries, it uses the following * criteria:** First, select entries which were never used in preference to used ones.** If not found, select the least recently used entry.** Next, give preference to entries which are unavailable to BOOTP clients.** Among unused or equally old entries, select the smallest possible * maximum which exceeds the requested lease length. If not found, * choose the resource with the largest maximum lease length.** The previous condition excludes resources with an infinite maximum* lease whenever possible, unless specifically requested by the client.** If not found (i.e. - all entries have same maximum lease length), * select the first available entry in the database.** RETURNS: Matching resource, or NULL if none or not available.** ERRNO: N/A** NOMANUAL*/static struct dhcp_resource * select_newone ( int msgtype, /* DHCP message type */ struct client_id *cid, /* pointer to client ID */ time_t curr_epoch, /* current time, in seconds */ u_long reqlease /* requested lease duration (seconds) */ ) { struct dhcp_resource *res = NULL; struct dhcp_resource *best = NULL; struct hash_member *resptr = NULL; /* Examine each resource in list constructed from database. */ resptr = reslist; while (resptr != NULL) { res = (struct dhcp_resource *)resptr->data; if (res->ip_addr.s_addr == 0) /* Skip dummy entries. */ { resptr = resptr->next; continue; } /* * Check the resource subnet and availability. Skip entries which * are not available or would change the subnet of the client. */ if (cid->subnet.s_addr == (res->ip_addr.s_addr & res->subnet_mask.s_addr) && available_res (res, cid, curr_epoch)) { /* * choose the best entry from available resources on the same * subnet. The criteria are listed in inverse priority order. */ /* Lowest priority - take first available entry. */ if (best == NULL) { if (icmp_check (msgtype, &res->ip_addr) == GOOD) best = res; else turnoff_bind (res->binding); resptr = resptr->next; continue; } /* Select unused entries in preference to used ones. */ if (best->binding == NULL && res->binding != NULL) { resptr = resptr->next; continue; } else if (best->binding != NULL && res->binding == NULL) { if (icmp_check (msgtype, &res->ip_addr) == GOOD) best = res; else turnoff_bind (res->binding); resptr = resptr->next; continue; } /* Give preference to entries not available to BOOTP clients. */ if (best->allow_bootp == FALSE && res->allow_bootp == TRUE) { resptr = resptr->next; continue; } else if (best->allow_bootp == TRUE && res->allow_bootp == FALSE) { if (icmp_check(msgtype, &res->ip_addr) == GOOD) best = res; else turnoff_bind (res->binding); resptr = resptr->next; continue; } /* * Tiebreaker conditionals for preferred entries (either both * unused or which both qualify as least recently used). * Overall, these conditionals select the resource whose maximum * lease exceeds the threshold of the requested lease length by * the minimum amount. If there is no resource whose maximum lease * exceeds the requested lease length, the resource with the * largest maximum lease is chosen. * * NOTE: These conditionals also implement a preference for resource * entries which do not provide an infinite lease, unless * specifically requested by the client. */ if ( (best->binding == NULL && res->binding == NULL) || (best->binding != NULL && res->binding != NULL && best->binding->expire_epoch == res->binding->expire_epoch)) { /* * Select resource with larger maximum lease, * even if shorter than the requested lease length. * Combined with the third conditional, the maximum value * of the maximum lease will be selected, if the lease length * threshold is not exceeded. */ if (reqlease >= res->max_lease && res->max_lease > best->max_lease) { if (icmp_check (msgtype, &res->ip_addr) == GOOD) best = res; else turnoff_bind (res->binding); resptr = resptr->next; continue; } /* * Among resources whose maximum lease exceeds * the requested value, select the minimum. * This condition is never true until either the * previous or next condition evaluated to true. */ if (reqlease != INFINITY && reqlease <= res->max_lease && res->max_lease < best->max_lease) { if (icmp_check (msgtype, &res->ip_addr) == GOOD) best = res; else turnoff_bind (res->binding); resptr = resptr->next; continue; } /* * Accept entries longer than both the requested value * and the current maximum. This condition evaluates to * true at most once. Once it does, neither it or the * first conditional will ever evaluate to true again. */ if (reqlease != INFINITY && res->max_lease >= reqlease && reqlease > best->max_lease) { if (icmp_check (msgtype, &res->ip_addr) == GOOD) best = res; else turnoff_bind (res->binding); resptr = resptr->next; continue; } resptr = resptr->next; continue; } /* * Among previously used entries, select those which expired * earlier. (In the aggregate, implements a LRU algorithm). */ if (best->binding != NULL && res->binding != NULL && best->binding->expire_epoch > res->binding->expire_epoch) { if (icmp_check (msgtype, &res->ip_addr) == GOOD) best = res; else turnoff_bind (res->binding); resptr = resptr->next; continue; } else { resptr = resptr->next; continue; } } resptr = resptr->next; } return (best); }/********************************************************************************* choose_res - select a resource for DHCP client** This routine chooses a resource in response to an incoming DHCP discover * message. If the server database contains a manual entry matching the* client identifier, the corresponding resource is returned. Otherwise,* the database entry which provides the requested IP address, if any, is * chosen. If the discover message does not require a specific entry, the* server selects a new entry using its own internal criteria, or NULL if* no entry is available.** RETURNS: Matching resource, or NULL if none available.** ERRNO: N/A** NOMANUAL*/static struct dhcp_resource * choose_res ( struct client_id *cid, /* pointer to client ID */ time_t curr_epoch, /* current time, in seconds */ u_long reqlease /* requested lease duration (seconds) */ ) { struct dhcp_resource *res = NULL; /* 1. select with client identifier, if found. */ if ( (res = select_wcid (DHCPDISCOVER, cid, curr_epoch)) != NULL) return (res); /* 2. select with requested IP address, if any. */ if ( (res = select_wreqip (DHCPDISCOVER, cid, curr_epoch)) != NULL) return (res); /* 3. select an entry using internal criteria. */ res = select_newone (DHCPDISCOVER, cid, curr_epoch, reqlease); if (res != NULL) return (res);#ifdef DHCPS_DEBUG logMsg ("Warning: DHCPDISCOVER - No available addresses in the pool.\n", 0, 0, 0, 0, 0, 0);#endif return (NULL); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -