📄 dhcpd.c
字号:
/**************************************************************************** * netutils/dhcpd/dhcpd.c * * Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <spudmonkey@racsa.co.cr> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************//**************************************************************************** * Included Files ****************************************************************************/#ifdef CONFIG_NETUTILS_DHCPD_HOST# include <stdio.h>typedef unsigned char uint8;typedef unsigned short uint16;typedef unsigned int uint32;typedef unsigned char boolean;# define HTONS(a) htons(a)# define HTONL(a) htonl(a)# define dbg(...) printf(__VA_ARGS__)# define vdbg(...) printf(__VA_ARGS__)# define TRUE (1)# define FALSE (0)# define ERROR (-1)# define OK (0)#else# include <nuttx/config.h># include <debug.h># include <net/uip/dhcpd.h>#endif#include <sys/types.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <string.h>#include <unistd.h>#include <time.h>#include <errno.h>#include <net/if.h>#include <netinet/in.h>#include <arpa/inet.h>/**************************************************************************** * Private Data ****************************************************************************/#define DHCP_SERVER_PORT 67#define DHCP_CLIENT_PORT 68/* Option codes understood in this file *//* Code Data Description *//* Length */#define DHCP_OPTION_PAD 1 /* 1 Pad */#define DHCP_OPTION_REQ_IPADDR 50 /* 4 Requested IP Address */#define DHCP_OPTION_LEASE_TIME 51 /* 4 IP address lease time */#define DHCP_OPTION_OVERLOAD 52 /* 1 Option overload */#define DHCP_OPTION_MSG_TYPE 53 /* 1 DHCP message type */#define DHCP_OPTION_SERVER_ID 54 /* 4 Server identifier */#define DHCP_OPTION_END 255 /* 0 End *//* Values for the dhcp msg 'op' field */#define DHCP_REQUEST 1#define DHCP_REPLY 2/* DHCP message types understood in this file */#define DHCPDISCOVER 1 /* Received from client only */#define DHCPOFFER 2 /* Sent from server only */#define DHCPREQUEST 3 /* Received from client only */#define DHCPDECLINE 4 /* Received from client only */#define DHCPACK 5 /* Sent from server only */#define DHCPNAK 6 /* Sent from server only */#define DHCPRELEASE 7 /* Received from client only */#define DHCPINFORM 8 /* Not used *//* The form of an option is: * code - 1 byte * length - 1 byte * data - variable number of bytes */#define DHCPD_OPTION_CODE 0#define DHCPD_OPTION_LENGTH 1#define DHCPD_OPTION_DATA 2/* Size of options in DHCP message */#define DHCPD_OPTIONS_SIZE 312/* Values for htype and hlen field */#define DHCP_HTYPE_ETHERNET 1#define DHCP_HLEN_ETHERNET 6/* Values for flags field */#define BOOTP_BROADCAST 0x8000/* 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 */#define DHCPD_OPTION_FIELD 0#define DHCPD_FILE_FIELD 1#define DHCPD_SNAME_FIELD 2#ifndef CONFIG_NETUTILS_DHCPD_LEASETIME# define CONFIG_NETUTILS_DHCPD_LEASETIME (60*60*24*10) /* 10 days */# undef CONFIG_NETUTILS_DHCPD_MINLEASETIME# undef CONFIG_NETUTILS_DHCPD_MAXLEASETIME#endif#ifndef CONFIG_NETUTILS_DHCPD_MINLEASETIME# define CONFIG_NETUTILS_DHCPD_MINLEASETIME (60*60*24*1) /* 1 days */#endif#ifndef CONFIG_NETUTILS_DHCPD_MAXLEASETIME# define CONFIG_NETUTILS_DHCPD_MAXLEASETIME (60*60*24*30) /* 30 days */#endif#ifndef CONFIG_NETUTILS_DHCPD_INTERFACE# define CONFIG_NETUTILS_DHCPD_INTERFACE "eth0"#endif#ifndef CONFIG_NETUTILS_DHCPD_MAXLEASES# define CONFIG_NETUTILS_DHCPD_MAXLEASES 16#endif#ifndef CONFIG_NETUTILS_DHCPD_STARTIP# define CONFIG_NETUTILS_DHCPD_STARTIP (10<<24|0<<16|0<<16|2)#endif#undef CONFIG_NETUTILS_DHCP_OPTION_ENDIP#define CONFIG_NETUTILS_DHCP_OPTION_ENDIP \ (CONFIG_NETUTILS_DHCPD_STARTIP + CONFIG_NETUTILS_DHCPD_MAXLEASES - 1)#ifndef CONFIG_NETUTILS_DHCPD_OFFERTIME# define CONFIG_NETUTILS_DHCPD_OFFERTIME (60*60) /* 1 hour */#endif#ifndef CONFIG_NETUTILS_DHCPD_DECLINETIME# define CONFIG_NETUTILS_DHCPD_DECLINETIME (60*60) /* 1 hour */#endif#undef HAVE_LEASE_TIME#if defined(CONFIG_NETUTILS_DHCPD_HOST) || !defined(CONFIG_DISABLE_POSIX_TIMERS)# define HAVE_LEASE_TIME 1#endif/**************************************************************************** * Private Types ****************************************************************************//* This structure describes one element in the lease table. There is one slot * in the lease table for each assign-able IP address (hence, the IP address * itself does not have to be in the table. */struct lease_s{ uint8 mac[DHCP_HLEN_ETHERNET]; /* MAC address (network order) -- could be larger! */ boolean allocated; /* true: IP address is allocated */#ifdef HAVE_LEASE_TIME time_t expiry; /* Lease expiration time (seconds past Epoch) */#endif};struct dhcpmsg_s{ uint8 op; uint8 htype; uint8 hlen; uint8 hops; uint8 xid[4]; uint16 secs; uint16 flags; uint8 ciaddr[4]; uint8 yiaddr[4]; uint8 siaddr[4]; uint8 giaddr[4]; uint8 chaddr[16];#ifndef CONFIG_NET_DHCP_LIGHT uint8 sname[64]; uint8 file[128];#endif uint8 options[312];};struct dhcpd_state_s{ /* Server configuration */ in_addr_t ds_serverip; /* The server IP address */ /* Message buffers */ struct dhcpmsg_s ds_inpacket; /* Holds the incoming DHCP client message */ struct dhcpmsg_s ds_outpacket; /* Holds the outgoing DHCP server message */ /* Parsed options from the incoming DHCP client message */ uint8 ds_optmsgtype; /* Incoming DHCP message type */ in_addr_t ds_optreqip; /* Requested IP address (host order) */ in_addr_t ds_optserverip; /* Serverip IP address (host order) */ time_t ds_optleasetime; /* Requested lease time (host order) */ /* End option pointer for outgoing DHCP server message */ uint8 *ds_optend; /* Leases */ struct lease_s ds_leases[CONFIG_NETUTILS_DHCPD_MAXLEASES];};/**************************************************************************** * Private Data ****************************************************************************/static const uint8 g_magiccookie[4] = {99, 130, 83, 99};static const uint8 g_anyipaddr[4] = {0, 0, 0, 0};static struct dhcpd_state_s g_state;/**************************************************************************** * Private Functions ****************************************************************************//**************************************************************************** * Name: dhcpd_time ****************************************************************************/#ifdef CONFIG_NETUTILS_DHCPD_HOST# define dhcpd_time() time(0)#elif defined(HAVE_LEASE_TIME)static time_t dhcpd_time(void){ struct timespec time; time_t ret = 0; if (clock_gettime(CLOCK_REALTIME, &time) == OK) { ret = time.tv_sec; } return ret;}#else# define dhcpd_time() (0)#endif/**************************************************************************** * Name: dhcpd_leaseexpired ****************************************************************************/#ifdef HAVE_LEASE_TIMEstatic inline boolean dhcpd_leaseexpired(struct lease_s *lease){ if (lease->expiry < dhcpd_time()) { return FALSE; } else { memset(lease, 0, sizeof(struct lease_s)); return TRUE; }}#else# define dhcpd_leaseexpired(lease) (FALSE)#endif/**************************************************************************** * Name: dhcpd_setlease ****************************************************************************/struct lease_s *dhcpd_setlease(const uint8 *mac, in_addr_t ipaddr, time_t expiry){ int ndx = ntohl(ipaddr) - CONFIG_NETUTILS_DHCPD_STARTIP; struct lease_s *ret = NULL; if (ndx >= 0 && ndx < CONFIG_NETUTILS_DHCPD_MAXLEASES) { ret = &g_state.ds_leases[ndx]; memcpy(ret->mac, mac, DHCP_HLEN_ETHERNET); ret->allocated = TRUE;#ifdef HAVE_LEASE_TIME ret->expiry = dhcpd_time() + expiry;#endif } return ret;}/**************************************************************************** * Name: dhcp_leaseipaddr ****************************************************************************/static inline in_addr_t dhcp_leaseipaddr( struct lease_s *lease){ return htonl((g_state.ds_leases - lease)/sizeof(struct lease_s) + CONFIG_NETUTILS_DHCPD_STARTIP);}/**************************************************************************** * Name: dhcpd_findbymac ****************************************************************************/static struct lease_s *dhcpd_findbymac(const uint8 *mac){ int i; for (i = 0; i < CONFIG_NETUTILS_DHCPD_MAXLEASES; i++) { if (memcmp(g_state.ds_leases[i].mac, mac, DHCP_HLEN_ETHERNET) == 0) { return &(g_state.ds_leases[i]); } } return NULL;}/**************************************************************************** * Name: dhcpd_findbyipaddr ****************************************************************************/static struct lease_s *dhcpd_findbyipaddr(in_addr_t ipaddr){ if (ipaddr >= CONFIG_NETUTILS_DHCPD_STARTIP && ipaddr <= CONFIG_NETUTILS_DHCP_OPTION_ENDIP) { struct lease_s *lease = &g_state.ds_leases[ipaddr - CONFIG_NETUTILS_DHCPD_STARTIP]; if (lease->allocated > 0) { return lease; } } return NULL;}/**************************************************************************** * Name: dhcpd_allocipaddr ****************************************************************************/in_addr_t dhcpd_allocipaddr(void){ struct lease_s *lease = NULL; in_addr_t ipaddr; ipaddr = CONFIG_NETUTILS_DHCPD_STARTIP; for (; ipaddr <= CONFIG_NETUTILS_DHCP_OPTION_ENDIP; ipaddr++) { if ((ipaddr & 0xff) == 0 || (ipaddr & 0xff) == 0xff) { continue; } lease = dhcpd_findbyipaddr(ipaddr); if ((!lease || dhcpd_leaseexpired(lease))) {#warning "FIXME: Should check if anything responds to an ARP request or ping"#warning " to verify that there is no other user of this IP address" memset(g_state.ds_leases[ipaddr - CONFIG_NETUTILS_DHCPD_STARTIP].mac, 0, DHCP_HLEN_ETHERNET); g_state.ds_leases[ipaddr - CONFIG_NETUTILS_DHCPD_STARTIP].allocated = TRUE;#ifdef HAVE_LEASE_TIME g_state.ds_leases[ipaddr - CONFIG_NETUTILS_DHCPD_STARTIP].expiry = dhcpd_time() + CONFIG_NETUTILS_DHCPD_OFFERTIME;#endif return ntohl(ipaddr); } } return 0;}/**************************************************************************** * Name: dhcpd_parseoptions ****************************************************************************/static inline boolean dhcpd_parseoptions(void){ uint32 tmp; uint8 *ptr; uint8 overloaded; uint8 currfield; int optlen; int remaining; /* Verify that the option field starts with a valid magic number */ ptr = g_state.ds_inpacket.options; if (memcmp(ptr, g_magiccookie, 4) != 0) { /* Bad magic number... skip g_state.ds_outpacket */ dbg("Bad magic: %d,%d,%d,%d\n", ptr[0], ptr[1], ptr[2], ptr[3]); return FALSE; } /* Set up to parse the options */ ptr += 4; remaining = DHCPD_OPTIONS_SIZE - 4; overloaded = DHCPD_OPTION_FIELD; currfield = DHCPD_OPTION_FIELD; /* Set all options to the default value */ g_state.ds_optmsgtype = 0; /* Incoming DHCP message type */ g_state.ds_optreqip = 0; /* Requested IP address (host order) */ g_state.ds_optserverip = 0; /* Serverip IP address (host order) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -