1 /*
2  * File      : dhcp_server.c
3  *             A simple DHCP server implementation
4  *
5  * COPYRIGHT (C) 2011-2018, Shanghai Real-Thread Technology Co., Ltd
6  * http://www.rt-thread.com
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without modification,
10  * are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  *    this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright notice,
15  *    this list of conditions and the following disclaimer in the documentation
16  *    and/or other materials provided with the distribution.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
21  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
23  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
25  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
28  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
29  * OF SUCH DAMAGE.
30  *
31  * Change Logs:
32  * Date           Author       Notes
33  * 2013-01-30     aozima       the first version
34  * 2013-08-08     aozima       support different network segments.
35  * 2015-01-30     bernard      release to RT-Thread RTOS.
36  * 2017-12-27     aozima       add [mac-ip] table support.
37  */
38 
39 #include <stdio.h>
40 #include <stdint.h>
41 #include <rtthread.h>
42 
43 #include <lwip/opt.h>
44 #include <lwip/sockets.h>
45 #include <lwip/inet_chksum.h>
46 #include <netif/etharp.h>
47 #include <netif/ethernetif.h>
48 #include <lwip/ip.h>
49 #include <lwip/init.h>
50 
51 #if (LWIP_VERSION) >= 0x02000000U
52     #include <lwip/prot/dhcp.h>
53 #endif
54 
55 /* DHCP server option */
56 
57 /* allocated client ip range */
58 #ifndef DHCPD_CLIENT_IP_MIN
59     #define DHCPD_CLIENT_IP_MIN     2
60 #endif
61 #ifndef DHCPD_CLIENT_IP_MAX
62     #define DHCPD_CLIENT_IP_MAX     254
63 #endif
64 
65 /* the DHCP server address */
66 #ifndef DHCPD_SERVER_IP
67     #define DHCPD_SERVER_IP "192.168.169.1"
68 #endif
69 
70 //#define DHCP_DEBUG_PRINTF
71 
72 #ifdef  DHCP_DEBUG_PRINTF
73     #define DEBUG_PRINTF        rt_kprintf("[DHCP] "); rt_kprintf
74 #else
75     #define DEBUG_PRINTF(...)
76 #endif /* DHCP_DEBUG_PRINTF */
77 
78 /* we need some routines in the DHCP of lwIP */
79 #undef  LWIP_DHCP
80 #define LWIP_DHCP   1
81 #include <lwip/dhcp.h>
82 
83 #ifndef DHCP_CLIENT_PORT
84 #define DHCP_CLIENT_PORT  68
85 #endif
86 
87 #ifndef DHCP_SERVER_PORT
88 #define DHCP_SERVER_PORT  67
89 #endif
90 
91 #ifndef ETHADDR32_COPY
92 #define ETHADDR32_COPY(dst, src)  SMEMCPY(dst, src, ETH_HWADDR_LEN)
93 #endif
94 
95 #ifndef ETHADDR16_COPY
96 #define ETHADDR16_COPY(dst, src)  SMEMCPY(dst, src, ETH_HWADDR_LEN)
97 #endif
98 
99 /* buffer size for receive DHCP packet */
100 #define BUFSZ               1024
101 
102 #ifndef MAC_ADDR_LEN
103     #define MAC_ADDR_LEN     6
104 #endif
105 
106 #ifndef MAC_TABLE_LEN
107     #define MAC_TABLE_LEN     4
108 #endif
109 
110 struct mac_addr_t
111 {
112     uint8_t add[MAC_ADDR_LEN];
113 };
114 
115 struct mac_ip_item_t
116 {
117     struct mac_addr_t mac_addr;
118     uint8_t ip_addr_3;
119 };
120 
_low_level_dhcp_send(struct netif * netif,const void * buffer,rt_size_t size)121 static rt_err_t _low_level_dhcp_send(struct netif *netif,
122                                      const void *buffer,
123                                      rt_size_t size)
124 {
125     struct pbuf *p;
126     struct eth_hdr *ethhdr;
127     struct ip_hdr *iphdr;
128     struct udp_hdr *udphdr;
129 
130     p = pbuf_alloc(PBUF_LINK,
131                    SIZEOF_ETH_HDR + sizeof(struct ip_hdr)
132                    + sizeof(struct udp_hdr) + size,
133                    PBUF_RAM);
134     if (p == RT_NULL) return -RT_ENOMEM;
135 
136     ethhdr = (struct eth_hdr *)p->payload;
137     iphdr  = (struct ip_hdr *)((char *)ethhdr + SIZEOF_ETH_HDR);
138     udphdr = (struct udp_hdr *)((char *)iphdr + sizeof(struct ip_hdr));
139 
140     ETHADDR32_COPY(&ethhdr->dest, (struct eth_addr *)&ethbroadcast);
141     ETHADDR16_COPY(&ethhdr->src, netif->hwaddr);
142     ethhdr->type = PP_HTONS(ETHTYPE_IP);
143 
144     iphdr->src.addr  = 0x00000000; /* src: 0.0.0.0 */
145     iphdr->dest.addr = 0xFFFFFFFF; /* src: 255.255.255.255 */
146 
147     IPH_VHL_SET(iphdr, 4, IP_HLEN / 4);
148     IPH_TOS_SET(iphdr, 0x00);
149     IPH_LEN_SET(iphdr, htons(IP_HLEN + sizeof(struct udp_hdr) + size));
150     IPH_ID_SET(iphdr, htons(2));
151     IPH_OFFSET_SET(iphdr, 0);
152     IPH_TTL_SET(iphdr, 255);
153     IPH_PROTO_SET(iphdr, IP_PROTO_UDP);
154     IPH_CHKSUM_SET(iphdr, 0);
155     IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
156 
157     udphdr->src = htons(DHCP_SERVER_PORT);
158     udphdr->dest = htons(DHCP_CLIENT_PORT);
159     udphdr->len = htons(sizeof(struct udp_hdr) + size);
160     udphdr->chksum = 0;
161 
162     memcpy((char *)udphdr + sizeof(struct udp_hdr),
163            buffer, size);
164 
165     netif->linkoutput(netif, p);
166     pbuf_free(p);
167 
168     return RT_EOK;
169 }
170 
get_ip(struct mac_addr_t * p_mac_addr)171 static uint8_t get_ip(struct mac_addr_t *p_mac_addr)
172 {
173     static uint8_t next_client_ip = DHCPD_CLIENT_IP_MIN;
174     static struct mac_ip_item_t mac_table[MAC_TABLE_LEN];
175     static int offset = 0;
176 
177     struct mac_addr_t bad_mac;
178     int i;
179     uint8_t ip_addr_3;
180 
181     rt_memset(&bad_mac, 0, sizeof(bad_mac));
182     if (!rt_memcmp(&bad_mac, p_mac_addr, sizeof(bad_mac)))
183     {
184         DEBUG_PRINTF("mac address all zero");
185         ip_addr_3 = DHCPD_CLIENT_IP_MAX;
186         goto _return;
187     }
188 
189     rt_memset(&bad_mac, 0xFF, sizeof(bad_mac));
190     if (!rt_memcmp(&bad_mac, p_mac_addr, sizeof(bad_mac)))
191     {
192         DEBUG_PRINTF("mac address all one");
193         ip_addr_3 = DHCPD_CLIENT_IP_MAX;
194         goto _return;
195     }
196 
197     for (i = 0; i < MAC_TABLE_LEN; i++)
198     {
199         if (!rt_memcmp(&mac_table[i].mac_addr, p_mac_addr, sizeof(bad_mac)))
200         {
201             //use old ip
202             ip_addr_3 = mac_table[i].ip_addr_3;
203             DEBUG_PRINTF("return old ip: %d\n", (int)ip_addr_3);
204             goto _return;
205         }
206     }
207 
208     /* add new ip */
209     mac_table[offset].mac_addr = *p_mac_addr;
210     mac_table[offset].ip_addr_3  = next_client_ip;
211     ip_addr_3 = mac_table[offset].ip_addr_3 ;
212 
213     offset++;
214     if (offset >= MAC_TABLE_LEN)
215         offset = 0;
216 
217     next_client_ip++;
218     if (next_client_ip > DHCPD_CLIENT_IP_MAX)
219         next_client_ip = DHCPD_CLIENT_IP_MIN;
220 
221     DEBUG_PRINTF("create new ip: %d\n", (int)ip_addr_3);
222     DEBUG_PRINTF("next_client_ip %d\n", next_client_ip);
223 
224 _return:
225     return ip_addr_3;
226 }
227 
dhcpd_thread_entry(void * parameter)228 static void dhcpd_thread_entry(void *parameter)
229 {
230     struct netif *netif = RT_NULL;
231     int sock;
232     int bytes_read;
233     char *recv_data;
234     rt_uint32_t addr_len;
235     struct sockaddr_in server_addr, client_addr;
236     struct dhcp_msg *msg;
237     int optval = 1;
238     struct mac_addr_t mac_addr;
239     uint8_t DHCPD_SERVER_IPADDR0, DHCPD_SERVER_IPADDR1, DHCPD_SERVER_IPADDR2, DHCPD_SERVER_IPADDR3;
240 
241     /* get ethernet interface. */
242     netif = (struct netif *) parameter;
243     RT_ASSERT(netif != RT_NULL);
244 
245     /* our DHCP server information */
246     {
247 #if (LWIP_VERSION) >= 0x02000000U
248         ip4_addr_t addr;
249         ip4addr_aton(DHCPD_SERVER_IP, &addr);
250 #else
251         struct ip_addr addr;
252         ipaddr_aton(DHCPD_SERVER_IP, &addr);
253 #endif /* LWIP_VERSION */
254 
255         DHCPD_SERVER_IPADDR0 = (ntohl(addr.addr) >> 24) & 0xFF;
256         DHCPD_SERVER_IPADDR1 = (ntohl(addr.addr) >> 16) & 0xFF;
257         DHCPD_SERVER_IPADDR2 = (ntohl(addr.addr) >>  8) & 0xFF;
258         DHCPD_SERVER_IPADDR3 = (ntohl(addr.addr) >>  0) & 0xFF;
259     }
260     DEBUG_PRINTF("DHCP server IP: %d.%d.%d.%d  client IP: %d.%d.%d.%d-%d\n",
261                  DHCPD_SERVER_IPADDR0, DHCPD_SERVER_IPADDR1,
262                  DHCPD_SERVER_IPADDR2, DHCPD_SERVER_IPADDR3,
263                  DHCPD_SERVER_IPADDR0, DHCPD_SERVER_IPADDR1,
264                  DHCPD_SERVER_IPADDR2, DHCPD_CLIENT_IP_MIN, DHCPD_CLIENT_IP_MAX);
265 
266     /* allocate buffer for receive */
267     recv_data = rt_malloc(BUFSZ);
268     if (recv_data == RT_NULL)
269     {
270         /* No memory */
271         DEBUG_PRINTF("Out of memory\n");
272         return;
273     }
274 
275     /* create a socket with UDP */
276     if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
277     {
278         DEBUG_PRINTF("create socket failed, errno = %d\n", errno);
279         rt_free(recv_data);
280         return;
281     }
282 
283     /* set to receive broadcast packet */
284     setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval));
285 
286     /* initialize server address */
287     server_addr.sin_family = AF_INET;
288     server_addr.sin_port = htons(DHCP_SERVER_PORT);
289     server_addr.sin_addr.s_addr = INADDR_ANY;
290     rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
291 
292     /* bind socket to the server address */
293     if (bind(sock, (struct sockaddr *)&server_addr,
294              sizeof(struct sockaddr)) == -1)
295     {
296         /* bind failed. */
297         DEBUG_PRINTF("bind server address failed, errno=%d\n", errno);
298         closesocket(sock);
299         rt_free(recv_data);
300         return;
301     }
302 
303     addr_len = sizeof(struct sockaddr);
304     DEBUG_PRINTF("DHCP server listen on port %d...\n", DHCP_SERVER_PORT);
305 
306     while (1)
307     {
308         bytes_read = recvfrom(sock, recv_data, BUFSZ - 1, 0,
309                               (struct sockaddr *)&client_addr, (socklen_t *)&addr_len);
310         if (bytes_read <= 0)
311         {
312             closesocket(sock);
313             rt_free(recv_data);
314             return;
315         }
316         else if (bytes_read < DHCP_MSG_LEN)
317         {
318             DEBUG_PRINTF("packet too short, wait for next!\n");
319             continue;
320         }
321 
322         msg = (struct dhcp_msg *)recv_data;
323         /* check message type to make sure we can handle it */
324         if ((msg->op != DHCP_BOOTREQUEST) || (msg->cookie != PP_HTONL(DHCP_MAGIC_COOKIE)))
325         {
326             continue;
327         }
328 
329         memcpy(mac_addr.add, msg->chaddr, MAC_ADDR_LEN);
330 
331         /* handler. */
332         {
333             uint8_t *dhcp_opt;
334             uint8_t option;
335             uint8_t length;
336 
337             uint8_t message_type = 0;
338             uint8_t finished = 0;
339             uint32_t request_ip  = 0;
340 
341             uint8_t client_ip_3;
342 
343             client_ip_3 = get_ip(&mac_addr);
344 
345             dhcp_opt = (uint8_t *)msg + DHCP_OPTIONS_OFS;
346             while (finished == 0)
347             {
348                 option = *dhcp_opt;
349                 length = *(dhcp_opt + 1);
350 
351                 switch (option)
352                 {
353                 case DHCP_OPTION_REQUESTED_IP:
354                     request_ip = *(dhcp_opt + 2) << 24 | *(dhcp_opt + 3) << 16
355                                  | *(dhcp_opt + 4) << 8 | *(dhcp_opt + 5);
356                     break;
357 
358                 case DHCP_OPTION_END:
359                     finished = 1;
360                     break;
361 
362                 case DHCP_OPTION_MESSAGE_TYPE:
363                     message_type = *(dhcp_opt + 2);
364                     break;
365 
366                 default:
367                     break;
368                 } /* switch(option) */
369 
370                 dhcp_opt += (2 + length);
371             }
372 
373             /* reply. */
374             dhcp_opt = (uint8_t *)msg + DHCP_OPTIONS_OFS;
375 
376             /* check. */
377             if (request_ip)
378             {
379                 uint32_t client_ip = DHCPD_SERVER_IPADDR0 << 24 | DHCPD_SERVER_IPADDR1 << 16
380                                      | DHCPD_SERVER_IPADDR2 << 8 | client_ip_3;
381 
382                 DEBUG_PRINTF("message_type: %d, request_ip: %08X, client_ip: %08X.\n", message_type, request_ip, client_ip);
383 
384                 if (request_ip != client_ip)
385                 {
386                     *dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE;
387                     *dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE_LEN;
388                     *dhcp_opt++ = DHCP_NAK;
389                     *dhcp_opt++ = DHCP_OPTION_END;
390 
391                     DEBUG_PRINTF("requested IP invalid, reply DHCP_NAK\n");
392 
393                     if (netif != RT_NULL)
394                     {
395                         int send_byte = (dhcp_opt - (uint8_t *)msg);
396                         _low_level_dhcp_send(netif, msg, send_byte);
397                         DEBUG_PRINTF("DHCP server send %d byte\n", send_byte);
398                     }
399 
400                     continue;
401                 }
402             }
403 
404             if (message_type == DHCP_DISCOVER)
405             {
406                 DEBUG_PRINTF("request DHCP_DISCOVER\n");
407                 DEBUG_PRINTF("reply   DHCP_OFFER\n");
408 
409                 // DHCP_OPTION_MESSAGE_TYPE
410                 *dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE;
411                 *dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE_LEN;
412                 *dhcp_opt++ = DHCP_OFFER;
413 
414                 // DHCP_OPTION_SERVER_ID
415                 *dhcp_opt++ = DHCP_OPTION_SERVER_ID;
416                 *dhcp_opt++ = 4;
417                 *dhcp_opt++ = DHCPD_SERVER_IPADDR0;
418                 *dhcp_opt++ = DHCPD_SERVER_IPADDR1;
419                 *dhcp_opt++ = DHCPD_SERVER_IPADDR2;
420                 *dhcp_opt++ = DHCPD_SERVER_IPADDR3;
421 
422                 // DHCP_OPTION_LEASE_TIME
423                 *dhcp_opt++ = DHCP_OPTION_LEASE_TIME;
424                 *dhcp_opt++ = 4;
425                 *dhcp_opt++ = 0x00;
426                 *dhcp_opt++ = 0x01;
427                 *dhcp_opt++ = 0x51;
428                 *dhcp_opt++ = 0x80;
429             }
430             else if (message_type == DHCP_REQUEST)
431             {
432                 DEBUG_PRINTF("request DHCP_REQUEST\n");
433                 DEBUG_PRINTF("reply   DHCP_ACK\n");
434 
435                 // DHCP_OPTION_MESSAGE_TYPE
436                 *dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE;
437                 *dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE_LEN;
438                 *dhcp_opt++ = DHCP_ACK;
439 
440                 // DHCP_OPTION_SERVER_ID
441                 *dhcp_opt++ = DHCP_OPTION_SERVER_ID;
442                 *dhcp_opt++ = 4;
443                 *dhcp_opt++ = DHCPD_SERVER_IPADDR0;
444                 *dhcp_opt++ = DHCPD_SERVER_IPADDR1;
445                 *dhcp_opt++ = DHCPD_SERVER_IPADDR2;
446                 *dhcp_opt++ = DHCPD_SERVER_IPADDR3;
447 
448                 // DHCP_OPTION_SUBNET_MASK
449                 *dhcp_opt++ = DHCP_OPTION_SUBNET_MASK;
450                 *dhcp_opt++ = 4;
451                 *dhcp_opt++ = 0xFF;
452                 *dhcp_opt++ = 0xFF;
453                 *dhcp_opt++ = 0xFF;
454                 *dhcp_opt++ = 0x00;
455 
456 #ifdef DHCPD_USING_ROUTER
457                 // DHCP_OPTION_ROUTER
458                 *dhcp_opt++ = DHCP_OPTION_ROUTER;
459                 *dhcp_opt++ = 4;
460                 *dhcp_opt++ = DHCPD_SERVER_IPADDR0;
461                 *dhcp_opt++ = DHCPD_SERVER_IPADDR1;
462                 *dhcp_opt++ = DHCPD_SERVER_IPADDR2;
463                 *dhcp_opt++ = 1;
464 #endif
465 
466                 // DHCP_OPTION_DNS_SERVER, use the default DNS server address in lwIP
467                 *dhcp_opt++ = DHCP_OPTION_DNS_SERVER;
468                 *dhcp_opt++ = 4;
469 
470 #ifndef DHCP_DNS_SERVER_IP
471                 *dhcp_opt++ = DHCPD_SERVER_IPADDR0;
472                 *dhcp_opt++ = DHCPD_SERVER_IPADDR1;
473                 *dhcp_opt++ = DHCPD_SERVER_IPADDR2;
474                 *dhcp_opt++ = 1;
475 #else
476                 {
477 #if (LWIP_VERSION) >= 0x02000000U
478                     ip4_addr_t dns_addr;
479 #else
480                     struct ip_addr dns_addr;
481 #endif /* LWIP_VERSION */
482                     ip4addr_aton(DHCP_DNS_SERVER_IP, &dns_addr);
483 
484                     *dhcp_opt++ = (ntohl(dns_addr.addr) >> 24) & 0xFF;
485                     *dhcp_opt++ = (ntohl(dns_addr.addr) >> 16) & 0xFF;
486                     *dhcp_opt++ = (ntohl(dns_addr.addr) >>  8) & 0xFF;
487                     *dhcp_opt++ = (ntohl(dns_addr.addr) >>  0) & 0xFF;
488                 }
489 #endif
490 
491                 // DHCP_OPTION_LEASE_TIME
492                 *dhcp_opt++ = DHCP_OPTION_LEASE_TIME;
493                 *dhcp_opt++ = 4;
494                 *dhcp_opt++ = 0x00;
495                 *dhcp_opt++ = 0x01;
496                 *dhcp_opt++ = 0x51;
497                 *dhcp_opt++ = 0x80;
498             }
499             else
500             {
501                 DEBUG_PRINTF("un handle message:%d\n", message_type);
502             }
503 
504             // append DHCP_OPTION_END
505             *dhcp_opt++ = DHCP_OPTION_END;
506 
507             /* send reply. */
508             if ((message_type == DHCP_DISCOVER) || (message_type == DHCP_REQUEST))
509             {
510                 msg->op = DHCP_BOOTREPLY;
511                 IP4_ADDR(&msg->yiaddr,
512                          DHCPD_SERVER_IPADDR0, DHCPD_SERVER_IPADDR1,
513                          DHCPD_SERVER_IPADDR2, client_ip_3);
514 
515                 client_addr.sin_addr.s_addr = INADDR_BROADCAST;
516 
517                 if (netif != RT_NULL)
518                 {
519                     int send_byte = (dhcp_opt - (uint8_t *)msg);
520                     _low_level_dhcp_send(netif, msg, send_byte);
521                     DEBUG_PRINTF("DHCP server send %d byte\n", send_byte);
522                 }
523             }
524         } /* handler. */
525     }
526 }
527 
dhcpd_start(const char * netif_name)528 void dhcpd_start(const char *netif_name)
529 {
530     rt_thread_t thread;
531     struct netif *netif = netif_list;
532 
533     if (strlen(netif_name) > sizeof(netif->name))
534     {
535         rt_kprintf("network interface name too long!\r\n");
536         return;
537     }
538     while (netif != RT_NULL)
539     {
540         if (strncmp(netif_name, netif->name, sizeof(netif->name)) == 0)
541             break;
542 
543         netif = netif->next;
544         if (netif == RT_NULL)
545         {
546             rt_kprintf("network interface: %s not found!\r\n", netif_name);
547             return;
548         }
549     }
550 
551     if (1)
552     {
553         extern void set_if(const char *netif_name, const char *ip_addr, const char *gw_addr, const char *nm_addr);
554 
555         dhcp_stop(netif);
556 
557         set_if(netif_name, DHCPD_SERVER_IP, "0.0.0.0", "255.255.255.0");
558 
559         netif_set_up(netif);
560     }
561 
562     thread = rt_thread_create("dhcpd",
563                               dhcpd_thread_entry, netif,
564                               1024,
565                               RT_THREAD_PRIORITY_MAX - 3,
566                               2);
567     if (thread != RT_NULL)
568     {
569         rt_thread_startup(thread);
570     }
571 }
572