xref: /aosp_15_r20/external/toybox/toys/pending/dhcpd.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1 /* dhcpd.c - DHCP server for dynamic network configuration.
2  *
3  * Copyright 2013 Madhur Verma <[email protected]>
4  * Copyright 2013 Kyungwan Han <[email protected]>
5  * Copyright 2015 Yeongdeok Suh <[email protected]>
6  *
7  * No Standard
8 USE_DHCPD(NEWTOY(dhcpd, ">1P#<0>65535fi:S46[!46]", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
9 
10 config DHCPD
11   bool "dhcpd"
12   default n
13   help
14    usage: dhcpd [-46fS] [-i IFACE] [-P N] [CONFFILE]
15 
16     -f    Run in foreground
17     -i Interface to use
18     -S    Log to syslog too
19     -P N  Use port N (default ipv4 67, ipv6 547)
20     -4, -6    Run as a DHCPv4 or DHCPv6 server
21 
22 config DEBUG_DHCP
23   bool "debugging messeges ON/OFF"
24   default n
25   depends on DHCPD
26 */
27 
28 /*
29  * TODO
30  * - Working as an relay agent
31  * - Rapid commit option support
32  * - Additional packet options (commented on the middle of sources)
33  * - Create common modules
34  */
35 
36 #define FOR_dhcpd
37 
38 #include "toys.h"
39 #include <linux/sockios.h>
40 #include <linux/if_ether.h>
41 
42 // Todo: headers not in posix
43 #include <netinet/ip.h>
44 #include <netinet/ip6.h>
45 #include <netinet/udp.h>
46 #include <netpacket/packet.h>
47 
48 #if CFG_DEBUG_DHCP==1
49 # define dbg(fmt, arg...)   printf(fmt, ##arg)
50 #else
51 # define dbg(fmt, arg...)
52 #endif
53 
54 #define LOG_SILENT          0x0
55 #define LOG_CONSOLE         0x1
56 #define LOG_SYSTEM          0x2
57 
58 #define DHCP_MAGIC          0x63825363
59 
60 #define DHCPDISCOVER        1
61 #define DHCPOFFER           2
62 #define DHCPREQUEST         3
63 #define DHCPDECLINE         4
64 #define DHCPACK             5
65 #define DHCPNAK             6
66 #define DHCPRELEASE         7
67 #define DHCPINFORM          8
68 
69 #define DHCP6SOLICIT        1
70 #define DHCP6ADVERTISE      2   // server -> client
71 #define DHCP6REQUEST        3
72 #define DHCP6CONFIRM        4
73 #define DHCP6RENEW          5
74 #define DHCP6REBIND         6
75 #define DHCP6REPLY          7   // server -> client
76 #define DHCP6RELEASE        8
77 #define DHCP6DECLINE        9
78 #define DHCP6RECONFIGURE    10  // server -> client
79 #define DHCP6INFOREQUEST    11
80 #define DHCP6RELAYFLOW      12  // relay -> relay/server
81 #define DHCP6RELAYREPLY     13  // server/relay -> relay
82 
83 #define DHCP_NUM8           (1<<8)
84 #define DHCP_NUM16          (1<<9)
85 #define DHCP_NUM32          DHCP_NUM16 | DHCP_NUM8
86 #define DHCP_STRING         (1<<10)
87 #define DHCP_STRLST         (1<<11)
88 #define DHCP_IP             (1<<12)
89 #define DHCP_IPLIST         (1<<13)
90 #define DHCP_IPPLST         (1<<14)
91 #define DHCP_STCRTS         (1<<15)
92 
93 // DHCP option codes (partial list). See RFC 2132 and
94 #define DHCP_OPT_PADDING                          0x00
95 #define DHCP_OPT_HOST_NAME          DHCP_STRING | 0x0c // either client informs server or server gives name to client
96 #define DHCP_OPT_REQUESTED_IP       DHCP_IP     | 0x32 // sent by client if specific IP is wanted
97 #define DHCP_OPT_LEASE_TIME         DHCP_NUM32  | 0x33
98 #define DHCP_OPT_OPTION_OVERLOAD                  0x34
99 #define DHCP_OPT_MESSAGE_TYPE       DHCP_NUM8   | 0x35
100 #define DHCP_OPT_SERVER_ID          DHCP_IP     | 0x36 // by default server's IP
101 #define DHCP_OPT_PARAM_REQ          DHCP_STRING | 0x37 // list of options client wants
102 #define DHCP_OPT_END                              0xff
103 
104 // DHCPv6 option codes (partial). See RFC 3315
105 #define DHCP6_OPT_CLIENTID      1
106 #define DHCP6_OPT_SERVERID      2
107 #define DHCP6_OPT_IA_NA         3
108 #define DHCP6_OPT_IA_ADDR       5
109 #define DHCP6_OPT_ORO           6
110 #define DHCP6_OPT_PREFERENCE    7
111 #define DHCP6_OPT_ELAPSED_TIME  8
112 #define DHCP6_OPT_RELAY_MSG     9
113 #define DHCP6_OPT_STATUS_CODE   13
114 #define DHCP6_OPT_IA_PD         25
115 #define DHCP6_OPT_IA_PREFIX     26
116 
117 #define DHCP6_STATUS_SUCCESS        0
118 #define DHCP6_STATUS_NOADDRSAVAIL   2
119 
120 #define DHCP6_DUID_LLT    1
121 #define DHCP6_DUID_EN     2
122 #define DHCP6_DUID_LL     3
123 #define DHCP6_DUID_UUID   4
124 
125 GLOBALS(
126   char *i;
127   long p;
128 )
129 
130 struct config_keyword {
131   char *keyword;
132   int (*handler)(const char *str, void *var);
133   void *var;
134   char *def;
135 };
136 
137 typedef struct dhcp_msg_s {
138   char op, htype, hlen, hops;
139   unsigned xid;
140   unsigned short secs, flags;
141   unsigned ciaddr, yiaddr, nsiaddr, ngiaddr;
142   char chaddr[16], sname[64], file[128];
143   unsigned cookie;
144   char options[308];
145 } dhcp_msg_t;
146 
147 typedef struct dhcp6_msg_s {
148   char msgtype, transaction_id[3], options[524];
149 } dhcp6_msg_t;
150 
151 typedef struct __attribute__((packed)) dhcp_raw_s {
152   struct iphdr iph;
153   struct udphdr udph;
154   dhcp_msg_t dhcp;
155 } dhcp_raw_t;
156 
157 typedef struct __attribute__((packed)) dhcp6_raw_s {
158   struct ip6_hdr iph;
159   struct udphdr udph;
160   dhcp6_msg_t dhcp6;
161 } dhcp6_raw_t;
162 
163 typedef struct static_lease_s {
164   struct static_lease_s *next;
165   unsigned nip;
166   int mac[6];
167 } static_lease;
168 
169 typedef struct static_lease6_s {
170   struct static_lease6_s *next;
171   unsigned short duid_len, ia_type;
172   unsigned iaid;
173   char nip6[16], duid[20];
174 } static_lease6;
175 
176 typedef struct {
177   unsigned expires, lease_nip;
178   char lease_mac[6], hostname[20], pad[2];
179 } dyn_lease;
180 
181 typedef struct {
182   unsigned short duid_len, ia_type;
183   unsigned expires, iaid;
184   char lease_nip6[16], duid[20];
185 } dyn_lease6;
186 
187 typedef struct option_val_s {
188   char *key;
189   unsigned short code;
190   void *val;
191   size_t len;
192 } option_val_t;
193 
194 struct optval_duid_llt {
195   unsigned short type, hwtype;
196   unsigned time;
197   char lladdr[];
198 };
199 
200 struct optval_ia_na {
201   unsigned iaid, t1, t2;
202   char optval[];
203 };
204 
205 struct optval_ia_addr {
206   char ipv6_addr[16];
207   unsigned pref_lifetime, valid_lifetime;
208 };
209 struct optval_status_code {
210   unsigned short status_code;
211   char status_msg[];
212 };
213 
214 typedef struct __attribute__((__may_alias__)) server_config_s {
215   char *interface;                // interface to use
216   int ifindex;
217   uint8_t server_nip6[16];
218   uint32_t server_nip;
219   uint32_t port;
220   uint8_t server_mac[6];          // our MAC address (used only for ARP probing)
221   void *options[256];             // list of DHCP options loaded from the config file
222   /* start,end are in host order: we need to compare start <= ip <= end*/
223   uint32_t start_ip;              // start address of leases, in host order
224   uint32_t end_ip;                // end of leases, in host order
225   uint8_t start_ip6[16];          // start address of leases, in IPv6 mode
226   uint8_t end_ip6[16];            // end of leases, in IPv6 mode
227   uint32_t max_lease_sec;         // maximum lease time (host order)
228   uint32_t min_lease_sec;         // minimum lease time a client can request
229   uint32_t max_leases;            // maximum number of leases (including reserved addresses)
230   uint32_t auto_time;             // how long should dhcpd wait before writing a config file.
231                                   // if this is zero, it will only write one on SIGUSR1
232   uint32_t decline_time;          // how long an address is reserved if a client returns a
233                                   // decline message
234   uint32_t conflict_time;         // how long an arp conflict offender is leased for
235   uint32_t offer_time;            // how long an offered address is reserved
236   uint32_t siaddr_nip;            // "next server" bootp option
237   char *lease_file;
238   char *lease6_file;
239   char *pidfile;
240   char *notify_file;              // what to run whenever leases are written
241   char *sname;                    // bootp server name
242   char *boot_file;                // bootp boot file option
243   uint32_t pref_lifetime;
244   uint32_t valid_lifetime;
245   uint32_t t1,t2;
246   struct static_lease *static_leases; // List of ip/mac pairs to assign static leases
247 } server_config_t;
248 
249 typedef struct __attribute__((__may_alias__)) server_state_s {
250   uint8_t client_nip6[16];
251   uint32_t client_port;
252   uint8_t rqcode;
253   int listensock;
254   union {
255     dhcp_msg_t rcvd_pkt;
256     dhcp6_msg_t rcvd_pkt6;
257   } rcvd;
258   uint8_t* rqopt;
259   union {
260     dhcp_msg_t send_pkt;
261     dhcp6_msg_t send_pkt6;
262   } send;
263   union {
264     static_lease *sleases;
265     static_lease6 *sleases6;
266   } leases;
267   struct arg_list *dleases;
268 } server_state_t;
269 
270 static option_val_t options_list[] = {
271     {"lease"          , DHCP_NUM32  | 0x33, NULL, 0},
272     {"subnet"         , DHCP_IP     | 0x01, NULL, 0},
273     {"broadcast"      , DHCP_IP     | 0x1c, NULL, 0},
274     {"router"         , DHCP_IP     | 0x03, NULL, 0},
275     {"ipttl"          , DHCP_NUM8   | 0x17, NULL, 0},
276     {"mtu"            , DHCP_NUM16  | 0x1a, NULL, 0},
277     {"hostname"       , DHCP_STRING | 0x0c, NULL, 0},
278     {"domain"         , DHCP_STRING | 0x0f, NULL, 0},
279     {"search"         , DHCP_STRLST | 0x77, NULL, 0},
280     {"nisdomain"      , DHCP_STRING | 0x28, NULL, 0},
281     {"timezone"       , DHCP_NUM32  | 0x02, NULL, 0},
282     {"tftp"           , DHCP_STRING | 0x42, NULL, 0},
283     {"bootfile"       , DHCP_STRING | 0x43, NULL, 0},
284     {"bootsize"       , DHCP_NUM16  | 0x0d, NULL, 0},
285     {"rootpath"       , DHCP_STRING | 0x11, NULL, 0},
286     {"wpad"           , DHCP_STRING | 0xfc, NULL, 0},
287     {"serverid"       , DHCP_IP     | 0x36, NULL, 0},
288     {"message"        , DHCP_STRING | 0x38, NULL, 0},
289     {"vlanid"         , DHCP_NUM32  | 0x84, NULL, 0},
290     {"vlanpriority"   , DHCP_NUM32  | 0x85, NULL, 0},
291     {"dns"            , DHCP_IPLIST | 0x06, NULL, 0},
292     {"wins"           , DHCP_IPLIST | 0x2c, NULL, 0},
293     {"nissrv"         , DHCP_IPLIST | 0x29, NULL, 0},
294     {"ntpsrv"         , DHCP_IPLIST | 0x2a, NULL, 0},
295     {"lprsrv"         , DHCP_IPLIST | 0x09, NULL, 0},
296     {"swapsrv"        , DHCP_IP     | 0x10, NULL, 0},
297     {"routes"         , DHCP_STCRTS | 0x21, NULL, 0},
298     {"staticroutes"   , DHCP_STCRTS | 0x79, NULL, 0},
299     {"msstaticroutes" , DHCP_STCRTS | 0xf9, NULL, 0},
300 };
301 
302 struct fd_pair { int rd; int wr; };
303 static server_config_t gconfig;
304 static server_state_t gstate;
305 static uint8_t infomode;
306 static struct fd_pair sigfd;
307 static int constone = 1;
308 static sa_family_t addr_version = AF_INET;
309 
310 // calculate options size.
dhcp_opt_size(uint8_t * optionptr)311 static int dhcp_opt_size(uint8_t *optionptr)
312 {
313   int i = 0;
314   for(;optionptr[i] != 0xff; i++)
315     if(optionptr[i] != 0x00) i += optionptr[i + 1] + 2 -1;
316   return i;
317 }
318 
319 // calculates checksum for dhcp messeges.
dhcp_checksum(void * addr,int count)320 static uint16_t dhcp_checksum(void *addr, int count)
321 {
322   int32_t sum = 0;
323   uint16_t tmp = 0, *source = (uint16_t *)addr;
324 
325   while (count > 1)  {
326     sum += *source++;
327     count -= 2;
328   }
329   if (count > 0) {
330     *(uint8_t*)&tmp = *(uint8_t*)source;
331     sum += tmp;
332   }
333   while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
334   return ~sum;
335 }
336 
337 // gets information of INTERFACE and updates IFINDEX, MAC and IP
get_interface(const char * interface,int * ifindex,void * oip,uint8_t * mac)338 static int get_interface(const char *interface, int *ifindex, void *oip,
339     uint8_t *mac)
340 {
341   struct ifreq req;
342   struct sockaddr_in *ip;
343   struct sockaddr_in6 ip6;
344   int fd = xsocket(addr_version, SOCK_RAW, IPPROTO_RAW);
345   char ipv6_addr[40] = {0,};
346 
347   req.ifr_addr.sa_family = addr_version;
348   xstrncpy(req.ifr_name, (char *)interface, IFNAMSIZ);
349 
350   xioctl(fd, SIOCGIFFLAGS, &req);
351 
352   if (!(req.ifr_flags & IFF_UP)) return -1;
353 
354   if (addr_version == AF_INET6) {
355 
356     FILE *fd6 = fopen("/proc/net/if_inet6", "r");
357     uint8_t *oip6 = (uint8_t*)oip;
358     int i;
359 
360     while(fgets(toybuf, sizeof(toybuf), fd6)) {
361       if (!strstr(toybuf, interface))
362         continue;
363 
364       if (sscanf(toybuf, "%32s \n", ipv6_addr) == 1)
365         break;
366     }
367     fclose(fd6);
368 
369     if (oip6) {
370       char *ptr = ipv6_addr+sizeof(ipv6_addr)-1;
371 
372       // convert giant hex string into colon-spearated ipv6 address by
373       // inserting ':' every 4 characters.
374       for (i = 32; i; i--)
375         if ((*(ptr--) = ipv6_addr[i])) if (!(i&3)) *(ptr--) = ':';
376 
377       dbg("ipv6 %s\n", ipv6_addr);
378       if(inet_pton(AF_INET6, ipv6_addr, &ip6.sin6_addr) <= 0)
379         error_msg("inet : the ipv6 address is not proper");
380       else
381         memcpy(oip6, ip6.sin6_addr.s6_addr32, sizeof(uint32_t)*4);
382     }
383   } else {
384     uint32_t *oip4 = (uint32_t*)oip;
385     if (oip4) {
386       xioctl(fd, SIOCGIFADDR, &req);
387       ip = (struct sockaddr_in*) &req.ifr_addr;
388       dbg("IP %s\n", inet_ntoa(ip->sin_addr));
389       *oip4 = ntohl(ip->sin_addr.s_addr);
390     }
391   }
392 
393   if (ifindex) {
394     xioctl(fd, SIOCGIFINDEX, &req);
395     dbg("Adapter index %d\n", req.ifr_ifindex);
396     *ifindex = req.ifr_ifindex;
397   }
398   if (mac) {
399     xioctl(fd, SIOCGIFHWADDR, &req);
400     memcpy(mac, req.ifr_hwaddr.sa_data, 6);
401     dbg("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
402   }
403 
404   close(fd);
405   return 0;
406 }
407 
408 /*
409  *logs messeges to syslog or console
410  *opening the log is still left with applet.
411  *FIXME: move to more relevent lib. probably libc.c
412  */
infomsg(uint8_t infomode,char * s,...)413 static void infomsg(uint8_t infomode, char *s, ...)
414 {
415   int used;
416   char *msg;
417   va_list p, t;
418 
419   if (infomode == LOG_SILENT) return;
420   va_start(p, s);
421   va_copy(t, p);
422   used = vsnprintf(NULL, 0, s, t);
423   used++;
424   va_end(t);
425 
426   msg = xmalloc(used);
427   vsnprintf(msg, used, s, p);
428   va_end(p);
429 
430   if (infomode & LOG_SYSTEM) syslog(LOG_INFO, "%s", msg);
431   if (infomode & LOG_CONSOLE) printf("%s\n", msg);
432   free(msg);
433 }
434 
435 /*
436  * Writes self PID in file PATH
437  * FIXME: libc implementation only writes in /var/run
438  * this is more generic as some implemenation may provide
439  * arguments to write in specific file. as dhcpd does.
440  */
write_pid(char * path)441 static void write_pid(char *path)
442 {
443   int pidfile = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666);
444   if (pidfile > 0) {
445     char pidbuf[12];
446 
447     sprintf(pidbuf, "%u", (unsigned)getpid());
448     write(pidfile, pidbuf, strlen(pidbuf));
449     close(pidfile);
450   }
451 }
452 
453 // Generic signal handler real handling is done in main funcrion.
signal_handler(int sig)454 static void signal_handler(int sig)
455 {
456   unsigned char ch = sig;
457   if (write(sigfd.wr, &ch, 1) != 1) dbg("can't send signal\n");
458 }
459 
460 // signal setup for SIGUSR1 SIGTERM
setup_signal()461 static int setup_signal()
462 {
463   if (pipe((int *)&sigfd) < 0) {
464     dbg("signal pipe failed\n");
465     return -1;
466   }
467   fcntl(sigfd.wr , F_SETFD, FD_CLOEXEC);
468   fcntl(sigfd.rd , F_SETFD, FD_CLOEXEC);
469   int flags = fcntl(sigfd.wr, F_GETFL);
470   fcntl(sigfd.wr, F_SETFL, flags | O_NONBLOCK);
471   signal(SIGUSR1, signal_handler);
472   signal(SIGTERM, signal_handler);
473   return 0;
474 }
475 
476 // String STR to UINT32 conversion strored in VAR
strtou32(const char * str,void * var)477 static int strtou32(const char *str, void *var)
478 {
479   char *endptr = NULL;
480   int base = 10;
481   errno=0;
482   *((uint32_t*)(var)) = 0;
483   if (str[0]=='0' && (str[1]=='x' || str[1]=='X')) {
484     base = 16;
485     str+=2;
486   }
487 
488   long ret_val = strtol(str, &endptr, base);
489   if (errno) infomsg(infomode, "config : Invalid num %s",str);
490   else if (endptr && (*endptr!='\0'||endptr == str))
491       infomsg(infomode, "config : Not a valid num %s",str);
492   else *((uint32_t*)(var)) = (uint32_t)ret_val;
493   return 0;
494 }
495 
496 // copy string STR in variable VAR
strinvar(const char * str,void * var)497 static int strinvar(const char *str, void *var)
498 {
499   char **dest = var;
500   if (*dest) free(*dest);
501   *dest = strdup(str);
502   return 0;
503 }
504 
505 // IP String STR to binary data.
striptovar(const char * str,void * var)506 static int striptovar(const char *str, void *var)
507 {
508   *((uint32_t*)(var)) = 0;
509   if(!str) {
510     error_msg("config : NULL address string \n");
511     return -1;
512   }
513   if((inet_pton(AF_INET6, str, var)<=0) && (inet_pton(AF_INET, str, var)<=0)) {
514     error_msg("config : wrong address %s \n", str);
515     return -1;
516   }
517   return 0;
518 }
519 
520 // String to dhcp option conversion
strtoopt(const char * str,void * var)521 static int strtoopt(const char *str, void *var)
522 {
523   char *option, *valstr, *grp, *tp;
524   uint32_t optcode = 0, inf = infomode, convtmp, mask, nip, router;
525   uint16_t flag = 0;
526   int count, size = ARRAY_LEN(options_list);
527 
528   if (!*str) return 0;
529   if (!(option = strtok((char*)str, " \t="))) return -1;
530 
531   infomode = LOG_SILENT;
532   strtou32(option, (uint32_t*)&optcode);
533   infomode = inf;
534 
535   if (optcode > 0 && optcode < 256) { // raw option
536     for (count = 0; count < size; count++) {
537       if ((options_list[count].code & 0X00FF) == optcode) {
538         flag = (options_list[count].code & 0XFF00);
539         break;
540       }
541     }
542   } else { //string option
543     for (count = 0; count < size; count++) {
544       if (!strncmp(options_list[count].key, option, strlen(options_list[count].key))) {
545         flag = (options_list[count].code & 0XFF00);
546         optcode = (options_list[count].code & 0X00FF);
547         break;
548       }
549     }
550   }
551   if (count == size) {
552     infomsg(inf, "config : Obsolete OR Unknown Option : %s", option);
553     return -1;
554   }
555 
556   if (!flag || !optcode) return -1;
557 
558   if (!(valstr = strtok(NULL, " \t"))) {
559     dbg("config : option %s has no value defined.\n", option);
560     return -1;
561   }
562   dbg(" value : %-20s : ", valstr);
563   switch (flag) {
564   case DHCP_NUM32:
565     options_list[count].len = sizeof(uint32_t);
566     options_list[count].val = xmalloc(sizeof(uint32_t));
567     strtou32(valstr, &convtmp);
568     memcpy(options_list[count].val, &convtmp, sizeof(uint32_t));
569     break;
570   case DHCP_NUM16:
571     options_list[count].len = sizeof(uint16_t);
572     options_list[count].val = xmalloc(sizeof(uint16_t));
573     strtou32(valstr, &convtmp);
574     memcpy(options_list[count].val, &convtmp, sizeof(uint16_t));
575     break;
576   case DHCP_NUM8:
577     options_list[count].len = sizeof(uint8_t);
578     options_list[count].val = xmalloc(sizeof(uint8_t));
579     strtou32(valstr, &convtmp);
580     memcpy(options_list[count].val, &convtmp, sizeof(uint8_t));
581     break;
582   case DHCP_IP:
583     options_list[count].len = sizeof(uint32_t);
584     options_list[count].val = xmalloc(sizeof(uint32_t));
585     striptovar(valstr, options_list[count].val);
586     break;
587   case DHCP_STRING:
588     options_list[count].len = strlen(valstr);
589     options_list[count].val = strdup(valstr);
590     break;
591   case DHCP_IPLIST:
592     while(valstr){
593       options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + sizeof(uint32_t));
594       striptovar(valstr, ((uint8_t*)options_list[count].val)+options_list[count].len);
595       options_list[count].len += sizeof(uint32_t);
596       valstr = strtok(NULL," \t");
597     }
598     break;
599   case DHCP_IPPLST:
600     break;
601   case DHCP_STCRTS:
602     /* Option binary format:
603      * mask [one byte, 0..32]
604      * ip [0..4 bytes depending on mask]
605      * router [4 bytes]
606      * may be repeated
607      * staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1
608      */
609     grp = strtok(valstr, ",");;
610     while(grp){
611       while(*grp == ' ' || *grp == '\t') grp++;
612       tp = strchr(grp, '/');
613       if (!tp) error_exit("wrong formatted static route option");
614       *tp = '\0';
615       mask = strtol(++tp, &tp, 10);
616       if (striptovar(grp, (uint8_t*)&nip)<0) error_exit("wrong formatted static route option");
617       while(*tp == ' ' || *tp == '\t' || *tp == '-') tp++;
618       if (striptovar(tp, (uint8_t*)&router)<0) error_exit("wrong formatted static route option");
619       options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + 1 + mask/8 + 4);
620       memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &mask, 1);
621       options_list[count].len += 1;
622       memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &nip, mask/8);
623       options_list[count].len += mask/8;
624       memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &router, 4);
625       options_list[count].len += 4;
626       tp = NULL;
627       grp = strtok(NULL, ",");
628     }
629     break;
630   }
631   return 0;
632 }
633 
634 // Reads Static leases from STR and updates inner structures.
get_staticlease(const char * str,void * var)635 static int get_staticlease(const char *str, void *var)
636 {
637   struct static_lease_s *sltmp;
638   char *tkmac, *tkip;
639   int count;
640 
641   if (!*str) return 0;
642 
643   if (!(tkmac = strtok((char*)str, " \t"))) {
644     infomsg(infomode, "config : static lease : mac not found");
645     return 0;
646   }
647   if (!(tkip = strtok(NULL, " \t"))) {
648     infomsg(infomode, "config : static lease : no ip bind to mac %s", tkmac);
649     return 0;
650   }
651   sltmp = xzalloc(sizeof(struct static_lease_s));
652   for (count = 0; count < 6; count++, tkmac++) {
653     errno = 0;
654     sltmp->mac[count] = strtol(tkmac, &tkmac, 16);
655     if (sltmp->mac[count]>255 || sltmp->mac[count]<0 || (*tkmac && *tkmac!=':') || errno) {
656       infomsg(infomode, "config : static lease : mac address wrong format");
657       free(sltmp);
658       return 0;
659     }
660   }
661   striptovar(tkip, &sltmp->nip);
662   sltmp->next = gstate.leases.sleases;
663   gstate.leases.sleases = sltmp;
664 
665   return 0;
666 }
667 
668 static struct config_keyword keywords[] = {
669 // keyword          handler           variable address                default
670   {"start"        , striptovar      , (void*)&gconfig.start_ip     , "192.168.0.20"},
671   {"end"          , striptovar      , (void*)&gconfig.end_ip       , "192.168.0.254"},
672   {"interface"    , strinvar        , (void*)&gconfig.interface    , "eth0"},
673   {"port"         , strtou32        , (void*)&gconfig.port         , "67"},
674   {"min_lease"    , strtou32        , (void*)&gconfig.min_lease_sec, "60"},
675   {"max_leases"   , strtou32        , (void*)&gconfig.max_leases   , "235"},
676   {"auto_time"    , strtou32        , (void*)&gconfig.auto_time    , "7200"},
677   {"decline_time" , strtou32        , (void*)&gconfig.decline_time , "3600"},
678   {"conflict_time", strtou32        , (void*)&gconfig.conflict_time, "3600"},
679   {"offer_time"   , strtou32        , (void*)&gconfig.offer_time   , "60"},
680   {"lease_file"   , strinvar        , (void*)&gconfig.lease_file   , "/var/lib/misc/dhcpd.leases"}, //LEASES_FILE
681   {"lease6_file"  , strinvar        , (void*)&gconfig.lease6_file  , "/var/lib/misc/dhcpd6.leases"}, //LEASES_FILE
682   {"pidfile"      , strinvar        , (void*)&gconfig.pidfile      , "/var/run/dhcpd.pid"}, //DPID_FILE
683   {"siaddr"       , striptovar      , (void*)&gconfig.siaddr_nip   , "0.0.0.0"},
684   {"option"       , strtoopt        , (void*)&gconfig.options      , ""},
685   {"opt"          , strtoopt        , (void*)&gconfig.options      , ""},
686   {"notify_file"  , strinvar        , (void*)&gconfig.notify_file  , ""},
687   {"sname"        , strinvar        , (void*)&gconfig.sname        , ""},
688   {"boot_file"    , strinvar        , (void*)&gconfig.boot_file    , ""},
689   {"static_lease" , get_staticlease , (void*)&gconfig.static_leases, ""},
690   {"start6"       , striptovar      , (void*)&gconfig.start_ip6    , "2001:620:40b:555::100"},
691   {"end6"         , striptovar      , (void*)&gconfig.end_ip6      , "2001:620:40b:555::200"},
692   {"preferred_lifetime" , strtou32  , (void*)&gconfig.pref_lifetime, "3600"},
693   {"valid_lifetime"     , strtou32  , (void*)&gconfig.valid_lifetime, "7200"},
694   {"t1"           , strtou32        , (void*)&gconfig.t1           , "3600"},
695   {"t2"           , strtou32        , (void*)&gconfig.t2           , "5400"},
696 };
697 
698 // Parses the server config file and updates the global server config accordingly.
parse_server_config(char * config_file,struct config_keyword * confkey)699 static int parse_server_config(char *config_file, struct config_keyword *confkey)
700 {
701   FILE *fs = NULL;
702   char *confline_temp = NULL,*confline = NULL, *tk = NULL, *tokens[2] = {NULL, NULL};
703   int len, linelen, tcount, count, size = ARRAY_LEN(keywords);
704 
705   for (count = 0; count < size; count++)
706     if (confkey[count].handler)
707       confkey[count].handler(confkey[count].def, confkey[count].var);
708 
709   if (!(fs = fopen(config_file, "r"))) perror_msg("%s", config_file);
710   for (len = 0, linelen = 0; fs;) {
711     len = getline(&confline_temp, (size_t*) &linelen, fs);
712     confline = confline_temp;
713     if (len <= 0) break;
714     for (; *confline == ' '; confline++, len--);
715     if ((confline[0] == '#') || (confline[0] == '\n')) goto free_conf_continue;
716     tk = strchr(confline, '#');
717     if (tk) {
718       for (; *(tk-1)==' ' || *(tk-1)=='\t'; tk--);
719       *tk = '\0';
720     }
721     tk = strchr(confline, '\n');
722     if (tk) {
723       for (; *(tk-1)==' ' || *(tk-1)=='\t'; tk--);
724       *tk = '\0';
725     }
726     for (tcount=0, tk=strtok(confline, " \t"); tk && (tcount < 2);
727         tcount++, tk=strtok(NULL,(tcount==1)?"":" \t")) {
728       while ((*tk == '\t') || (*tk == ' ')) tk++;
729       tokens[tcount] = xstrdup(tk);
730     }
731     if (tcount<=1) goto free_tk0_continue;
732     for (count = 0; count < size; count++) {
733       if (!strcmp(confkey[count].keyword,tokens[0])) {
734         dbg("got config : %15s : ", confkey[count].keyword);
735         if (confkey[count].handler(tokens[1], confkey[count].var) == 0)
736           dbg("%s \n", tokens[1]);
737         break;
738       }
739     }
740     if (tokens[1]) { free(tokens[1]); tokens[1] = NULL; }
741 free_tk0_continue:
742     if (tokens[0]) { free(tokens[0]); tokens[0] = NULL; }
743 free_conf_continue:
744     free(confline_temp);
745     confline_temp = NULL;
746   }
747   if (fs) fclose(fs);
748   return 0;
749 }
750 
751 // opens UDP socket for listen ipv6 packets
open_listensock6(void)752 static int open_listensock6(void)
753 {
754   struct sockaddr_in6 addr6;
755   struct ipv6_mreq mreq;
756 
757   if (gstate.listensock > 0) close(gstate.listensock);
758 
759   dbg("Opening listen socket on *:%d %s\n", gconfig.port, gconfig.interface);
760 
761   gstate.listensock = xsocket(PF_INET6, SOCK_DGRAM, 0);
762   setsockopt(gstate.listensock, SOL_SOCKET, SO_REUSEADDR, &constone, sizeof(constone));
763   setsockopt(gstate.listensock, IPPROTO_IPV6, IPV6_CHECKSUM, &constone, sizeof(constone));
764 
765   if (setsockopt(gstate.listensock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &constone,
766         sizeof(constone)) == -1) {
767     error_msg("failed to receive ipv6 packets.\n");
768     close(gstate.listensock);
769     return -1;
770   }
771 
772   setsockopt(gstate.listensock, SOL_SOCKET, SO_BINDTODEVICE, gconfig.interface, strlen(gconfig.interface)+1);
773 
774   memset(&addr6, 0, sizeof(addr6));
775   addr6.sin6_family = AF_INET6;
776   addr6.sin6_port = htons(gconfig.port); //SERVER_PORT
777   addr6.sin6_scope_id = if_nametoindex(gconfig.interface);
778   //Listening for multicast packet
779   inet_pton(AF_INET6, "ff02::1:2", &addr6.sin6_addr);
780 
781   if (bind(gstate.listensock, (struct sockaddr *) &addr6, sizeof(addr6)) == -1) {
782     close(gstate.listensock);
783     perror_exit("bind failed");
784   }
785 
786   memset(&mreq, 0, sizeof(mreq));
787   mreq.ipv6mr_interface = if_nametoindex(gconfig.interface);
788   memcpy(&mreq.ipv6mr_multiaddr, &addr6.sin6_addr, sizeof(addr6.sin6_addr));
789 
790   if(setsockopt(gstate.listensock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) {
791     error_msg("failed to join a multicast group.\n");
792     close(gstate.listensock);
793     return -1;
794   }
795 
796   dbg("OPEN : success\n");
797   return 0;
798 }
799 
800 // opens UDP socket for listen
open_listensock(void)801 static int open_listensock(void)
802 {
803   struct sockaddr_in addr;
804   struct ifreq ifr;
805 
806   if (gstate.listensock > 0) close(gstate.listensock);
807 
808   dbg("Opening listen socket on *:%d %s\n", gconfig.port, gconfig.interface);
809   gstate.listensock = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
810   setsockopt(gstate.listensock, SOL_SOCKET, SO_REUSEADDR, &constone, sizeof(constone));
811   if (setsockopt(gstate.listensock, SOL_SOCKET, SO_BROADCAST, &constone, sizeof(constone)) == -1) {
812     error_msg("failed to receive brodcast packets.\n");
813     close(gstate.listensock);
814     return -1;
815   }
816   memset(&ifr, 0, sizeof(ifr));
817   xstrncpy(ifr.ifr_name, gconfig.interface, IFNAMSIZ);
818   setsockopt(gstate.listensock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
819 
820   memset(&addr, 0, sizeof(addr));
821   addr.sin_family = AF_INET;
822   addr.sin_port = htons(gconfig.port); //SERVER_PORT
823   addr.sin_addr.s_addr = INADDR_ANY ;
824 
825   if (bind(gstate.listensock, (struct sockaddr *) &addr, sizeof(addr))) {
826     close(gstate.listensock);
827     perror_exit("bind failed");
828   }
829   dbg("OPEN : success\n");
830   return 0;
831 }
832 
send_packet6(uint8_t relay,uint8_t * client_lla,uint16_t optlen)833 static int send_packet6(uint8_t relay, uint8_t *client_lla, uint16_t optlen)
834 {
835   struct sockaddr_ll dest_sll;
836   dhcp6_raw_t packet;
837   unsigned padding;
838   int fd, result = -1;
839 
840   memset(&packet, 0, sizeof(dhcp6_raw_t));
841   memcpy(&packet.dhcp6, &gstate.send.send_pkt6, sizeof(dhcp6_msg_t));
842   padding = sizeof(packet.dhcp6.options) - optlen;
843 
844   if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6))) < 0) {
845     dbg("SEND : ipv6 socket failed\n");
846     return -1;
847   }
848   memset(&dest_sll, 0, sizeof(dest_sll));
849   dest_sll.sll_family = AF_PACKET;
850   dest_sll.sll_protocol = htons(ETH_P_IPV6);
851   dest_sll.sll_ifindex = gconfig.ifindex;
852   dest_sll.sll_halen = ETH_ALEN;
853   memcpy(dest_sll.sll_addr, client_lla, sizeof(uint8_t)*6);
854 
855   if (bind(fd, (struct sockaddr *) &dest_sll, sizeof(dest_sll)) < 0) {
856     dbg("SEND : bind failed\n");
857     close(fd);
858     return -1;
859   }
860   memcpy(&packet.iph.ip6_src, &gconfig.server_nip6, sizeof(uint32_t)*4);
861   memcpy(&packet.iph.ip6_dst, &gstate.client_nip6, sizeof(uint32_t)*4);
862 
863   packet.udph.source = htons(gconfig.port); //SERVER_PORT
864   packet.udph.dest = gstate.client_port; //CLIENT_PORT
865   packet.udph.len = htons(sizeof(dhcp6_raw_t) - sizeof(struct ip6_hdr) - padding);
866   packet.iph.ip6_ctlun.ip6_un1.ip6_un1_plen = htons(ntohs(packet.udph.len) + 0x11);
867   packet.udph.check = dhcp_checksum(&packet, sizeof(dhcp6_raw_t) - padding);
868   packet.iph.ip6_ctlun.ip6_un1.ip6_un1_flow = htonl(0x60000000);
869   packet.iph.ip6_ctlun.ip6_un1.ip6_un1_plen = packet.udph.len;
870   packet.iph.ip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_UDP;
871   packet.iph.ip6_ctlun.ip6_un1.ip6_un1_hlim = 0x64;
872 
873   result = sendto(fd, &packet, sizeof(dhcp6_raw_t)-padding,
874       0, (struct sockaddr *) &dest_sll, sizeof(dest_sll));
875 
876   dbg("sendto %d\n", result);
877   close(fd);
878   if (result < 0) dbg("PACKET send error\n");
879   return result;
880 }
881 
882 // Sends data through raw socket.
send_packet(uint8_t broadcast)883 static int send_packet(uint8_t broadcast)
884 {
885   struct sockaddr_ll dest_sll;
886   dhcp_raw_t packet;
887   unsigned padding;
888   int fd, result = -1;
889   char bmacaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
890 
891   memset(&packet, 0, sizeof(dhcp_raw_t));
892   memcpy(&packet.dhcp, &gstate.send.send_pkt, sizeof(dhcp_msg_t));
893 
894   if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
895     dbg("SEND : socket failed\n");
896     return -1;
897   }
898   memset(&dest_sll, 0, sizeof(dest_sll));
899   dest_sll.sll_family = AF_PACKET;
900   dest_sll.sll_protocol = htons(ETH_P_IP);
901   dest_sll.sll_ifindex = gconfig.ifindex;
902   dest_sll.sll_halen = 6;
903   memcpy(dest_sll.sll_addr, (broadcast)?bmacaddr:gstate.rcvd.rcvd_pkt.chaddr , 6);
904 
905   if (bind(fd, (struct sockaddr *) &dest_sll, sizeof(dest_sll)) < 0) {
906     dbg("SEND : bind failed\n");
907     close(fd);
908     return -1;
909   }
910   padding = 308 - 1 - dhcp_opt_size(gstate.send.send_pkt.options);
911   packet.iph.protocol = IPPROTO_UDP;
912   packet.iph.saddr = gconfig.server_nip;
913   packet.iph.daddr = (broadcast || (gstate.rcvd.rcvd_pkt.ciaddr == 0))?
914     INADDR_BROADCAST : gstate.rcvd.rcvd_pkt.ciaddr;
915   packet.udph.source = htons(gconfig.port);//SERVER_PORT
916   packet.udph.dest = gstate.client_port; //CLIENT_PORT
917   packet.udph.len = htons(sizeof(dhcp_raw_t) - sizeof(struct iphdr) - padding);
918   packet.iph.tot_len = packet.udph.len;
919   packet.udph.check = dhcp_checksum(&packet, sizeof(dhcp_raw_t) - padding);
920   packet.iph.tot_len = htons(sizeof(dhcp_raw_t) - padding);
921   packet.iph.ihl = sizeof(packet.iph) >> 2;
922   packet.iph.version = IPVERSION;
923   packet.iph.ttl = IPDEFTTL;
924   packet.iph.check = dhcp_checksum(&packet.iph, sizeof(packet.iph));
925 
926   result = sendto(fd, &packet, sizeof(dhcp_raw_t) - padding, 0,
927       (struct sockaddr *) &dest_sll, sizeof(dest_sll));
928 
929   dbg("sendto %d\n", result);
930   close(fd);
931   if (result < 0) dbg("PACKET send error\n");
932   return result;
933 }
934 
read_packet6(void)935 static int read_packet6(void)
936 {
937   int ret;
938   struct sockaddr_in6 c_addr;
939   socklen_t c_addr_size = sizeof(c_addr);
940 
941   memset(&gstate.rcvd.rcvd_pkt6, 0, sizeof(dhcp6_msg_t));
942   ret = recvfrom(gstate.listensock, &gstate.rcvd.rcvd_pkt6, sizeof(dhcp6_msg_t),
943       0, (struct sockaddr*) &c_addr, &c_addr_size);
944   memcpy(gstate.client_nip6, &c_addr.sin6_addr, sizeof(uint32_t)*4);
945   memcpy(&gstate.client_port, &c_addr.sin6_port, sizeof(uint32_t));
946   if (ret < 0) {
947     dbg("Packet read error, ignoring. \n");
948     return ret; // returns -1
949   }
950   if (gstate.rcvd.rcvd_pkt6.msgtype < 1) {
951     dbg("Bad message type, igroning. \n");
952     return -2;
953   }
954 
955   dbg("Received an ipv6 packet. Size : %d \n", ret);
956   return ret;
957 }
958 
959 // Reads from UDP socket
read_packet(void)960 static int read_packet(void)
961 {
962   int ret;
963   struct sockaddr_in c_addr;
964   socklen_t c_addr_size = sizeof(c_addr);
965 
966   memset(&gstate.rcvd.rcvd_pkt, 0, sizeof(dhcp_msg_t));
967   ret = recvfrom(gstate.listensock, &gstate.rcvd.rcvd_pkt, sizeof(dhcp_msg_t),
968       0, (struct sockaddr*) &c_addr, &c_addr_size);
969   memcpy(&gstate.client_port, &c_addr.sin_port, sizeof(uint32_t));
970   /*ret = read(gstate.listensock, &gstate.rcvd.rcvd_pkt, sizeof(dhcp_msg_t));*/
971   if (ret < 0) {
972     dbg("Packet read error, ignoring. \n");
973     return ret; // returns -1
974   }
975   if (gstate.rcvd.rcvd_pkt.cookie != htonl(DHCP_MAGIC)) {
976     dbg("Packet with bad magic, ignoring. \n");
977     return -2;
978   }
979   if (gstate.rcvd.rcvd_pkt.op != 1) { //BOOTPREQUEST
980     dbg("Not a BOOT REQUEST ignoring. \n");
981     return -2;
982   }
983   if (gstate.rcvd.rcvd_pkt.hlen != 6) {
984     dbg("hlen != 6 ignoring. \n");
985     return -2;
986   }
987   dbg("Received a packet. Size : %d \n", ret);
988   return ret;
989 }
990 
991 // Preapres a dhcp packet with defaults and configs
prepare_send_pkt(void)992 static uint8_t* prepare_send_pkt(void)
993 {
994   memset((void*)&gstate.send.send_pkt, 0, sizeof(gstate.send.send_pkt));
995   gstate.send.send_pkt.op = 2; //BOOTPREPLY
996   gstate.send.send_pkt.htype = 1;
997   gstate.send.send_pkt.hlen = 6;
998   gstate.send.send_pkt.xid = gstate.rcvd.rcvd_pkt.xid;
999   gstate.send.send_pkt.cookie = htonl(DHCP_MAGIC);
1000   gstate.send.send_pkt.nsiaddr = gconfig.server_nip;
1001   memcpy(gstate.send.send_pkt.chaddr, gstate.rcvd.rcvd_pkt.chaddr, 16);
1002   gstate.send.send_pkt.options[0] = DHCP_OPT_END;
1003   return gstate.send.send_pkt.options;
1004 }
1005 
prepare_send_pkt6(uint16_t opt)1006 static uint8_t* prepare_send_pkt6(uint16_t opt)
1007 {
1008   memset((void*)&gstate.send.send_pkt6, 0, sizeof(gstate.send.send_pkt6));
1009   gstate.send.send_pkt6.msgtype = opt;
1010   memcpy(gstate.send.send_pkt6.transaction_id, gstate.rcvd.rcvd_pkt6.transaction_id, 3);
1011   return gstate.send.send_pkt6.options;
1012 }
1013 
1014 // Sets a option value in dhcp packet's option field
set_optval(uint8_t * optptr,uint16_t opt,void * var,size_t len)1015 static uint8_t* set_optval(uint8_t *optptr, uint16_t opt, void *var, size_t len)
1016 {
1017   while (*optptr != DHCP_OPT_END) optptr++;
1018   *optptr++ = (uint8_t)(opt & 0x00FF);
1019   *optptr++ = (uint8_t) len;
1020   memcpy(optptr, var, len);
1021   optptr += len;
1022   *optptr = DHCP_OPT_END;
1023   return optptr;
1024 }
1025 
set_optval6(uint8_t * optptr,uint16_t opt,void * var,size_t len)1026 static uint8_t* set_optval6(uint8_t *optptr, uint16_t opt, void *var, size_t len)
1027 {
1028   *((uint16_t*)optptr) = htons(opt);
1029   *(uint16_t*)(optptr+2) = htons(len);
1030   memcpy(optptr+4, var, len);
1031   optptr += len+4;
1032   return optptr;
1033 }
1034 
1035 // Gets a option value from dhcp packet's option field
get_optval(uint8_t * optptr,uint16_t opt,void * var)1036 static uint8_t* get_optval(uint8_t *optptr, uint16_t opt, void *var)
1037 {
1038   size_t len;
1039   uint8_t overloaded = 0;
1040 
1041   while (1) {
1042     while (*optptr == DHCP_OPT_PADDING) optptr++;
1043     if ((*optptr & 0x00FF) == DHCP_OPT_END) break;
1044     if ((*optptr & 0x00FF) == DHCP_OPT_OPTION_OVERLOAD) {
1045       overloaded = optptr[2];
1046       optptr += optptr[1] + 2;
1047     }
1048     len = optptr[1];
1049     if (*optptr == (opt & 0x00FF))
1050       switch (opt & 0xFF00) {
1051         case DHCP_NUM32: // FALLTHROUGH
1052         case DHCP_IP:
1053           memcpy(var, optptr+2, sizeof(uint32_t));
1054           optptr += len + 2;
1055           return optptr;
1056           break;
1057         case DHCP_NUM16:
1058           memcpy(var, optptr+2, sizeof(uint16_t));
1059           optptr += len + 2;
1060           return optptr;
1061           break;
1062         case DHCP_NUM8:
1063           memcpy(var, optptr+2, sizeof(uint8_t));
1064           optptr += len + 2;
1065           return optptr;
1066           break;
1067         case DHCP_STRING:
1068           var = xstrndup((char*) optptr, len);
1069           optptr += len + 2;
1070           return optptr;
1071           break;
1072       }
1073     optptr += len + 2;
1074   }
1075   if ((overloaded == 1) | (overloaded == 3)) get_optval((uint8_t*)&gstate.rcvd.rcvd_pkt.file, opt, var);
1076   if ((overloaded == 2) | (overloaded == 3)) get_optval((uint8_t*)&gstate.rcvd.rcvd_pkt.sname, opt, var);
1077   return optptr;
1078 }
1079 
get_optval6(uint8_t * optptr,uint16_t opt,uint16_t * datalen,void ** var)1080 static uint8_t* get_optval6(uint8_t *optptr, uint16_t opt, uint16_t *datalen, void **var)
1081 {
1082   uint16_t optcode;
1083   uint16_t len;
1084 
1085   memcpy(&optcode, optptr, sizeof(uint16_t));
1086   memcpy(&len, optptr+2, sizeof(uint16_t));
1087   if(!optcode) {
1088     dbg("Option %d is not exist.\n", opt);
1089     return optptr;
1090   }
1091   optcode = ntohs(optcode);
1092   len = ntohs(len);
1093 
1094   if (opt == optcode) {
1095     *var = xmalloc(len);
1096     memcpy(*var, optptr+4, len);
1097     optptr = optptr + len + 4;
1098     memcpy(datalen, &len, sizeof(uint16_t));
1099   }
1100   else {
1101     optptr = get_optval6(optptr+len+4, opt, datalen, var);
1102   }
1103 
1104   return optptr;
1105 }
1106 
1107 // Retrives Requested Parameter list from dhcp req packet.
get_reqparam(uint8_t ** list)1108 static uint8_t get_reqparam(uint8_t **list)
1109 {
1110   uint8_t len, *optptr;
1111   if(*list) free(*list);
1112   for (optptr = gstate.rcvd.rcvd_pkt.options;
1113       *optptr && *optptr!=((DHCP_OPT_PARAM_REQ) & 0x00FF); optptr+=optptr[1]+2);
1114   len = *++optptr;
1115   *list = xzalloc(len+1);
1116   memcpy(*list, ++optptr, len);
1117   return len;
1118 }
1119 
1120 // Sets values of req param in dhcp offer packet.
set_reqparam(uint8_t * optptr,uint8_t * list)1121 static uint8_t* set_reqparam(uint8_t *optptr, uint8_t *list)
1122 {
1123   uint8_t reqcode;
1124   int count, size = ARRAY_LEN(options_list);
1125 
1126   while (*list) {
1127     reqcode = *list++;
1128     for (count = 0; count < size; count++) {
1129       if ((options_list[count].code & 0X00FF)==reqcode) {
1130         if (!(options_list[count].len) || !(options_list[count].val)) break;
1131         for (; *optptr && *optptr!=DHCP_OPT_END; optptr+=optptr[1]+2);
1132         *optptr++ = (uint8_t) (options_list[count].code & 0x00FF);
1133         *optptr++ = (uint8_t) options_list[count].len;
1134         memcpy(optptr, options_list[count].val, options_list[count].len);
1135         optptr += options_list[count].len;
1136         *optptr = DHCP_OPT_END;
1137         break;
1138       }
1139     }
1140   }
1141   return optptr;
1142 }
1143 
run_notify(char ** argv)1144 static void run_notify(char **argv)
1145 {
1146   struct stat sts;
1147   volatile int error = 0;
1148   pid_t pid;
1149 
1150   if (stat(argv[0], &sts) == -1 && errno == ENOENT) {
1151     infomsg(infomode, "notify file: %s : not exist.", argv[0]);
1152     return;
1153   }
1154   fflush(NULL);
1155 
1156   pid = vfork();
1157   if (pid < 0) {
1158     dbg("Fork failed.\n");
1159     return;
1160   }
1161   if (!pid) {
1162     execvp(argv[0], argv);
1163     error = errno;
1164     _exit(111);
1165   }
1166   if (error) {
1167     waitpid(pid, NULL, 0);
1168     errno = error;
1169   }
1170   dbg("script complete.\n");
1171 }
1172 
write_leasefile(void)1173 static void write_leasefile(void)
1174 {
1175   int fd;
1176   uint32_t curr, tmp_time;
1177   int64_t timestamp;
1178   struct arg_list *listdls = gstate.dleases;
1179   dyn_lease *dls;
1180 
1181   if ((fd = open(gconfig.lease_file, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
1182     perror_msg("can't open %s ", gconfig.lease_file);
1183   } else {
1184     curr = timestamp = time(NULL);
1185     timestamp = SWAP_BE64(timestamp);
1186     writeall(fd, &timestamp, sizeof(timestamp));
1187 
1188     while (listdls) {
1189       dls = (dyn_lease*)listdls->arg;
1190       tmp_time = dls->expires;
1191       dls->expires -= curr;
1192       if ((int32_t) dls->expires < 0) goto skip;
1193       dls->expires = htonl(dls->expires);
1194       writeall(fd, dls, sizeof(dyn_lease));
1195 skip:
1196       dls->expires = tmp_time;
1197       listdls = listdls->next;
1198     }
1199     close(fd);
1200     if (gconfig.notify_file) {
1201       char *argv[3];
1202       argv[0] = gconfig.notify_file;
1203       argv[1] = gconfig.lease_file;
1204       argv[2] = NULL;
1205       run_notify(argv);
1206     }
1207   }
1208 }
1209 
write_lease6file(void)1210 static void write_lease6file(void)
1211 {
1212   int fd;
1213   uint32_t curr, tmp_time;
1214   int64_t timestamp;
1215   struct arg_list *listdls = gstate.dleases;
1216   dyn_lease6 *dls6;
1217 
1218   if ((fd = open(gconfig.lease6_file, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
1219     perror_msg("can't open %s ", gconfig.lease6_file);
1220   } else {
1221     curr = timestamp = time(NULL);
1222     timestamp = SWAP_BE64(timestamp);
1223     writeall(fd, &timestamp, sizeof(timestamp));
1224 
1225     while (listdls) {
1226       dls6 = (dyn_lease6*)listdls->arg;
1227       tmp_time = dls6->expires;
1228       dls6->expires -= curr;
1229       if ((int32_t) dls6->expires < 0) goto skip;
1230       dls6->expires = htonl(dls6->expires);
1231       writeall(fd, dls6, sizeof(dyn_lease6));
1232 skip:
1233       dls6->expires = tmp_time;
1234       listdls = listdls->next;
1235     }
1236     close(fd);
1237     if (gconfig.notify_file) {
1238       char *argv[3];
1239       argv[0] = gconfig.notify_file;
1240       argv[1] = gconfig.lease6_file;
1241       argv[2] = NULL;
1242       run_notify(argv);
1243     }
1244   }
1245 }
1246 
1247 // Update max lease time from options.
set_maxlease(void)1248 static void set_maxlease(void)
1249 {
1250   int count, size = ARRAY_LEN(options_list);
1251   for (count = 0; count < size; count++)
1252     if (options_list[count].val && options_list[count].code == (DHCP_OPT_LEASE_TIME)) {
1253       gconfig.max_lease_sec = *((uint32_t*)options_list[count].val);
1254       break;
1255     }
1256   if (!gconfig.max_lease_sec) gconfig.max_lease_sec = (60*60*24*10);// DEFAULT_LEASE_TIME;
1257 }
1258 
1259 // Returns lease time for client.
get_lease(uint32_t req_exp)1260 static uint32_t get_lease(uint32_t req_exp)
1261 {
1262   uint32_t now = time(NULL);
1263   req_exp = req_exp - now;
1264   if(addr_version == AF_INET6) {
1265     if ((req_exp <= 0) || req_exp > gconfig.pref_lifetime ||
1266         req_exp > gconfig.valid_lifetime) {
1267       if ((gconfig.pref_lifetime > gconfig.valid_lifetime)) {
1268         error_msg("The valid lifetime must be greater than the preferred lifetime, \
1269             setting to valid lifetime %u", gconfig.valid_lifetime);
1270         return gconfig.valid_lifetime;
1271       }
1272       return gconfig.pref_lifetime;
1273     }
1274   } else {
1275     if ((req_exp <= 0) || (req_exp > gconfig.max_lease_sec))
1276       return gconfig.max_lease_sec;
1277 
1278     if (req_exp < gconfig.min_lease_sec)
1279       return gconfig.min_lease_sec;
1280   }
1281 
1282   return req_exp;
1283 }
1284 
verifyip6_in_lease(uint8_t * nip6,uint8_t * duid,uint16_t ia_type,uint32_t iaid)1285 static int verifyip6_in_lease(uint8_t *nip6, uint8_t *duid, uint16_t ia_type, uint32_t iaid)
1286 {
1287   static_lease6 *sls6;
1288   struct arg_list *listdls;
1289 
1290   for (listdls = gstate.dleases; listdls; listdls = listdls->next) {
1291     if (!memcmp(((dyn_lease6*) listdls->arg)->lease_nip6, nip6, sizeof(uint32_t)*4))
1292       return -1;
1293 
1294     if (!memcmp(((dyn_lease6*) listdls->arg)->duid, duid, ((dyn_lease6*) listdls->arg)->duid_len)
1295         && ((dyn_lease6*) listdls->arg)->ia_type == ia_type)
1296       return -1;
1297   }
1298   for (sls6 = gstate.leases.sleases6; sls6; sls6 = sls6->next)
1299     if (memcmp(sls6->nip6, nip6, sizeof(uint32_t)*4)==0) return -2;
1300 
1301   if (memcmp(nip6, gconfig.start_ip6, sizeof(uint32_t)*4) < 0 ||
1302       memcmp(nip6, gconfig.end_ip6, sizeof(uint32_t)*4) > 0)
1303     return -3;
1304 
1305   return 0;
1306 }
1307 
1308 // Verify ip NIP in current leases ( assigned or not)
verifyip_in_lease(uint32_t nip,uint8_t mac[6])1309 static int verifyip_in_lease(uint32_t nip, uint8_t mac[6])
1310 {
1311   static_lease *sls;
1312   struct arg_list *listdls;
1313 
1314   for (listdls = gstate.dleases; listdls; listdls = listdls->next) {
1315     if (((dyn_lease*) listdls->arg)->lease_nip == nip) {
1316       if (((int32_t)(((dyn_lease*) listdls->arg)->expires) - time(NULL)) < 0)
1317         return 0;
1318       return -1;
1319     }
1320     if (!memcmp(((dyn_lease*) listdls->arg)->lease_mac, mac, 6)) return -1;
1321   }
1322   for (sls = gstate.leases.sleases; sls; sls = sls->next)
1323     if (sls->nip == nip) return -2;
1324 
1325   if ((ntohl(nip) < gconfig.start_ip) || (ntohl(nip) > gconfig.end_ip))
1326     return -3;
1327 
1328   return 0;
1329 }
1330 
1331 // add ip assigned_nip to dynamic lease.
addip_to_lease(uint32_t assigned_nip,uint8_t mac[6],uint32_t * req_exp,char * hostname,uint8_t update)1332 static int addip_to_lease(uint32_t assigned_nip, uint8_t mac[6], uint32_t *req_exp, char *hostname, uint8_t update)
1333 {
1334   dyn_lease *dls;
1335   struct arg_list *listdls = gstate.dleases;
1336   uint32_t now = time(NULL);
1337 
1338   while (listdls) {
1339     if (!memcmp(((dyn_lease*) listdls->arg)->lease_mac, mac, 6)) {
1340       if (update) *req_exp = get_lease(*req_exp + ((dyn_lease*) listdls->arg)->expires);
1341       ((dyn_lease*) listdls->arg)->expires = *req_exp + now;
1342       return 0;
1343     }
1344     listdls = listdls->next;
1345   }
1346 
1347   dls = xzalloc(sizeof(dyn_lease));
1348   memcpy(dls->lease_mac, mac, 6);
1349   dls->lease_nip = assigned_nip;
1350   if (hostname) memcpy(dls->hostname, hostname, 20);
1351 
1352   if (update) *req_exp = get_lease(*req_exp + now);
1353   dls->expires = *req_exp + now;
1354 
1355   listdls = xzalloc(sizeof(struct arg_list));
1356   listdls->next = gstate.dleases;
1357   listdls->arg = (char*)dls;
1358   gstate.dleases = listdls;
1359 
1360   return 0;
1361 }
1362 
addip6_to_lease(uint8_t * assigned_nip,uint8_t * duid,uint16_t duid_len,uint16_t ia_type,uint32_t iaid,uint32_t * lifetime,uint8_t update)1363 static int addip6_to_lease(uint8_t *assigned_nip, uint8_t *duid, uint16_t duid_len, uint16_t ia_type, uint32_t iaid, uint32_t *lifetime, uint8_t update)
1364 {
1365   dyn_lease6 *dls6;
1366   struct arg_list *listdls = gstate.dleases;
1367   uint32_t now = time(NULL);
1368 
1369   while (listdls) {
1370     if (!memcmp(((dyn_lease6*) listdls->arg)->duid, duid, ((dyn_lease6*) listdls->arg)->duid_len)) {
1371       if (update) *lifetime = get_lease(*lifetime + ((dyn_lease6*) listdls->arg)->expires);
1372       ((dyn_lease6*) listdls->arg)->expires = *lifetime + now;
1373       return 0;
1374     }
1375     listdls = listdls->next;
1376   }
1377 
1378   dls6 = xzalloc(sizeof(dyn_lease6));
1379   dls6->duid_len = duid_len;
1380   memcpy(dls6->duid, duid, duid_len);
1381   dls6->ia_type = ia_type;
1382   dls6->iaid = iaid;
1383   memcpy(dls6->lease_nip6, assigned_nip, sizeof(uint32_t)*4);
1384 
1385   if (update) *lifetime = get_lease(*lifetime + now);
1386   dls6->expires = *lifetime + now;
1387 
1388   listdls = xzalloc(sizeof(struct arg_list));
1389   listdls->next = gstate.dleases;
1390   listdls->arg = (char*)dls6;
1391   gstate.dleases = listdls;
1392 
1393   return 0;
1394 }
1395 
1396 // delete ip assigned_nip from dynamic lease.
delip_from_lease(uint32_t assigned_nip,uint8_t mac[6],uint32_t del_time)1397 static int delip_from_lease(uint32_t assigned_nip, uint8_t mac[6], uint32_t del_time)
1398 {
1399   struct arg_list *listdls = gstate.dleases;
1400 
1401   while (listdls) {
1402     if (!memcmp(((dyn_lease*) listdls->arg)->lease_mac, mac, 6)) {
1403       ((dyn_lease*) listdls->arg)->expires = del_time + time(NULL);
1404       return 0;
1405     }
1406     listdls = listdls->next;
1407   }
1408   return -1;
1409 }
1410 
1411 // returns a IP from static, dynamic leases or free ip pool, 0 otherwise.
getip_from_pool(uint32_t req_nip,uint8_t mac[6],uint32_t * req_exp,char * hostname)1412 static uint32_t getip_from_pool(uint32_t req_nip, uint8_t mac[6], uint32_t *req_exp, char *hostname)
1413 {
1414   uint32_t nip = 0;
1415   static_lease *sls = gstate.leases.sleases;
1416   struct arg_list *listdls = gstate.dleases, *tmp = NULL;
1417 
1418   if (req_nip && (!verifyip_in_lease(req_nip, mac))) nip = req_nip;
1419 
1420   if (!nip) {
1421     while (listdls) {
1422       if (!memcmp(((dyn_lease*)listdls->arg)->lease_mac, mac, 6)) {
1423         nip = ((dyn_lease*)listdls->arg)->lease_nip;
1424         if (tmp) tmp->next = listdls->next;
1425         else gstate.dleases = listdls->next;
1426         free(listdls->arg);
1427         free(listdls);
1428         if (verifyip_in_lease(nip, mac) < 0) nip = 0;
1429         break;
1430       }
1431       tmp = listdls;
1432       listdls = listdls->next;
1433     }
1434   }
1435   if (!nip) {
1436     while (sls) {
1437       if (memcmp(sls->mac, mac, 6) == 0) {
1438         nip = sls->nip;
1439         break;
1440       }
1441       sls = sls->next;
1442     }
1443   }
1444   if (!nip) {
1445     for (nip = htonl(gconfig.start_ip); ntohl(nip) <= gconfig.end_ip; ) {
1446       if (!verifyip_in_lease(nip, mac)) break;
1447       nip = ntohl(nip);
1448       nip = htonl(++nip);
1449     }
1450     if (ntohl(nip) > gconfig.end_ip) {
1451       nip = 0;
1452       infomsg(infomode, "can't find free IP in IP Pool.");
1453     }
1454   }
1455   if (nip) addip_to_lease(nip, mac, req_exp, hostname, 1);
1456   return nip;
1457 }
1458 
getip6_from_pool(uint8_t * duid,uint16_t duid_len,uint16_t ia_type,uint32_t iaid,uint32_t * lifetime)1459 static uint8_t *getip6_from_pool(uint8_t *duid, uint16_t duid_len, uint16_t ia_type, uint32_t iaid, uint32_t *lifetime)
1460 {
1461   static uint8_t nip6[16] = {0, };
1462   static_lease6 *sls6 = gstate.leases.sleases6;
1463   struct arg_list *listdls6 = gstate.dleases, *tmp = NULL;
1464 
1465   while(listdls6) {
1466     if (!memcmp(((dyn_lease6*)listdls6->arg)->duid, duid, duid_len)) {
1467       memcpy(nip6, ((dyn_lease6*)listdls6->arg)->lease_nip6, sizeof(nip6));
1468       if(tmp) tmp->next = listdls6->next;
1469       else gstate.dleases = listdls6->next;
1470       free(listdls6->arg);
1471       free(listdls6);
1472 
1473       if(verifyip6_in_lease(nip6, duid, ia_type, iaid) < 0)
1474         memset(nip6, 0, sizeof(nip6));
1475       break;
1476     }
1477     tmp = listdls6;
1478     listdls6 = listdls6->next;
1479   }
1480 
1481   if(!memcmp(nip6, (uint8_t[16]){0}, sizeof(uint32_t)*4)) {
1482     while(sls6) {
1483       if(!memcmp(sls6->duid, duid, 6)) {
1484         memcpy(nip6, sls6->nip6, sizeof(nip6));
1485         break;
1486       }
1487       sls6 = sls6->next;
1488     }
1489   }
1490 
1491   if(!memcmp(nip6, (uint8_t[16]){0}, sizeof(uint32_t)*4)) {
1492     memcpy(nip6, gconfig.start_ip6, sizeof(nip6));
1493     while(memcmp(nip6, gconfig.end_ip6, sizeof(nip6)) < 0) {
1494       if(!verifyip6_in_lease(nip6, duid, ia_type, iaid)) break;
1495       int i=sizeof(nip6);
1496       while(i--) {
1497         ++nip6[i];
1498         if (!nip6[i]) {
1499           if(i==(sizeof(nip6)-1)) ++nip6[i];
1500           ++nip6[i-1];
1501         } else
1502           break;
1503       }
1504     }
1505 
1506     if (memcmp(nip6, gconfig.end_ip6, sizeof(nip6)) > 0) {
1507       memset(nip6, 0, sizeof(nip6));
1508       infomsg(infomode, "can't find free IP in IPv6 Pool.");
1509     }
1510   }
1511 
1512   if(memcmp(nip6, (uint8_t[16]){0}, sizeof(uint32_t)*4)) {
1513     addip6_to_lease(nip6, duid, duid_len, ia_type, iaid, lifetime, 1);
1514     infomsg(infomode, "Assigned IPv6 %02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
1515         nip6[0], nip6[1], nip6[2], nip6[3], nip6[4], nip6[5], nip6[6], nip6[7], nip6[8],
1516         nip6[9], nip6[10], nip6[11], nip6[12], nip6[13], nip6[14], nip6[15]);
1517   }
1518   return nip6;
1519 }
1520 
read_leasefile(void)1521 static void read_leasefile(void)
1522 {
1523   uint32_t passed, ip;
1524   int32_t tmp_time;
1525   int64_t timestamp;
1526   dyn_lease *dls;
1527   int fd = open(gconfig.lease_file, O_RDONLY);
1528 
1529   dls = xzalloc(sizeof(dyn_lease));
1530 
1531   if (read(fd, &timestamp, sizeof(timestamp)) != sizeof(timestamp))
1532     goto lease_error_exit;
1533 
1534   timestamp = SWAP_BE64(timestamp);
1535   passed = time(NULL) - timestamp;
1536   if ((uint64_t)passed > 12 * 60 * 60) goto lease_error_exit;
1537 
1538   while (read(fd, dls, sizeof(dyn_lease)) == sizeof(dyn_lease)) {
1539     ip = ntohl(dls->lease_nip);
1540     if (ip >= gconfig.start_ip && ip <= gconfig.end_ip) {
1541       tmp_time = ntohl(dls->expires) - passed;
1542       if (tmp_time < 0) continue;
1543       addip_to_lease(dls->lease_nip, dls->lease_mac,
1544           (uint32_t*)&tmp_time, dls->hostname, 0);
1545     }
1546   }
1547 lease_error_exit:
1548   free(dls);
1549   close(fd);
1550 }
1551 
read_lease6file(void)1552 static void read_lease6file(void)
1553 {
1554   uint32_t passed;
1555   uint32_t tmp_time;
1556   int64_t timestamp;
1557   dyn_lease6 *dls6;
1558   int fd = open(gconfig.lease6_file, O_RDONLY);
1559 
1560   dls6 = xzalloc(sizeof(dyn_lease6));
1561 
1562   if (read(fd, &timestamp, sizeof(timestamp)) != sizeof(timestamp))
1563     goto lease6_error_exit;
1564 
1565   timestamp = SWAP_BE64(timestamp);
1566   passed = time(NULL) - timestamp;
1567   if ((uint64_t)passed > 12 * 60 * 60) goto lease6_error_exit;
1568 
1569   while (read(fd, dls6, sizeof(dyn_lease6)) == sizeof(dyn_lease6)) {
1570     if (memcmp(dls6->lease_nip6, gconfig.start_ip6, sizeof(uint32_t)*4) > 0 &&
1571         memcmp(dls6->lease_nip6, gconfig.end_ip6, sizeof(uint32_t)*4) < 0) {
1572       tmp_time = ntohl(dls6->expires) - passed;
1573       if (tmp_time < 0U) continue;
1574       addip6_to_lease(dls6->lease_nip6, dls6->duid, dls6->duid_len, dls6->ia_type, dls6->iaid,
1575           (uint32_t*)&tmp_time, 0);
1576     }
1577   }
1578 
1579 lease6_error_exit:
1580   free(dls6);
1581   close(fd);
1582 }
1583 
dhcpd_main(void)1584 void dhcpd_main(void)
1585 {
1586   struct timeval tv;
1587   int retval, i;
1588   char *optptr, msgtype = 0, *hstname = 0, transactionid[3] = {0};
1589   unsigned short optlen = 0;
1590   unsigned waited = 0, serverid = 0, requested_nip = 0, reqested_lease = 0,
1591            ip_pool_size = 0;
1592   fd_set rfds;
1593 
1594   infomode = LOG_CONSOLE;
1595   if (!FLAG(f)) {
1596     daemon(0, 0);
1597     infomode = LOG_SILENT;
1598   }
1599   if (FLAG(S)) {
1600     openlog("UDHCPD :", LOG_PID, LOG_DAEMON);
1601     infomode |= LOG_SYSTEM;
1602   }
1603   setlinebuf(stdout);
1604   //DHCPD_CONF_FILE
1605   parse_server_config((toys.optc==1) ? *toys.optargs: "/etc/dhcpd.conf",
1606     keywords);
1607   infomsg(infomode, "toybox dhcpd started");
1608 
1609   if (FLAG(6)) {
1610     addr_version = AF_INET6;
1611     gconfig.t1 = ntohl(gconfig.t1);
1612     gconfig.t2 = ntohl(gconfig.t2);
1613     gconfig.pref_lifetime = ntohl(gconfig.pref_lifetime);
1614     gconfig.valid_lifetime = ntohl(gconfig.valid_lifetime);
1615     gconfig.port = 547;
1616     for(i=0; i<4; i++)
1617       ip_pool_size += (gconfig.end_ip6[i]-gconfig.start_ip6[i])<<((3-i)*8);
1618   } else {
1619     gconfig.start_ip = ntohl(gconfig.start_ip);
1620     gconfig.end_ip = ntohl(gconfig.end_ip);
1621     ip_pool_size = gconfig.end_ip - gconfig.start_ip + 1;
1622   }
1623 
1624   if (gconfig.max_leases > ip_pool_size) {
1625     error_msg("max_leases=%u is too big, setting to %u",
1626         (unsigned) gconfig.max_leases, ip_pool_size);
1627     gconfig.max_leases = ip_pool_size;
1628   }
1629   write_pid(gconfig.pidfile);
1630   set_maxlease();
1631   if (TT.i) gconfig.interface = TT.i;
1632   if (TT.p) gconfig.port = TT.p;
1633   (addr_version==AF_INET6) ? read_lease6file() : read_leasefile();
1634 
1635   if (get_interface(gconfig.interface, &gconfig.ifindex,
1636         (addr_version==AF_INET6)? (void*)gconfig.server_nip6 :
1637         (void*)&gconfig.server_nip, gconfig.server_mac) < 0)
1638     perror_exit("Failed to get interface %s", gconfig.interface);
1639   setup_signal();
1640   if (addr_version==AF_INET6) open_listensock6();
1641   else {
1642     gconfig.server_nip = htonl(gconfig.server_nip);
1643     open_listensock();
1644   }
1645 
1646   fcntl(gstate.listensock, F_SETFD, FD_CLOEXEC);
1647 
1648   for (;;) {
1649     uint32_t timestmp = time(NULL);
1650     FD_ZERO(&rfds);
1651     FD_SET(gstate.listensock, &rfds);
1652     FD_SET(sigfd.rd, &rfds);
1653     tv.tv_sec = gconfig.auto_time - waited;
1654     tv.tv_usec = 0;
1655     retval = 0;
1656     serverid = 0;
1657     msgtype = 0;
1658 
1659     int maxfd = (sigfd.rd > gstate.listensock)? sigfd.rd : gstate.listensock;
1660     dbg("select waiting ....\n");
1661     retval = select(maxfd + 1, &rfds, NULL, NULL, (gconfig.auto_time?&tv:NULL));
1662     if (retval < 0) {
1663       if (errno == EINTR) {
1664         waited += (unsigned) time(NULL) - timestmp;
1665         continue;
1666       }
1667       dbg("Error in select wait again...\n");
1668       continue;
1669     }
1670     if (!retval) { // Timed out
1671       dbg("select wait Timed Out...\n");
1672       waited = 0;
1673       (addr_version == AF_INET6)? write_lease6file() : write_leasefile();
1674       if (get_interface(gconfig.interface, &gconfig.ifindex,
1675             (addr_version==AF_INET6)? (void*)gconfig.server_nip6 :
1676             (void*)&gconfig.server_nip, gconfig.server_mac)<0)
1677         perror_exit("Failed to get interface %s", gconfig.interface);
1678       if(addr_version != AF_INET6) {
1679         gconfig.server_nip = htonl(gconfig.server_nip);
1680       }
1681       continue;
1682     }
1683     if (FD_ISSET(sigfd.rd, &rfds)) { // Some Activity on RDFDs : is signal
1684       unsigned char sig;
1685       if (read(sigfd.rd, &sig, 1) != 1) {
1686         dbg("signal read failed.\n");
1687         continue;
1688       }
1689       switch (sig) {
1690         case SIGUSR1:
1691           infomsg(infomode, "Received SIGUSR1");
1692           (addr_version==AF_INET6)? write_lease6file() : write_leasefile();
1693           continue;
1694         case SIGTERM:
1695           infomsg(infomode, "received sigterm");
1696           (addr_version==AF_INET6)? write_lease6file() : write_leasefile();
1697           unlink(gconfig.pidfile);
1698           exit(0);
1699           break;
1700         default: break;
1701       }
1702     }
1703     if (FD_ISSET(gstate.listensock, &rfds)) { // Some Activity on RDFDs : is socket
1704       dbg("select listen sock read\n");
1705       if(addr_version==AF_INET6) {
1706         void *client_duid, *server_duid, *client_ia_na, *server_ia_na,
1707              *client_ia_pd;
1708         uint8_t client_lla[6] = {0,};
1709         uint16_t client_duid_len = 0, server_duid_len = 0, server_ia_na_len = 0,
1710                  client_ia_na_len = 0, client_ia_pd_len = 0;
1711 
1712         if(read_packet6() < 0) {
1713           open_listensock6();
1714           continue;
1715         }
1716         waited += time(NULL) - timestmp;
1717 
1718         memcpy(&gstate.rqcode, &gstate.rcvd.rcvd_pkt6.msgtype, sizeof(uint8_t));
1719         memcpy(&transactionid, &gstate.rcvd.rcvd_pkt6.transaction_id,
1720             sizeof(transactionid));
1721 
1722         if (!gstate.rqcode || gstate.rqcode < DHCP6SOLICIT ||
1723             gstate.rqcode > DHCP6RELAYREPLY) {
1724           dbg("no or bad message type option, ignoring packet.\n");
1725           continue;
1726         }
1727         if (memcmp(gstate.rcvd.rcvd_pkt6.transaction_id, transactionid, 3)) {
1728           dbg("no or bad transaction id, ignoring packet.\n");
1729           continue;
1730         }
1731 
1732         waited += time(NULL) - timestmp;
1733         switch (gstate.rqcode) {
1734           case DHCP6SOLICIT:
1735             dbg("Message Type: DHCP6SOLICIT\n");
1736             optptr = prepare_send_pkt6(DHCP6ADVERTISE);
1737             optlen = 0;
1738 
1739             //TODO policy check
1740             //TODO Receive: ORO check (e.g. DNS)
1741 
1742             //Receive: Client Identifier (DUID)
1743             get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
1744                 DHCP6_OPT_CLIENTID, &client_duid_len, &client_duid);
1745 
1746             //Receive: Identity Association for Non-temporary Address
1747             if(get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
1748                   DHCP6_OPT_IA_NA, &client_ia_na_len, &client_ia_na)) {
1749               uint16_t ia_addr_len = sizeof(struct optval_ia_addr);
1750               void *ia_addr, *status_code;
1751               char *status_code_msg;
1752               uint16_t status_code_len = 0;
1753               server_ia_na_len = sizeof(struct optval_ia_na);
1754 
1755               //IA Address
1756               ia_addr = xzalloc(ia_addr_len);
1757               struct optval_ia_addr *ia_addr_p = (struct optval_ia_addr*)ia_addr;
1758               (*ia_addr_p).pref_lifetime = gconfig.pref_lifetime;
1759               (*ia_addr_p).valid_lifetime = gconfig.valid_lifetime;
1760               memcpy(&(*ia_addr_p).ipv6_addr,
1761                   getip6_from_pool(client_duid, client_duid_len,
1762                     DHCP6_OPT_IA_NA, (*(struct optval_ia_na*) client_ia_na).iaid,
1763                     &(*ia_addr_p).pref_lifetime), sizeof(uint32_t)*4);
1764               server_ia_na_len += (ia_addr_len+4);
1765 
1766               //Status Code
1767               if(memcmp((*ia_addr_p).ipv6_addr, (uint8_t[16]){0}, sizeof(uint32_t)*4)) {
1768                 status_code_msg = xstrdup("Assigned an address.");
1769                 status_code_len = strlen(status_code_msg)+1;
1770                 status_code = xzalloc(status_code_len);
1771                 struct optval_status_code *status_code_p =
1772                   (struct optval_status_code*)status_code;
1773                 (*status_code_p).status_code = htons(DHCP6_STATUS_SUCCESS);
1774                 memcpy((*status_code_p).status_msg, status_code_msg,
1775                     status_code_len);
1776                 server_ia_na_len += (status_code_len+4);
1777                 free(status_code_msg);
1778               } else {
1779                 status_code_msg = xstrdup("There's no available address.");
1780                 status_code_len = strlen(status_code_msg)+1;
1781                 status_code = xzalloc(status_code_len);
1782                 struct optval_status_code *status_code_p =
1783                   (struct optval_status_code*)status_code;
1784                 (*status_code_p).status_code = htons(DHCP6_STATUS_NOADDRSAVAIL);
1785                 memcpy((*status_code_p).status_msg, status_code_msg,
1786                     status_code_len);
1787                 server_ia_na_len += (status_code_len+4);
1788                 server_ia_na_len -= (ia_addr_len+4);
1789                 ia_addr_len = 0;
1790                 free(ia_addr);
1791                 free(status_code_msg);
1792                 //TODO send failed status code
1793                 break;
1794               }
1795 
1796               //combine options
1797               server_ia_na = xzalloc(server_ia_na_len);
1798               struct optval_ia_na *ia_na_p = (struct optval_ia_na*)server_ia_na;
1799               (*ia_na_p).iaid = (*(struct optval_ia_na*)client_ia_na).iaid;
1800               (*ia_na_p).t1 = gconfig.t1;
1801               (*ia_na_p).t2 = gconfig.t2;
1802 
1803               uint8_t* ia_na_optptr = (*ia_na_p).optval;
1804               if(ia_addr_len) {
1805                 set_optval6(ia_na_optptr, DHCP6_OPT_IA_ADDR, ia_addr, ia_addr_len);
1806                 ia_na_optptr += (ia_addr_len + 4);
1807                 free(ia_addr);
1808               }
1809               if(status_code_len) {
1810                 set_optval6(ia_na_optptr, DHCP6_OPT_STATUS_CODE, status_code,
1811                     status_code_len);
1812                 ia_na_optptr += (status_code_len);
1813                 free(status_code);
1814               }
1815 
1816               //Response: Identity Association for Non-temporary Address
1817               optptr = set_optval6(optptr, DHCP6_OPT_IA_NA, server_ia_na,
1818                   server_ia_na_len);
1819               optlen += (server_ia_na_len + 4);
1820               free(client_ia_na);free(server_ia_na);
1821             }
1822             //Receive: Identity Association for Prefix Delegation
1823             else if(get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
1824                   DHCP6_OPT_IA_PD, &client_ia_pd_len, &client_ia_pd)) {
1825 
1826               //TODO
1827               //Response: Identity Association for Prefix Delegation
1828             }
1829 
1830             //DUID type: link-layer address plus time
1831             if(ntohs((*(struct optval_duid_llt*)client_duid).type) ==
1832                 DHCP6_DUID_LLT) {
1833               server_duid_len = 8+sizeof(gconfig.server_mac);
1834               server_duid = xzalloc(server_duid_len);
1835               struct optval_duid_llt *server_duid_p =
1836                 (struct optval_duid_llt*)server_duid;
1837               (*server_duid_p).type = htons(1);
1838               (*server_duid_p).hwtype = htons(1);
1839               (*server_duid_p).time = htonl((uint32_t)
1840                   (time(NULL) - 946684800) & 0xffffffff);
1841               memcpy((*server_duid_p).lladdr, gconfig.server_mac,
1842                   sizeof(gconfig.server_mac));
1843               memcpy(&client_lla, (*(struct optval_duid_llt*)client_duid).lladdr,
1844                   sizeof(client_lla));
1845 
1846               //Response: Server Identifier (DUID)
1847               optptr = set_optval6(optptr, DHCP6_OPT_SERVERID, server_duid,
1848                   server_duid_len);
1849               optlen += (server_duid_len + 4);
1850               //Response: Client Identifier
1851               optptr = set_optval6(optptr, DHCP6_OPT_CLIENTID, client_duid,
1852                   client_duid_len);
1853               optlen += (client_duid_len + 4);
1854               free(client_duid);free(server_duid);
1855             }
1856 
1857             send_packet6(0, client_lla, optlen);
1858             write_lease6file();
1859             break;
1860           case DHCP6REQUEST:
1861             dbg("Message Type: DHCP6REQUEST\n");
1862             optptr = prepare_send_pkt6(DHCP6REPLY);
1863             optlen = 0;
1864 
1865             //Receive: Client Identifier (DUID)
1866             get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
1867                 DHCP6_OPT_CLIENTID, &client_duid_len, &client_duid);
1868             optptr = set_optval6(optptr, DHCP6_OPT_CLIENTID, client_duid,
1869                 client_duid_len);
1870             optlen += (client_duid_len + 4);
1871             memcpy(client_lla, (*(struct optval_duid_llt*)client_duid).lladdr,
1872                 sizeof(client_lla));
1873 
1874             //Receive: Identity Association for Non-temporary Address
1875             if(get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
1876                   DHCP6_OPT_IA_NA, &client_ia_na_len, &client_ia_na)) {
1877               uint16_t ia_addr_len = 0, status_code_len = 0;
1878               void *ia_addr, *status_code;
1879               uint16_t server_ia_na_len = sizeof(struct optval_ia_na);
1880               char *status_code_msg;
1881 
1882               //Check IA Address
1883               get_optval6((uint8_t*)(*(struct optval_ia_na*)client_ia_na).optval,
1884                   DHCP6_OPT_IA_ADDR, &ia_addr_len, &ia_addr);
1885               struct optval_ia_addr *ia_addr_p = (struct optval_ia_addr*)ia_addr;
1886               if(verifyip6_in_lease((*ia_addr_p).ipv6_addr, client_duid,
1887                     DHCP6_OPT_IA_NA, (*(struct optval_ia_na*)client_ia_na).iaid)
1888                   == -1) {
1889                 server_ia_na_len += (ia_addr_len + 4);
1890                 //Add Status Code
1891                 status_code_msg = xstrdup("Assigned an address.");
1892                 status_code_len = strlen(status_code_msg) + 1;
1893                 status_code = xzalloc(status_code_len);
1894                 struct optval_status_code *status_code_p =
1895                   (struct optval_status_code*)status_code;
1896                 (*status_code_p).status_code = htons(DHCP6_STATUS_SUCCESS);
1897                 memcpy((*status_code_p).status_msg, status_code_msg,
1898                     status_code_len);
1899                 server_ia_na_len += (status_code_len+4);
1900               } else {
1901                 //TODO send failed status code
1902                 break;
1903               }
1904 
1905               //combine options
1906               server_ia_na = xzalloc(server_ia_na_len);
1907               struct optval_ia_na *ia_na_p = (struct optval_ia_na*)server_ia_na;
1908               (*ia_na_p).iaid = (*(struct optval_ia_na*)client_ia_na).iaid;
1909               (*ia_na_p).t1 = gconfig.t1;
1910               (*ia_na_p).t2 = gconfig.t2;
1911 
1912               uint8_t* ia_na_optptr = (*ia_na_p).optval;
1913               ia_na_optptr = set_optval6(ia_na_optptr, DHCP6_OPT_IA_ADDR,
1914                   ia_addr, ia_addr_len);
1915               free(ia_addr);
1916 
1917               if(status_code_len) {
1918                 ia_na_optptr = set_optval6(ia_na_optptr, DHCP6_OPT_STATUS_CODE,
1919                     status_code, status_code_len);
1920                 free(status_code);
1921               }
1922 
1923               //Response: Identity Association for Non-temporary Address
1924               //(Status Code added)
1925               optptr = set_optval6(optptr, DHCP6_OPT_IA_NA,
1926                   server_ia_na, server_ia_na_len);
1927               optlen += (server_ia_na_len + 4);
1928               free(client_ia_na);free(server_ia_na);
1929             }
1930 
1931             //Receive: Server Identifier (DUID)
1932             get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
1933                 DHCP6_OPT_SERVERID, &server_duid_len, &server_duid);
1934             optptr = set_optval6(optptr, DHCP6_OPT_SERVERID,
1935                 server_duid, server_duid_len);
1936             optlen += (server_duid_len + 4);
1937 
1938             free(client_duid); free(server_duid);
1939 
1940             send_packet6(0, client_lla, optlen);
1941             write_lease6file();
1942             break;
1943           case DHCP6DECLINE:  //TODO
1944           case DHCP6RENEW:    //TODO
1945           case DHCP6REBIND:   //TODO
1946           case DHCP6RELEASE:
1947             dbg("Message Type: DHCP6RELEASE\n");
1948             optptr = prepare_send_pkt6(DHCP6REPLY);
1949             break;
1950           default:
1951             dbg("Message Type : %u\n", gstate.rqcode);
1952             break;
1953         }
1954 
1955       } else {
1956         if(read_packet() < 0) {
1957           open_listensock();
1958           continue;
1959         }
1960         waited += time(NULL) - timestmp;
1961 
1962         get_optval((uint8_t*)&gstate.rcvd.rcvd_pkt.options,
1963             DHCP_OPT_MESSAGE_TYPE, &gstate.rqcode);
1964         if (gstate.rqcode == 0 || gstate.rqcode < DHCPDISCOVER
1965             || gstate.rqcode > DHCPINFORM) {
1966           dbg("no or bad message type option, ignoring packet.\n");
1967           continue;
1968         }
1969         get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
1970             DHCP_OPT_SERVER_ID, &serverid);
1971         if (serverid && (serverid != gconfig.server_nip)) {
1972           dbg("server ID doesn't match, ignoring packet.\n");
1973           continue;
1974         }
1975 
1976         waited += time(NULL) - timestmp;
1977         switch (gstate.rqcode) {
1978           case DHCPDISCOVER:
1979             msgtype = DHCPOFFER;
1980             dbg("Message Type : DHCPDISCOVER\n");
1981             get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
1982                 DHCP_OPT_REQUESTED_IP, &requested_nip);
1983             get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
1984                 DHCP_OPT_HOST_NAME, &hstname);
1985             reqested_lease = gconfig.offer_time;
1986             get_reqparam(&gstate.rqopt);
1987             optptr = prepare_send_pkt();
1988             gstate.send.send_pkt.yiaddr = getip_from_pool(requested_nip,
1989                 gstate.rcvd.rcvd_pkt.chaddr, &reqested_lease, hstname);
1990             if(!gstate.send.send_pkt.yiaddr){
1991               msgtype = DHCPNAK;
1992               optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1);
1993               send_packet(1);
1994               break;
1995             }
1996             get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
1997                 DHCP_OPT_LEASE_TIME, &reqested_lease);
1998             reqested_lease = htonl(get_lease(reqested_lease + time(NULL)));
1999             optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1);
2000             optptr = set_optval(optptr, DHCP_OPT_SERVER_ID, &gconfig.server_nip, 4);
2001             optptr = set_optval(optptr, DHCP_OPT_LEASE_TIME, &reqested_lease, 4);
2002             optptr = set_reqparam(optptr, gstate.rqopt);
2003             send_packet(1);
2004             break;
2005           case DHCPREQUEST:
2006             msgtype = DHCPACK;
2007             dbg("Message Type : DHCPREQUEST\n");
2008             optptr = prepare_send_pkt();
2009             get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
2010                 DHCP_OPT_REQUESTED_IP, &requested_nip);
2011             get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
2012                 DHCP_OPT_LEASE_TIME, &reqested_lease);
2013             get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
2014                 DHCP_OPT_HOST_NAME, &hstname);
2015             gstate.send.send_pkt.yiaddr = getip_from_pool(requested_nip,
2016                 gstate.rcvd.rcvd_pkt.chaddr, &reqested_lease, hstname);
2017             if (!serverid) reqested_lease = gconfig.max_lease_sec;
2018             if (!gstate.send.send_pkt.yiaddr) {
2019               msgtype = DHCPNAK;
2020               optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1);
2021               send_packet(1);
2022               break;
2023             }
2024             optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1);
2025             optptr = set_optval(optptr, DHCP_OPT_SERVER_ID, &gconfig.server_nip, 4);
2026             reqested_lease = htonl(reqested_lease);
2027             optptr = set_optval(optptr, DHCP_OPT_LEASE_TIME, &reqested_lease, 4);
2028             send_packet(1);
2029             write_leasefile();
2030             break;
2031           case DHCPDECLINE:// FALL THROUGH
2032           case DHCPRELEASE:
2033             dbg("Message Type : DHCPDECLINE or DHCPRELEASE \n");
2034             get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
2035                 DHCP_OPT_SERVER_ID, &serverid);
2036             if (serverid != gconfig.server_nip) break;
2037             get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
2038                 DHCP_OPT_REQUESTED_IP, &requested_nip);
2039             delip_from_lease(requested_nip, gstate.rcvd.rcvd_pkt.chaddr,
2040                 (gstate.rqcode==DHCPRELEASE)?0:gconfig.decline_time);
2041             break;
2042           default:
2043             dbg("Message Type : %u\n", gstate.rqcode);
2044             break;
2045         }
2046       }
2047     }
2048   }
2049 }
2050