📄 dhcps.c
字号:
/********************************************************************************* update_db - add entries to internal data structures to reflect client state** This routine updates the binding list and corresponding hash tables when* the server receives a DHCP discover message, or a DHCP or BOOTP request* message from a client. The binding entry for the resource is marked* unavailable for a short interval (for DHCP discover) or until the expiration* of the lease.** RETURNS: 0 if update completed, or -1 on error.** ERRNO: N/A** NOMANUAL*/static int update_db ( int msgtype, /* DHCP message type */ struct client_id *cid, /* pointer to client ID */ struct dhcp_resource *res, /* pointer to lease descriptor */ u_long lease, /* lease duration, in seconds */ time_t curr_epoch /* current time, in seconds */ ) { struct dhcp_binding *binding = NULL; /* * Ignore lease descriptors already offered (res->binding != NULL) * if also reserved to specific clients (STATIC_ENTRY flag set). */ if (res->binding != NULL && (res->binding->flag & STATIC_ENTRY) != 0) return (0); /* Remove old client identifier association from prior lease record. */ if (res->binding != NULL) hash_del (&cidhashtable, res->binding->cid.id, res->binding->cid.idlen, bindcidcmp, &res->binding->cid, free_bind); /* Create and assign new lease record entry. */ binding = (struct dhcp_binding *)calloc (1, sizeof (struct dhcp_binding)); if (binding == NULL) {#ifdef DHCPS_DEBUG logMsg ("Warning: memory allocation error updating database.\n", 0, 0, 0, 0, 0, 0);#endif return (-1); } if (cidcopy (cid, &binding->cid) != 0) return (-1); if (msgtype == DHCPDISCOVER) binding->temp_epoch = curr_epoch + MEMORIZE; else if (lease == 0xffffffff) binding->expire_epoch = 0xffffffff; else binding->expire_epoch = curr_epoch + lease; /* Link lease record and lease descriptor. */ binding->res = res; bcopy (res->entryname, binding->res_name, strlen (res->entryname)); binding->res_name [strlen (res->entryname)] = '\0'; res->binding = binding; /* Record client hardware address. */ binding->haddr.htype = dhcpsMsgIn.dhcp->htype; binding->haddr.hlen = dhcpsMsgIn.dhcp->hlen; if (binding->haddr.hlen > MAX_HLEN) binding->haddr.hlen = MAX_HLEN; bcopy (dhcpsMsgIn.dhcp->chaddr, binding->haddr.haddr, binding->haddr.hlen); /* Add association of lease record and client identifier. */ if ( (hash_ins (&cidhashtable, binding->cid.id, binding->cid.idlen, bindcidcmp, &binding->cid, binding) < 0)) {#ifdef DHCPS_DEBUG logMsg ("Warning: hash table insertion with client ID failed.\n", 0, 0, 0, 0, 0, 0);#endif return (-1); } /* Store record of lease. */ if (add_bind (binding) != 0) return (-1); return (0); }/********************************************************************************* turnoff_bind - mark resource entry as unavailable** This routine updates the binding list and corresponding hash tables when* the server discovers (through an ICMP check or client decline) that an IP * address is unexpectedly in use. The corresponding resource is marked as an * active lease for the next half-hour.** RETURNS: N/A** ERRNO: N/A** NOMANUAL*/static void turnoff_bind ( struct dhcp_binding *binding /* unavailable lease record */ ) { time_t curr_epoch = 0; int result; if (binding == NULL) return; if (dhcpTime (&curr_epoch) == -1) {#ifdef DHCPS_DEBUG logMsg ("Warning: turnoff_bind() can't retrieve current time.\n", 0, 0, 0, 0, 0, 0);#endif return; } /* Remove client ID from hash table entry for address in use. */ binding->expire_epoch = binding->temp_epoch = curr_epoch + 1800; hash_del (&cidhashtable, binding->cid.id, binding->cid.idlen, bindcidcmp, &binding->cid, free_fake); bzero (binding->cid.id, binding->cid.idlen); result = hash_ins (&cidhashtable, binding->cid.id, binding->cid.idlen, bindcidcmp, &binding->cid, binding);#ifdef DHCPS_DEBUG if (result < 0) logMsg ("Warning: couldn't alter hash table in turnoff_bind()", 0, 0, 0, 0, 0, 0);#endif binding->flag &= ~COMPLETE_ENTRY; return; }/********************************************************************************* clean_sbuf - clean the message transmission buffers** This routine clears the vectored buffers used to store outgoing DHCP * messages. The first buffer contains the Ethernet, IP and UDP headers, as well* as the fixed-length portion of the DHCP message and the options which fit * within the default (312 byte) option field. The second buffer contains * overflow options, if any, for clients capable of receiving DHCP messages * longer than the default 548 bytes.** RETURNS: N/A** ERRNO: N/A** NOMANUAL*/static void clean_sbuf (void) { bzero (sbufvec[0].iov_base, sbufvec[0].iov_len); bzero (sbufvec[1].iov_base, sbufvec[1].iov_len); sbufvec[1].iov_len = 0; return; }/********************************************************************************* construct_msg - make an outgoing DHCP message** This routine creates all DHCP server responses to client requests, according* to the behavior specified in RFC 1541. The message type parameter indicates* whether to build a DHCP offer message, a DHCP ACK message, or a NAK reply.** RETURNS: N/A** ERRNO: N/A** NOMANUAL*/static void construct_msg ( u_char msgtype, /* type of DHCP message to construct */ struct dhcp_resource *res, /* lease descriptor describing contents */ u_long lease, /* lease duration, in seconds */ struct if_info *ifp /* descriptor of receiving interface */ ) { int i = 0; int reqoptlen = 0; u_long tmp = 0; char *reqopt = NULL; char inserted[32]; char *option = NULL; struct client_id paramId; /* Key for additional parameters. */ struct dhcp_resource * params; /* Client- or class-specific options. */ int result; bzero (inserted, sizeof (inserted)); clean_sbuf (); /* Zero out outgoing message buffer. */ dhcpsMsgOut.dhcp->op = BOOTREPLY; dhcpsMsgOut.dhcp->htype = dhcpsMsgIn.dhcp->htype; dhcpsMsgOut.dhcp->hlen = dhcpsMsgIn.dhcp->hlen; dhcpsMsgOut.dhcp->hops = 0; dhcpsMsgOut.dhcp->xid = dhcpsMsgIn.dhcp->xid; dhcpsMsgOut.dhcp->secs = 0; dhcpsMsgOut.dhcp->flags = dhcpsMsgIn.dhcp->flags; dhcpsMsgOut.dhcp->giaddr.s_addr = dhcpsMsgIn.dhcp->giaddr.s_addr; bcopy (dhcpsMsgIn.dhcp->chaddr, dhcpsMsgOut.dhcp->chaddr, dhcpsMsgIn.dhcp->hlen); if (msgtype == DHCPACK) /* ciaddr stays zero for all other types. */ dhcpsMsgOut.dhcp->ciaddr.s_addr = dhcpsMsgIn.dhcp->ciaddr.s_addr; if (msgtype != DHCPNAK) { dhcpsMsgOut.dhcp->yiaddr.s_addr = res->ip_addr.s_addr; if (ISSET (res->valid, S_SIADDR)) { dhcpsMsgOut.dhcp->siaddr.s_addr = res->siaddr.s_addr; } else { dhcpsMsgOut.dhcp->siaddr.s_addr = 0; } overload = BOTH_AREOPT; if (ISSET (res->valid, S_SNAME)) { strncpy (dhcpsMsgOut.dhcp->sname, res->sname, MAX_SNAME); dhcpsMsgOut.dhcp->sname [MAX_SNAME - 1] = '\0'; overload -= SNAME_ISOPT; } if (ISSET (res->valid, S_FILE)) { strncpy (dhcpsMsgOut.dhcp->file, res->file, MAX_FILE); dhcpsMsgOut.dhcp->file [MAX_FILE - 1] = '\0'; overload -= FILE_ISOPT; } } else { dhcpsMsgOut.dhcp->yiaddr.s_addr = 0; dhcpsMsgOut.dhcp->siaddr.s_addr = 0; /* Refinement for draft RFC. */ /* if (dhcpsMsgIn.giaddr.s_addr != 0) SETBRDCAST (dhcpsMsgOut.dhcp->flags); */ } /* insert magic cookie */ bcopy ((char *)dhcpCookie, dhcpsMsgOut.dhcp->options, MAGIC_LEN); off_options = MAGIC_LEN; off_extopt = 0; /* insert dhcp message type option */ dhcpsMsgOut.dhcp->options [off_options++] = _DHCP_MSGTYPE_TAG; dhcpsMsgOut.dhcp->options [off_options++] = 1; dhcpsMsgOut.dhcp->options [off_options++] = msgtype; /* Insert client ID when permitted. (Only allowed under draft RFC). */ if (msgtype == DHCPNAK) { SETBRDCST (dhcpsMsgOut.dhcp->flags);/* option = pickup_opt (dhcpsMsgIn.dhcp, rdhcplen, _DHCP_CLIENT_ID_TAG); if (option != NULL) { dhcpsMsgOut.dhcp->options [off_options++] = _DHCP_CLIENT_ID_TAG; dhcpsMsgOut.dhcp->options [off_options++] = DHCPOPTLEN(option); bcopy (option, &dhcpsMsgOut.dhcp->options [off_options], DHCPOPTLEN (option)); off_options += DHCPOPTLEN (option); } */ return; } /* insert "server identifier" (required). */ dhcpsMsgOut.dhcp->options [off_options++] = _DHCP_SERVER_ID_TAG; dhcpsMsgOut.dhcp->options [off_options++] = 4; bcopy ( (char *)&ifp->ipaddr.s_addr, &dhcpsMsgOut.dhcp->options [off_options], 4); off_options += 4; /* insert "subnet mask" (permitted). */ result = insert_opt (res, lease, _DHCP_SUBNET_MASK_TAG, inserted, PASSIVE);#ifdef DHCPS_DEBUG if (result == E_NOMORE) logMsg ("No space left in options field for DHCP%s", (int)((msgtype == DHCPOFFER) ? "OFFER" : "ACK"), 0, 0, 0, 0, 0);#endif /* insert "lease duration" (required). */ tmp = htonl (lease); dhcpsMsgOut.dhcp->options [off_options++] = _DHCP_LEASE_TIME_TAG; dhcpsMsgOut.dhcp->options [off_options++] = 4; bcopy ( (char *)&tmp, &dhcpsMsgOut.dhcp->options [off_options], sizeof (u_long)); off_options += 4; /* Insert "option overload" tag, if needed. */ if (overload != 0) { dhcpsMsgOut.dhcp->options[off_options++] = _DHCP_OPT_OVERLOAD_TAG; dhcpsMsgOut.dhcp->options[off_options++] = 1; dhcpsMsgOut.dhcp->options[off_options++] = overload; } /* insert the requested options */ option = pickup_opt(dhcpsMsgIn.dhcp, rdhcplen, _DHCP_REQ_LIST_TAG); if (option != NULL) { reqopt = OPTBODY (option); reqoptlen = DHCPOPTLEN (option); /* * Handle requested parameters. The PASSIVE flag only inserts options * explicity configured into the resource entry. (Rule 1 of RFC 1541). * Because the implementation used "tblc=dflt" to force inclusion of * any missing parameters defined in the Host Requirements Document, * the PASSIVE flag will also include those settings if not already * present. (Rule 2 of RFC 1541). */ for (i = 0; i < reqoptlen; i++) if (ISCLR (inserted, * (reqopt + i))) { result = insert_opt (res, lease, * (reqopt + i), inserted, PASSIVE); if (result == 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 parameters which differ from the Host Requirements RFC defaults. * (The tags for these parameters are preceded by "!" in the server * configuration table). */ for (i = 0; i < _DHCP_LAST_OPTION; i++) if (ISCLR (inserted, i)) if (insert_opt (res, lease, i, inserted, ACTIVE) == 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 client-specific options. */ /* Insert any parameters associated with explicit client identifier. */ tmp = 0; option = pickup_opt (dhcpsMsgIn.dhcp, rdhcplen, _DHCP_CLIENT_ID_TAG); if (option != NULL) { paramId.idlen = DHCPOPTLEN (option) - 1; paramId.idtype = *(char *)OPTBODY (option); bcopy (OPTBODY (option) + sizeof (char), 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -