📄 dhcpd.c
字号:
g_state.ds_optleasetime = 0; /* Requested lease time (host order) */ g_state.ds_optend = NULL; do { /* The form of an option is: * code - 1 byte * length - 1 byte * data - variable number of bytes */ switch (ptr[DHCPD_OPTION_CODE]) { /* Skip over any padding bytes */ case DHCP_OPTION_PAD: optlen = 1; break; /* the Overload option is used to indicate that the DHCP 'sname' or 'file' * fields are being overloaded by using them to carry DHCP options. A DHCP * server inserts this option if the returned parameters will exceed the * usual space allotted for options. * * If this option is present, the client interprets the specified additional * fields after it concludes interpretation of the standard option fields. * * Legal values for this option are: * * 1 the 'file' field is used to hold options * 2 the 'sname' field is used to hold options * 3 both fields are used to hold options */#ifndef CONFIG_NET_DHCP_LIGHT case DHCP_OPTION_OVERLOAD: optlen = ptr[DHCPD_OPTION_LENGTH] + 2; if (optlen >= 1 && optlen < remaining) { overloaded = ptr[DHCPD_OPTION_DATA]; } break;#endif case DHCP_OPTION_END:#ifndef CONFIG_NET_DHCP_LIGHT if (currfield == DHCPD_OPTION_FIELD && (overloaded & DHCPD_FILE_FIELD) != 0) { ptr = g_state.ds_inpacket.file; remaining = sizeof(g_state.ds_inpacket.file); currfield = DHCPD_FILE_FIELD; } else if (currfield == DHCPD_FILE_FIELD && (overloaded & DHCPD_SNAME_FIELD) != 0) { ptr = g_state.ds_inpacket.sname; remaining = sizeof(g_state.ds_inpacket.sname); currfield = DHCPD_SNAME_FIELD; } else { return TRUE; } break;#else return TRUE;#endif case DHCP_OPTION_REQ_IPADDR: /* Requested IP Address */ optlen = ptr[DHCPD_OPTION_LENGTH] + 2; if (optlen >= 4 && optlen < remaining) { memcpy(&tmp, &ptr[DHCPD_OPTION_DATA], 4); g_state.ds_optreqip = (in_addr_t)ntohl(tmp); } break; case DHCP_OPTION_LEASE_TIME: /* IP address lease time */ optlen = ptr[DHCPD_OPTION_LENGTH] + 2; if (optlen >= 4 && optlen < remaining) { memcpy(&tmp, &ptr[DHCPD_OPTION_DATA], 4); g_state.ds_optleasetime = (time_t)ntohl(tmp); } break; case DHCP_OPTION_MSG_TYPE: /* DHCP message type */ optlen = ptr[DHCPD_OPTION_LENGTH] + 2; if (optlen >= 1 && optlen < remaining) { g_state.ds_optmsgtype = ptr[DHCPD_OPTION_DATA]; } break; case DHCP_OPTION_SERVER_ID: /* Server identifier */ optlen = ptr[DHCPD_OPTION_LENGTH] + 2; if (optlen >= 4 && optlen < remaining) { memcpy(&tmp, &ptr[DHCPD_OPTION_DATA], 4); g_state.ds_optserverip = (in_addr_t)ntohl(tmp); } break; default: /* Skip over unsupported options */ optlen = ptr[DHCPD_OPTION_LENGTH] + 2; break; } /* Advance to the next option */ ptr += optlen; remaining -= optlen; } while (remaining > 0); return FALSE;}/**************************************************************************** * Name: dhcpd_verifyreqip ****************************************************************************/static inline boolean dhcpd_verifyreqip(void){ struct lease_s *lease; /* Verify that the requested IP address is within the supported lease range */ if (g_state.ds_optreqip > 0 && g_state.ds_optreqip >= CONFIG_NETUTILS_DHCPD_STARTIP && g_state.ds_optreqip <= CONFIG_NETUTILS_DHCP_OPTION_ENDIP) { /* And verify that the lease has not already been taken or offered * (unless the lease/offer is expired, then the address is free game). */ lease = dhcpd_findbyipaddr(g_state.ds_optreqip); if (!lease || dhcpd_leaseexpired(lease)) { return TRUE; } } return FALSE;}/**************************************************************************** * Name: dhcpd_verifyreqleasetime ****************************************************************************/static inline boolean dhcpd_verifyreqleasetime(uint32 *leasetime){ uint32 tmp = g_state.ds_optleasetime; /* Did the client request a specific lease time? */ if (tmp != 0) { /* Yes.. Verify that the requested lease time is within a valid range */ if (tmp > CONFIG_NETUTILS_DHCPD_MAXLEASETIME) { tmp = CONFIG_NETUTILS_DHCPD_MAXLEASETIME; } else if (tmp < CONFIG_NETUTILS_DHCPD_MINLEASETIME) { tmp = CONFIG_NETUTILS_DHCPD_MINLEASETIME; } /* Return the clipped lease time */ *leasetime = tmp; return TRUE; } return FALSE;}/**************************************************************************** * Name: dhcpd_addoption ****************************************************************************/static int dhcpd_addoption(uint8 *option){ int offset; int len = 4; if (g_state.ds_optend) { offset = g_state.ds_outpacket.options - g_state.ds_optend; len = option[DHCPD_OPTION_LENGTH] + 2; /* Check if the option will fit into the options array */ if (offset + len + 1 < DHCPD_OPTIONS_SIZE) { /* Copy the option into the option array */ memcpy(g_state.ds_optend, option, len); g_state.ds_optend += len; *g_state.ds_optend = DHCP_OPTION_END; } } return len;}/**************************************************************************** * Name: dhcpd_addoption8 ****************************************************************************/static int dhcpd_addoption8(uint8 code, uint8 value){ uint8 option[3]; /* Construct the option sequence */ option[DHCPD_OPTION_CODE] = code; option[DHCPD_OPTION_LENGTH] = 1; option[DHCPD_OPTION_DATA] = value; /* Add the option sequence to the response */ return dhcpd_addoption(option);}/**************************************************************************** * Name: dhcpd_addoption32 ****************************************************************************/static int dhcpd_addoption32(uint8 code, uint32 value){ uint8 option[6]; /* Construct the option sequence */ option[DHCPD_OPTION_CODE] = code; option[DHCPD_OPTION_LENGTH] = 4; memcpy(&option[DHCPD_OPTION_DATA], &value, 4); /* Add the option sequence to the response */ return dhcpd_addoption(option);}/**************************************************************************** * Name: dhcpd_soclet ****************************************************************************/static inline int dhcpd_socket(void){ int sockfd;#if defined(HAVE_SO_REUSEADDR) || defined(HAVE_SO_BROADCAST) int optval; int ret;#endif /* Create a socket to listen for requests from DHCP clients */ sockfd = socket(PF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { dbg("socket failed: %d\n", errno); return ERROR; } /* Configure the socket */#ifdef HAVE_SO_REUSEADDR optval = 1; ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)); if (ret < 0) { dbg("setsockopt SO_REUSEADDR failed: %d\n", errno); close(sockfd); return ERROR; }#endif#ifdef HAVE_SO_BROADCAST optval = 1; ret = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (void*)&optval, sizeof(int)); if (ret < 0) { dbg("setsockopt SO_BROADCAST failed: %d\n", errno); close(sockfd); return ERROR; }#endif return sockfd;}/**************************************************************************** * Name: dhcpd_openresponder ****************************************************************************/static inline int dhcpd_openresponder(void){ struct sockaddr_in addr; int sockfd; int ret; /* Create a socket to listen for requests from DHCP clients */ sockfd = dhcpd_socket(); if (sockfd < 0) { dbg("socket failed: %d\n", errno); return ERROR; } /* Bind the socket to a local port. We have to use INADDRY_ANY to * receive broadcast messages. */ addr.sin_family = AF_INET; addr.sin_port = htons(DHCP_SERVER_PORT); addr.sin_addr.s_addr = g_state.ds_serverip; ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); if (ret < 0) { dbg("bind failed: %d\n", errno); close(sockfd); return ERROR; } return sockfd;}/**************************************************************************** * Name: dhcpd_initpacket ****************************************************************************/static void dhcpd_initpacket(uint8 mtype){ /* Set up the generic parts of the DHCP server message */ memset(&g_state.ds_outpacket, 0, sizeof(struct dhcpmsg_s)); g_state.ds_outpacket.op = DHCP_REPLY; g_state.ds_outpacket.htype = g_state.ds_inpacket.htype; g_state.ds_outpacket.hlen = g_state.ds_inpacket.hlen; memcpy(&g_state.ds_outpacket.xid, &g_state.ds_inpacket.xid, 4); memcpy(g_state.ds_outpacket.chaddr, g_state.ds_inpacket.chaddr, 16); if (g_state.ds_outpacket.giaddr) { g_state.ds_outpacket.flags = g_state.ds_inpacket.flags; } else { g_state.ds_outpacket.flags = 0; } memset(g_state.ds_outpacket.giaddr, 0, 4); /* Add the generic options */ memcpy(g_state.ds_outpacket.options, g_magiccookie, 4); g_state.ds_optend = &g_state.ds_outpacket.options[4]; *g_state.ds_optend = DHCP_OPTION_END; dhcpd_addoption8(DHCP_OPTION_MSG_TYPE, mtype); dhcpd_addoption32(DHCP_OPTION_SERVER_ID, g_state.ds_serverip);}/**************************************************************************** * Name: dhcpd_sendpacket ****************************************************************************/static int dhcpd_sendpacket(int bbroadcast){ struct sockaddr_in addr; in_addr_t ipaddr; int sockfd; int len; int ret = ERROR; /* Determine which address to respond to (or if we need to broadcast the response) */ if (bbroadcast) { ipaddr = INADDR_BROADCAST; } else if (memcmp(g_state.ds_outpacket.ciaddr, g_anyipaddr, 4) != 0) { memcpy(&ipaddr, g_state.ds_outpacket.ciaddr, 4); } else if (g_state.ds_outpacket.flags & HTONS(BOOTP_BROADCAST)) { ipaddr = INADDR_BROADCAST; } else { memcpy(&ipaddr, g_state.ds_outpacket.yiaddr, 4); } /* Create a socket to respond to send the packet to the client. We * cannot re-use the listener socket because it is not bound correctly */ sockfd = dhcpd_openresponder(); if (sockfd >= 0) { /* Then send the reponse to the DHCP client port at that address */ memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_port = HTONS(DHCP_CLIENT_PORT); addr.sin_addr.s_addr = ipaddr; /* Send the minimum sized packet that includes the END option */ len = (g_state.ds_optend - (uint8*)&g_state.ds_outpacket) + 1; ret = sendto(sockfd, &g_state.ds_outpacket, len, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); close(sockfd); } return ret;}/**************************************************************************** * Name: dhcpd_sendoffer ****************************************************************************/static inline int dhcpd_sendoffer(in_addr_t ipaddr, uint32 leasetime){ /* Initialize the outgoing packet */ dhcpd_initpacket(DHCPOFFER); /* Add the address offered to the client */ memcpy(g_state.ds_outpacket.yiaddr, &ipaddr, 4); /* Add the leasetime to the response options */ dhcpd_addoption32(DHCP_OPTION_LEASE_TIME, htonl(leasetime));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -