📄 dhcps.c
字号:
/* Insert options from matching resource entry not already present. */ if (params != NULL) { for (i = 0; i < _DHCP_LAST_OPTION; i++) if (ISCLR (inserted, i)) if (insert_opt (params, lease, i, inserted, PASSIVE) == E_NOMORE) {#ifdef DHCPS_DEBUG logMsg ("No space left in options field for DHCP%s", (int) ((msgtype == DHCPOFFER) ? "OFFER" : "ACK"), 0, 0, 0, 0, 0);#endif break; } } } /* Insert any class-specific options. */ option = pickup_opt (dhcpsMsgIn.dhcp, rdhcplen, _DHCP_CLASS_ID_TAG); if (option != NULL) { paramId.idlen = DHCPOPTLEN (option); paramId.idtype = 0; /* Unused for class identifiers. */ bcopy (OPTBODY (option), paramId.id, paramId.idlen); params = hash_find (¶mhashtable, paramId.id, paramId.idlen, paramcidcmp, ¶mId); /* Insert options from matching resource entry not already present. */ if (params != NULL) { for (i = 0; i < _DHCP_LAST_OPTION; i++) if (ISCLR (inserted, i)) if (insert_opt (params, lease, i, inserted, PASSIVE) == E_NOMORE) {#ifdef DHCPS_DEBUG logMsg ("No space left in options field for DHCP%s", (int) ((msgtype == DHCPOFFER) ? "OFFER" : "ACK"), 0, 0, 0, 0, 0);#endif break; } } } return;}/********************************************************************************* select_wciaddr - retrieve resource with matching IP address** This routine attempts to find an address pool entry whose IP address matches* the value requested by the client. If the matching IP address is part of a* manual lease, it also verifies that the client ID matches the required value.* Otherwise, it checks if the requesting client received an offer from the* server.** RETURNS: Matching resource, or NULL if none or not available.** ERRNO: N/A** NOMANUAL*//* * choose resource with ciaddr */static struct dhcp_resource *select_wciaddr (struct client_id *cid, /* pointer to identifier of request client */ time_t curr_epoch, /* current time, in seconds */ int *nosuchaddr /* flag indicating if address foun in table */ ){ struct dhcp_resource *res = NULL;#ifdef DHCPS_DEBUG char tmp[INET_ADDR_LEN];#endif *nosuchaddr = FALSE; res = (struct dhcp_resource *) hash_find (&iphashtable, (char *) &dhcpsMsgIn.dhcp->ciaddr.s_addr, sizeof (u_long), resipcmp, &dhcpsMsgIn.dhcp->ciaddr); if (res == NULL) { *nosuchaddr = TRUE; /* Fatal error - expected entry not found. */ return (NULL); } else { /* Check for subnet match. */ if (cid->subnet.s_addr != (res->ip_addr.s_addr & res->subnet_mask.s_addr)) {#ifdef DHCPS_DEBUG inet_ntoa_b (dhcpsMsgIn.dhcp->ciaddr, tmp); logMsg ("Subnet mismatch for DHCPREQUEST (cid: %s, ciaddr: %s).\n", (int) cidtos (cid, 1), (int) tmp, 0, 0, 0, 0);#endif return (NULL); } else if (ISSET (res->valid, S_CLIENT_ID)) { /* Manual allocation. */ /* Fatal error if no binding present for manual allocation. */ if (res->binding == NULL) {#ifdef DHCPS_DEBUG inet_ntoa_b (dhcpsMsgIn.dhcp->ciaddr, tmp); logMsg ("DHCPREQUEST(cid:\"%s\"): No binding for %s", (int) cidtos (cid, 1), (int) tmp, 0, 0, 0, 0);#endif *nosuchaddr = TRUE; return (NULL); } /* Check that client ID of binding matches requesting client. */ else if (res->binding->cid.idtype != cid->idtype || res->binding->cid.idlen != cid->idlen || bcmp (res->binding->cid.id, cid->id, cid->idlen) != 0) {#ifdef DHCPS_DEBUG inet_ntoa_b (dhcpsMsgIn.dhcp->ciaddr, tmp); logMsg ("DHCPREQUEST(cid:\"%s\", ciaddr:%s) - client ID mismatch.\n", (int) cidtos (cid, 1), (int) tmp, 0, 0, 0, 0);#endif return (NULL); } } /* Dynamic or automatic allocation. Fails if no binding present * (i.e. - unknown request), or lease has expired (i.e. - late * request), or if client ID doesn't match expected value from * the DHCP offer message. */ else if (res->binding == NULL || (res->binding->expire_epoch != 0xffffffff && res->binding->expire_epoch <= curr_epoch) || res->binding->cid.idtype != cid->idtype || res->binding->cid.idlen != cid->idlen || bcmp (res->binding->cid.id, cid->id, cid->idlen) != 0) {#ifdef DHCPS_DEBUG inet_ntoa_b (dhcpsMsgIn.dhcp->ciaddr, tmp); logMsg ("DHCPREQUEST(cid:\"%s\",ciaddr:%s): is unavailable.\n", (int) cidtos (cid, 1), (int) tmp, 0, 0, 0, 0);#endif return (NULL); } } return (res);}/********************************************************************************* discover - handle client discover messages** This routine examines client discover messages, selects an available * resource (if any), calculates the length of the lease, and sends the * appropriate offer to the client.** RETURNS: 0 if processing successful, or -1 on error.** ERRNO: N/A** NOMANUAL*/static int discover (struct if_info *ifp /* pointer to descriptor of receiving interface */ ){ struct dhcp_resource *offer_res = NULL; /* lease descriptor chosen */ struct client_id cid; /* ID of requesting client */ u_long offer_lease = 0; /* offered lease duration */ u_long reqlease = 0; /* requested lease duration */ time_t curr_epoch = 0; /* current time, in seconds */ int result; /* error value, if any */ bzero ((char *) &cid, sizeof (cid)); if (dhcpTime (&curr_epoch) == -1) {#ifdef DHCPS_DEBUG logMsg ("Warning: discover() couldn't retrieve current time.\n", 0, 0, 0, 0, 0, 0);#endif return (-1); } /* Extract requested lease from DHCP message. */ reqlease = get_reqlease (dhcpsMsgIn.dhcp, rdhcplen); /* Determine maximum length available in DHCP message for options. */ maxoptlen = get_maxoptlen (dhcpsMsgIn.dhcp, rdhcplen); /* Set pointers to access client ID within DHCP message options field. */ get_cid (dhcpsMsgIn.dhcp, rdhcplen, &cid); /* Critical section with dhcpsLeaseEntryAdd(). */ semTake (dhcpsMutexSem, WAIT_FOREVER); /* Retrieve subnet for incoming message. */ if (get_subnet (dhcpsMsgIn.dhcp, rdhcplen, &cid.subnet, ifp) != 0) { semGive (dhcpsMutexSem); return (-1); } /* Select an available lease descriptor. */ if ((offer_res = choose_res (&cid, curr_epoch, reqlease)) == NULL) { semGive (dhcpsMutexSem); return (-1); } /* Select a lease duration. */ offer_lease = choose_lease (reqlease, curr_epoch, offer_res); /* Record lease offer in data structures. */ result = update_db (DHCPDISCOVER, &cid, offer_res, offer_lease, curr_epoch); semGive (dhcpsMutexSem); if (result != 0) return (-1); /* Create outgoing DHCP offer message. */ construct_msg (DHCPOFFER, offer_res, offer_lease, ifp); /* * xxx must be able to handle the fragments, but currently not implemented */ /* Transfer message to receiving interface. */ send_dhcp (ifp, DHCPOFFER); return (0);}/********************************************************************************* request - handle client request messages** This routine responds to request messages sent by clients in response* to an offer from a DHCP server. If the server generated the offer, it* sends the appropriate ACK or NAK message. Otherwise, it updates the * internal data structure to reflect the implicit decline from the client.** RETURNS: 0 if processing successful, or -1 on error.** ERRNO: N/A** NOMANUAL*/static int request (struct if_info *ifp /* pointer to descriptor of receiving interface */ ){ BOOL reqforme = FALSE; BOOL nosuchaddr = FALSE; struct dhcp_resource *res = NULL; struct client_id cid; struct in_addr reqip; struct in_addr netmask; unsigned long offer_lease = 0; /* offering lease */ unsigned long reqlease = 0; /* requested lease duration */ char *option = NULL; int response; /* Accept request? */#define EPOCH "Thu Jan 1 00:00:00 1970\n"#define BRDCSTSTR "255.255.255.255" char datestr[sizeof (EPOCH)]; char addrstr[sizeof (BRDCSTSTR)]; time_t curr_epoch = 0; /* current epoch */ bzero ((char *) &cid, sizeof (cid)); bcopy (EPOCH, datestr, sizeof (EPOCH)); bcopy (BRDCSTSTR, addrstr, sizeof (BRDCSTSTR)); response = 2; /* Response not determined. */ if (dhcpTime (&curr_epoch) == -1) {#ifdef DHCPS_DEBUG logMsg ("Warning: Couldn't get timestamp when processing request.\n", 0, 0, 0, 0, 0, 0);#endif return (-1); } reqlease = get_reqlease (dhcpsMsgIn.dhcp, rdhcplen); maxoptlen = get_maxoptlen (dhcpsMsgIn.dhcp, rdhcplen); get_cid (dhcpsMsgIn.dhcp, rdhcplen, &cid); /* Critical section with dhcpsLeaseEntryAdd(). */ semTake (dhcpsMutexSem, WAIT_FOREVER); if (get_subnet (dhcpsMsgIn.dhcp, rdhcplen, &cid.subnet, ifp) != 0) { semGive (dhcpsMutexSem); return (-1); } /* * Check if this DHCP server is the request destination. * (Option not present unless client is in SELECTING state). */ option = pickup_opt (dhcpsMsgIn.dhcp, rdhcplen, _DHCP_SERVER_ID_TAG); if (option != NULL) if (htonl (GETHL (OPTBODY (option))) == ifp->ipaddr.s_addr) reqforme = TRUE; /* * Check the previously allocated network address sent by client * (i.e. - client is in RENEWING or REBINDING state). */ if (dhcpsMsgIn.dhcp->ciaddr.s_addr != 0) { /* For client in RENEWING state, no relay agents are used. */ if (get_snmk (dhcpsMsgIn.dhcp, rdhcplen, &netmask, ifp) == 0) if (dhcpsMsgIn.dhcp->giaddr.s_addr != 0) /* REBINDING state - check network of client. */ if ((dhcpsMsgIn.dhcp->giaddr.s_addr & netmask.s_addr) != (dhcpsMsgIn.dhcp->ciaddr.s_addr & netmask.s_addr)) /* goto nak; *//* Different subnet. */ response = 0; /* Send NAK to client. */ if (response != 0) { /* Response still not determined. */ res = select_wciaddr (&cid, curr_epoch, &nosuchaddr); if (res == NULL) { /* * If no entry present or manual entry present without a * matching binding the request is meant for another server * (for renewal request) or cannot be satisfied (for rebinding). */ if (nosuchaddr == TRUE) { semGive (dhcpsMutexSem); return (-1); } /* deny request for subnet mismatch, client ID mismatch, * expired lease, or missing binding for non-manual allocation. * (Missing binding means no DISCOVER received for request). */ else response = 0; } else /* goto ack; */ response = 1; /* Send ACK to client. */ } } if (response == 2) { /* Response still undetermined. */ /* Requesting client has no IP address (i.e. - initial request * from SELECTING state or verification of cached lease from * INIT-REBOOT state). */ reqip.s_addr = 0; option = pickup_opt (dhcpsMsgIn.dhcp, rdhcplen, _DHCP_REQUEST_IPADDR_TAG); if (option != NULL) reqip.s_addr = htonl (GETHL (OPTBODY (option))); if (reqip.s_addr != 0) { if (get_snmk (dhcpsMsgIn.dhcp, rdhcplen, &netmask, ifp) == 0) { /* * Deny request received if client is on the wrong network. * (Suggested behavior from RFC 1541). */ if (dhcpsMsgIn.dhcp->giaddr.s_addr != 0) { /* Deny request received from relay agent if requested IP * address is not on agent's subnet. */ if ((dhcpsMsgIn.dhcp->giaddr.s_addr & netmask.s_addr) != (reqip.s_addr & netmask.s_addr)) response = 0; /* Send NAK to client. */ } else { /* Deny request received directly if requested IP address * on different subnet from receiving interface. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -