1 /* dhcpd.c - DHCP server for dynamic network configuration.
3 * Copyright 2013 Madhur Verma <mad.flexi@gmail.com>
4 * Copyright 2013 Kyungwan Han <asura321@gamil.com>
5 * Copyright 2015 Yeongdeok Suh <skyducks111@gmail.com>
8 USE_DHCPD(NEWTOY(dhcpd, ">1P#<0>65535=67fi:S46[!46]", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
14 usage: dhcpd [-46fS] [-i IFACE] [-P N] [CONFFILE]
19 -P N Use port N (default ipv4 67, ipv6 547)
20 -4, -6 Run as a DHCPv4 or DHCPv6 server
23 bool "debugging messeges ON/OFF"
31 * - Working as an relay agent
32 * - Rapid commit option support
33 * - Additional packet options (commented on the middle of sources)
34 * - Create common modules
40 #include <linux/sockios.h>
41 #include <linux/if_ether.h>
43 // Todo: headers not in posix
44 #include <netinet/ip.h>
45 #include <netinet/ip6.h>
46 #include <netinet/udp.h>
47 #include <netpacket/packet.h>
49 # define dbg(fmt, arg...) printf(fmt, ##arg)
51 #define flag_get(f,v,d) ((toys.optflags & (f)) ? (v) : (d))
52 #define flag_chk(f) ((toys.optflags & (f)) ? 1 : 0)
54 #define LOG_SILENT 0x0
55 #define LOG_CONSOLE 0x1
56 #define LOG_SYSTEM 0x2
58 #define DHCP_MAGIC 0x63825363
60 #define DHCPDISCOVER 1
69 #define DHCP6SOLICIT 1
70 #define DHCP6ADVERTISE 2 // server -> client
71 #define DHCP6REQUEST 3
72 #define DHCP6CONFIRM 4
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
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)
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
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
117 #define DHCP6_STATUS_SUCCESS 0
118 #define DHCP6_STATUS_NOADDRSAVAIL 2
120 #define DHCP6_DUID_LLT 1
121 #define DHCP6_DUID_EN 2
122 #define DHCP6_DUID_LL 3
123 #define DHCP6_DUID_UUID 4
130 struct config_keyword {
132 int (*handler)(const char *str, void *var);
137 typedef struct __attribute__((packed)) dhcp_msg_s {
153 uint8_t options[308];
156 typedef struct __attribute__((packed)) dhcp6_msg_s {
158 uint8_t transaction_id[3];
159 uint8_t options[524];
162 typedef struct __attribute__((packed)) dhcp_raw_s {
168 typedef struct __attribute__((packed)) dhcp6_raw_s {
174 typedef struct static_lease_s {
175 struct static_lease_s *next;
180 typedef struct static_lease6_s {
181 struct static_lease6_s *next;
192 uint8_t lease_mac[6];
202 uint32_t lease_nip6[4];
206 typedef struct option_val_s {
213 struct __attribute__((packed)) optval_duid_llt {
220 struct __attribute__((packed)) optval_ia_na {
225 struct __attribute__((packed)) optval_ia_addr {
226 uint32_t ipv6_addr[4];
227 uint32_t pref_lifetime;
228 uint32_t valid_lifetime;
230 struct __attribute__((packed)) optval_status_code {
231 uint16_t status_code;
235 typedef struct __attribute__((__may_alias__)) server_config_s {
236 char *interface; // interface to use
238 uint32_t server_nip6[4];
241 uint8_t server_mac[6]; // our MAC address (used only for ARP probing)
242 void *options[256]; // list of DHCP options loaded from the config file
243 /* start,end are in host order: we need to compare start <= ip <= end*/
244 uint32_t start_ip; // start address of leases, in host order
245 uint32_t end_ip; // end of leases, in host order
246 uint32_t start_ip6[4]; // start address of leases, in IPv6 mode
247 uint32_t end_ip6[4]; // end of leases, in IPv6 mode
248 uint32_t max_lease_sec; // maximum lease time (host order)
249 uint32_t min_lease_sec; // minimum lease time a client can request
250 uint32_t max_leases; // maximum number of leases (including reserved addresses)
251 uint32_t auto_time; // how long should dhcpd wait before writing a config file.
252 // if this is zero, it will only write one on SIGUSR1
253 uint32_t decline_time; // how long an address is reserved if a client returns a
255 uint32_t conflict_time; // how long an arp conflict offender is leased for
256 uint32_t offer_time; // how long an offered address is reserved
257 uint32_t siaddr_nip; // "next server" bootp option
261 char *notify_file; // what to run whenever leases are written
262 char *sname; // bootp server name
263 char *boot_file; // bootp boot file option
264 uint32_t pref_lifetime;
265 uint32_t valid_lifetime;
267 struct static_lease *static_leases; // List of ip/mac pairs to assign static leases
270 typedef struct __attribute__((__may_alias__)) server_state_s {
275 dhcp6_msg_t rcvd_pkt6;
280 dhcp6_msg_t send_pkt6;
283 static_lease *sleases;
284 static_lease6 *sleases6;
286 struct arg_list *dleases;
289 static option_val_t options_list[] = {
290 {"lease" , DHCP_NUM32 | 0x33, NULL, 0},
291 {"subnet" , DHCP_IP | 0x01, NULL, 0},
292 {"broadcast" , DHCP_IP | 0x1c, NULL, 0},
293 {"router" , DHCP_IP | 0x03, NULL, 0},
294 {"ipttl" , DHCP_NUM8 | 0x17, NULL, 0},
295 {"mtu" , DHCP_NUM16 | 0x1a, NULL, 0},
296 {"hostname" , DHCP_STRING | 0x0c, NULL, 0},
297 {"domain" , DHCP_STRING | 0x0f, NULL, 0},
298 {"search" , DHCP_STRLST | 0x77, NULL, 0},
299 {"nisdomain" , DHCP_STRING | 0x28, NULL, 0},
300 {"timezone" , DHCP_NUM32 | 0x02, NULL, 0},
301 {"tftp" , DHCP_STRING | 0x42, NULL, 0},
302 {"bootfile" , DHCP_STRING | 0x43, NULL, 0},
303 {"bootsize" , DHCP_NUM16 | 0x0d, NULL, 0},
304 {"rootpath" , DHCP_STRING | 0x11, NULL, 0},
305 {"wpad" , DHCP_STRING | 0xfc, NULL, 0},
306 {"serverid" , DHCP_IP | 0x36, NULL, 0},
307 {"message" , DHCP_STRING | 0x38, NULL, 0},
308 {"vlanid" , DHCP_NUM32 | 0x84, NULL, 0},
309 {"vlanpriority" , DHCP_NUM32 | 0x85, NULL, 0},
310 {"dns" , DHCP_IPLIST | 0x06, NULL, 0},
311 {"wins" , DHCP_IPLIST | 0x2c, NULL, 0},
312 {"nissrv" , DHCP_IPLIST | 0x29, NULL, 0},
313 {"ntpsrv" , DHCP_IPLIST | 0x2a, NULL, 0},
314 {"lprsrv" , DHCP_IPLIST | 0x09, NULL, 0},
315 {"swapsrv" , DHCP_IP | 0x10, NULL, 0},
316 {"routes" , DHCP_STCRTS | 0x21, NULL, 0},
317 {"staticroutes" , DHCP_STCRTS | 0x79, NULL, 0},
318 {"msstaticroutes" , DHCP_STCRTS | 0xf9, NULL, 0},
321 struct fd_pair { int rd; int wr; };
322 static server_config_t gconfig;
323 static server_state_t gstate;
324 static uint8_t infomode;
325 static struct fd_pair sigfd;
326 static int constone = 1;
327 static sa_family_t addr_version = AF_INET;
329 static void htonl6(uint32_t *host_order, uint32_t *network_order)
333 error_msg("NULL ipv6 address");
335 for(i=0;i<4;i++) network_order[i] = htonl(host_order[i]);
339 static void ntohl6(uint32_t *network_order, uint32_t *host_order)
343 error_msg("NULL ipv6 address");
345 for(i=0;i<4;i++) host_order[i] = ntohl(network_order[i]);
349 // calculate options size.
350 static int dhcp_opt_size(uint8_t *optionptr)
353 for(;optionptr[i] != 0xff; i++)
354 if(optionptr[i] != 0x00) i += optionptr[i + 1] + 2 -1;
358 // calculates checksum for dhcp messeges.
359 static uint16_t dhcp_checksum(void *addr, int count)
362 uint16_t tmp = 0, *source = (uint16_t *)addr;
369 *(uint8_t*)&tmp = *(uint8_t*)source;
372 while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
376 // gets information of INTERFACE and updates IFINDEX, MAC and IP
377 static int get_interface(const char *interface, int *ifindex, uint32_t *oip,
381 struct sockaddr_in *ip;
382 struct sockaddr_in6 ip6;
383 int fd = xsocket(addr_version, SOCK_RAW, IPPROTO_RAW);
384 char ipv6_addr[40] = {0,};
386 req.ifr_addr.sa_family = addr_version;
387 xstrncpy(req.ifr_name, (char *)interface, IFNAMSIZ);
389 xioctl(fd, SIOCGIFFLAGS, &req);
391 if (!(req.ifr_flags & IFF_UP)) return -1;
393 if (addr_version == AF_INET6) {
395 FILE *fd6 = fopen("/proc/net/if_inet6", "r");
398 while(fgets(toybuf, sizeof(toybuf), fd6)) {
399 if (!strstr(toybuf, interface))
402 if (sscanf(toybuf, "%32s \n", ipv6_addr) != 1)
405 if (strstr(ipv6_addr, "fe80")) break;
410 char *ptr = ipv6_addr+sizeof(ipv6_addr)-1;
412 // convert giant hex string into colon-spearated ipv6 address by
413 // inserting ':' every 4 characters.
415 if ((*(ptr--) = ipv6_addr[i])) if (!(i&3)) *(ptr--) = ':';
417 dbg("ipv6 %s\n", ipv6_addr);
418 if(inet_pton(AF_INET6, ipv6_addr, &ip6.sin6_addr) <= 0)
419 error_msg("inet : the ipv6 address is not proper");
421 ntohl6(ip6.sin6_addr.s6_addr32, oip);
425 xioctl(fd, SIOCGIFADDR, &req);
426 ip = (struct sockaddr_in*) &req.ifr_addr;
427 dbg("IP %s\n", inet_ntoa(ip->sin_addr));
428 *oip = ntohl(ip->sin_addr.s_addr);
433 xioctl(fd, SIOCGIFINDEX, &req);
434 dbg("Adapter index %d\n", req.ifr_ifindex);
435 *ifindex = req.ifr_ifindex;
438 xioctl(fd, SIOCGIFHWADDR, &req);
439 memcpy(mac, req.ifr_hwaddr.sa_data, 6);
440 dbg("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
448 *logs messeges to syslog or console
449 *opening the log is still left with applet.
450 *FIXME: move to more relevent lib. probably libc.c
452 static void infomsg(uint8_t infomode, char *s, ...)
458 if (infomode == LOG_SILENT) return;
461 used = vsnprintf(NULL, 0, s, t);
466 vsnprintf(msg, used, s, p);
469 if (infomode & LOG_SYSTEM) syslog(LOG_INFO, "%s", msg);
470 if (infomode & LOG_CONSOLE) printf("%s\n", msg);
475 * Writes self PID in file PATH
476 * FIXME: libc implementation only writes in /var/run
477 * this is more generic as some implemenation may provide
478 * arguments to write in specific file. as dhcpd does.
480 static void write_pid(char *path)
482 int pidfile = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666);
486 sprintf(pidbuf, "%u", (unsigned)getpid());
487 write(pidfile, pidbuf, strlen(pidbuf));
492 // Generic signal handler real handling is done in main funcrion.
493 static void signal_handler(int sig)
495 unsigned char ch = sig;
496 if (write(sigfd.wr, &ch, 1) != 1) {
497 dbg("can't send signal\n");
502 // signal setup for SIGUSR1 SIGTERM
503 static int setup_signal()
505 if (pipe((int *)&sigfd) < 0) {
506 dbg("signal pipe failed\n");
509 fcntl(sigfd.wr , F_SETFD, FD_CLOEXEC);
510 fcntl(sigfd.rd , F_SETFD, FD_CLOEXEC);
511 int flags = fcntl(sigfd.wr, F_GETFL);
512 fcntl(sigfd.wr, F_SETFL, flags | O_NONBLOCK);
513 signal(SIGUSR1, signal_handler);
514 signal(SIGTERM, signal_handler);
518 // String STR to UINT32 conversion strored in VAR
519 static int strtou32(const char *str, void *var)
524 *((uint32_t*)(var)) = 0;
525 if (str[0]=='0' && (str[1]=='x' || str[1]=='X')) {
530 long ret_val = strtol(str, &endptr, base);
531 if (errno) infomsg(infomode, "config : Invalid num %s",str);
532 else if (endptr && (*endptr!='\0'||endptr == str))
533 infomsg(infomode, "config : Not a valid num %s",str);
534 else *((uint32_t*)(var)) = (uint32_t)ret_val;
538 // copy string STR in variable VAR
539 static int strinvar(const char *str, void *var)
542 if (*dest) free(*dest);
547 // IP String STR to binary data.
548 static int striptovar(const char *str, void *var)
550 *((uint32_t*)(var)) = 0;
552 error_msg("config : NULL address string \n");
555 if((inet_pton(AF_INET6, str, var)<=0) && (inet_pton(AF_INET, str, var)<=0)) {
556 error_msg("config : wrong address %s \n", str);
562 // String to dhcp option conversion
563 static int strtoopt(const char *str, void *var)
565 char *option, *valstr, *grp, *tp;
566 uint32_t optcode = 0, inf = infomode, convtmp, mask, nip, router;
568 int count, size = ARRAY_LEN(options_list);
571 if (!(option = strtok((char*)str, " \t="))) return -1;
573 infomode = LOG_SILENT;
574 strtou32(option, (uint32_t*)&optcode);
577 if (optcode > 0 && optcode < 256) { // raw option
578 for (count = 0; count < size; count++) {
579 if ((options_list[count].code & 0X00FF) == optcode) {
580 flag = (options_list[count].code & 0XFF00);
584 } else { //string option
585 for (count = 0; count < size; count++) {
586 if (!strncmp(options_list[count].key, option, strlen(options_list[count].key))) {
587 flag = (options_list[count].code & 0XFF00);
588 optcode = (options_list[count].code & 0X00FF);
594 infomsg(inf, "config : Obsolete OR Unknown Option : %s", option);
598 if (!flag || !optcode) return -1;
600 if (!(valstr = strtok(NULL, " \t"))) {
601 dbg("config : option %s has no value defined.\n", option);
604 dbg(" value : %-20s : ", valstr);
607 options_list[count].len = sizeof(uint32_t);
608 options_list[count].val = xmalloc(sizeof(uint32_t));
609 strtou32(valstr, &convtmp);
610 memcpy(options_list[count].val, &convtmp, sizeof(uint32_t));
613 options_list[count].len = sizeof(uint16_t);
614 options_list[count].val = xmalloc(sizeof(uint16_t));
615 strtou32(valstr, &convtmp);
616 memcpy(options_list[count].val, &convtmp, sizeof(uint16_t));
619 options_list[count].len = sizeof(uint8_t);
620 options_list[count].val = xmalloc(sizeof(uint8_t));
621 strtou32(valstr, &convtmp);
622 memcpy(options_list[count].val, &convtmp, sizeof(uint8_t));
625 options_list[count].len = sizeof(uint32_t);
626 options_list[count].val = xmalloc(sizeof(uint32_t));
627 striptovar(valstr, options_list[count].val);
630 options_list[count].len = strlen(valstr);
631 options_list[count].val = strdup(valstr);
635 options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + sizeof(uint32_t));
636 striptovar(valstr, ((uint8_t*)options_list[count].val)+options_list[count].len);
637 options_list[count].len += sizeof(uint32_t);
638 valstr = strtok(NULL," \t");
644 /* Option binary format:
645 * mask [one byte, 0..32]
646 * ip [0..4 bytes depending on mask]
649 * staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1
651 grp = strtok(valstr, ",");;
653 while(*grp == ' ' || *grp == '\t') grp++;
654 tp = strchr(grp, '/');
655 if (!tp) error_exit("wrong formated static route option");
657 mask = strtol(++tp, &tp, 10);
658 if (striptovar(grp, (uint8_t*)&nip)<0) error_exit("wrong formated static route option");
659 while(*tp == ' ' || *tp == '\t' || *tp == '-') tp++;
660 if (striptovar(tp, (uint8_t*)&router)<0) error_exit("wrong formated static route option");
661 options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + 1 + mask/8 + 4);
662 memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &mask, 1);
663 options_list[count].len += 1;
664 memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &nip, mask/8);
665 options_list[count].len += mask/8;
666 memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &router, 4);
667 options_list[count].len += 4;
669 grp = strtok(NULL, ",");
676 // Reads Static leases from STR and updates inner structures.
677 static int get_staticlease(const char *str, void *var)
679 struct static_lease_s *sltmp;
685 if (!(tkmac = strtok((char*)str, " \t"))) {
686 infomsg(infomode, "config : static lease : mac not found");
689 if (!(tkip = strtok(NULL, " \t"))) {
690 infomsg(infomode, "config : static lease : no ip bind to mac %s", tkmac);
693 sltmp = xzalloc(sizeof(struct static_lease_s));
694 for (count = 0; count < 6; count++, tkmac++) {
696 sltmp->mac[count] = strtol(tkmac, &tkmac, 16);
697 if (sltmp->mac[count]>255 || sltmp->mac[count]<0 || (*tkmac && *tkmac!=':') || errno) {
698 infomsg(infomode, "config : static lease : mac address wrong format");
703 striptovar(tkip, &sltmp->nip);
704 sltmp->next = gstate.leases.sleases;
705 gstate.leases.sleases = sltmp;
710 static struct config_keyword keywords[] = {
711 // keyword handler variable address default
712 {"start" , striptovar , (void*)&gconfig.start_ip , "192.168.0.20"},
713 {"end" , striptovar , (void*)&gconfig.end_ip , "192.168.0.254"},
714 {"interface" , strinvar , (void*)&gconfig.interface , "eth0"},
715 {"port" , strtou32 , (void*)&gconfig.port , "67"},
716 {"min_lease" , strtou32 , (void*)&gconfig.min_lease_sec, "60"},
717 {"max_leases" , strtou32 , (void*)&gconfig.max_leases , "235"},
718 {"auto_time" , strtou32 , (void*)&gconfig.auto_time , "7200"},
719 {"decline_time" , strtou32 , (void*)&gconfig.decline_time , "3600"},
720 {"conflict_time", strtou32 , (void*)&gconfig.conflict_time, "3600"},
721 {"offer_time" , strtou32 , (void*)&gconfig.offer_time , "60"},
722 {"lease_file" , strinvar , (void*)&gconfig.lease_file , "/var/lib/misc/dhcpd.leases"}, //LEASES_FILE
723 {"lease6_file" , strinvar , (void*)&gconfig.lease6_file , "/var/lib/misc/dhcpd6.leases"}, //LEASES_FILE
724 {"pidfile" , strinvar , (void*)&gconfig.pidfile , "/var/run/dhcpd.pid"}, //DPID_FILE
725 {"siaddr" , striptovar , (void*)&gconfig.siaddr_nip , "0.0.0.0"},
726 {"option" , strtoopt , (void*)&gconfig.options , ""},
727 {"opt" , strtoopt , (void*)&gconfig.options , ""},
728 {"notify_file" , strinvar , (void*)&gconfig.notify_file , ""},
729 {"sname" , strinvar , (void*)&gconfig.sname , ""},
730 {"boot_file" , strinvar , (void*)&gconfig.boot_file , ""},
731 {"static_lease" , get_staticlease , (void*)&gconfig.static_leases, ""},
732 {"start6" , striptovar , (void*)&gconfig.start_ip6 , "2001:620:40b:555::100"},
733 {"end6" , striptovar , (void*)&gconfig.end_ip6 , "2001:620:40b:555::200"},
734 {"preferred_lifetime" , strtou32 , (void*)&gconfig.pref_lifetime, "3600"},
735 {"valid_lifetime" , strtou32 , (void*)&gconfig.valid_lifetime, "7200"},
736 {"t1" , strtou32 , (void*)&gconfig.t1 , "3600"},
737 {"t2" , strtou32 , (void*)&gconfig.t2 , "5400"},
740 // Parses the server config file and updates the global server config accordingly.
741 static int parse_server_config(char *config_file, struct config_keyword *confkey)
744 char *confline_temp = NULL,*confline = NULL, *tk = NULL, *tokens[2] = {NULL, NULL};
745 int len, linelen, tcount, count, size = ARRAY_LEN(keywords);
747 for (count = 0; count < size; count++)
748 if (confkey[count].handler)
749 confkey[count].handler(confkey[count].def, confkey[count].var);
751 if (!(fs = fopen(config_file, "r"))) perror_msg("%s", config_file);
752 for (len = 0, linelen = 0; fs;) {
753 len = getline(&confline_temp, (size_t*) &linelen, fs);
754 confline = confline_temp;
756 for (; *confline == ' '; confline++, len--);
757 if ((confline[0] == '#') || (confline[0] == '\n')) goto free_conf_continue;
758 tk = strchr(confline, '#');
760 for (; *(tk-1)==' ' || *(tk-1)=='\t'; tk--);
763 tk = strchr(confline, '\n');
765 for (; *(tk-1)==' ' || *(tk-1)=='\t'; tk--);
768 for (tcount=0, tk=strtok(confline, " \t"); tk && (tcount < 2);
769 tcount++, tk=strtok(NULL,(tcount==1)?"":" \t")) {
770 while ((*tk == '\t') || (*tk == ' ')) tk++;
771 tokens[tcount] = xstrdup(tk);
773 if (tcount<=1) goto free_tk0_continue;
774 for (count = 0; count < size; count++) {
775 if (!strcmp(confkey[count].keyword,tokens[0])) {
776 dbg("got config : %15s : ", confkey[count].keyword);
777 if (confkey[count].handler(tokens[1], confkey[count].var) == 0)
778 dbg("%s \n", tokens[1]);
782 if (tokens[1]) { free(tokens[1]); tokens[1] = NULL; }
784 if (tokens[0]) { free(tokens[0]); tokens[0] = NULL; }
787 confline_temp = NULL;
793 // opens UDP socket for listen ipv6 packets
794 static int open_listensock6(void)
796 struct sockaddr_in6 addr6;
797 struct ipv6_mreq mreq;
799 if (gstate.listensock > 0) close(gstate.listensock);
801 dbg("Opening listen socket on *:%d %s\n", gconfig.port, gconfig.interface);
803 gstate.listensock = xsocket(PF_INET6, SOCK_DGRAM, 0);
804 setsockopt(gstate.listensock, SOL_SOCKET, SO_REUSEADDR, &constone, sizeof(constone));
806 if (setsockopt(gstate.listensock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &constone,
807 sizeof(constone)) == -1) {
808 error_msg("failed to receive ipv6 packets.\n");
809 close(gstate.listensock);
813 setsockopt(gstate.listensock, SOL_SOCKET, SO_BINDTODEVICE, gconfig.interface, strlen(gconfig.interface)+1);
815 memset(&addr6, 0, sizeof(addr6));
816 addr6.sin6_family = AF_INET6;
817 addr6.sin6_port = (flag_chk(FLAG_P))?htons(TT.port):htons(gconfig.port); //SERVER_PORT
818 addr6.sin6_scope_id = if_nametoindex(gconfig.interface);
819 //Listening for multicast packet
820 inet_pton(AF_INET6, "ff02::1:2", &addr6.sin6_addr);
822 if (bind(gstate.listensock, (struct sockaddr *) &addr6, sizeof(addr6)) == -1) {
823 close(gstate.listensock);
824 perror_exit("bind failed");
827 memset(&mreq, 0, sizeof(mreq));
828 mreq.ipv6mr_interface = if_nametoindex(gconfig.interface);
829 memcpy(&mreq.ipv6mr_multiaddr, &addr6.sin6_addr, sizeof(addr6.sin6_addr));
831 if(setsockopt(gstate.listensock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) {
832 error_msg("failed to join a multicast group.\n");
833 close(gstate.listensock);
837 dbg("OPEN : success\n");
841 // opens UDP socket for listen
842 static int open_listensock(void)
844 struct sockaddr_in addr;
847 if (gstate.listensock > 0) close(gstate.listensock);
849 dbg("Opening listen socket on *:%d %s\n", gconfig.port, gconfig.interface);
850 gstate.listensock = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
851 setsockopt(gstate.listensock, SOL_SOCKET, SO_REUSEADDR, &constone, sizeof(constone));
852 if (setsockopt(gstate.listensock, SOL_SOCKET, SO_BROADCAST, &constone, sizeof(constone)) == -1) {
853 error_msg("failed to receive brodcast packets.\n");
854 close(gstate.listensock);
857 memset(&ifr, 0, sizeof(ifr));
858 xstrncpy(ifr.ifr_name, gconfig.interface, IFNAMSIZ);
859 setsockopt(gstate.listensock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
861 memset(&addr, 0, sizeof(addr));
862 addr.sin_family = AF_INET;
863 addr.sin_port = (flag_chk(FLAG_P))?htons(TT.port):htons(gconfig.port); //SERVER_PORT
864 addr.sin_addr.s_addr = INADDR_ANY ;
866 if (bind(gstate.listensock, (struct sockaddr *) &addr, sizeof(addr))) {
867 close(gstate.listensock);
868 perror_exit("bind failed");
870 dbg("OPEN : success\n");
874 static int send_packet6(uint8_t relay, uint8_t *client_lla, uint16_t optlen)
876 struct sockaddr_ll dest_sll;
880 uint32_t front, back;
882 memset(&packet, 0, sizeof(dhcp6_raw_t));
883 memcpy(&packet.dhcp6, &gstate.send.send_pkt6, sizeof(dhcp6_msg_t));
884 padding = sizeof(packet.dhcp6.options) - optlen;
886 if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6))) < 0) {
887 dbg("SEND : ipv6 socket failed\n");
890 memset(&dest_sll, 0, sizeof(dest_sll));
891 dest_sll.sll_family = AF_PACKET;
892 dest_sll.sll_protocol = htons(ETH_P_IPV6);
893 dest_sll.sll_ifindex = gconfig.ifindex;
894 dest_sll.sll_halen = ETH_ALEN;
895 memcpy(dest_sll.sll_addr, client_lla, sizeof(client_lla));
897 if (bind(fd, (struct sockaddr *) &dest_sll, sizeof(dest_sll)) < 0) {
898 dbg("SEND : bind failed\n");
902 memcpy(&packet.iph.ip6_src, &gconfig.server_nip6, sizeof(uint32_t)*4);
903 //HW addr to Link-Local addr
904 inet_pton(AF_INET6, "fe80::0200:00ff:fe00:0000", &packet.iph.ip6_dst);
905 ntohl6(packet.iph.ip6_dst.__in6_u.__u6_addr32,packet.iph.ip6_dst.__in6_u.__u6_addr32);
906 front = ntohl(*(uint32_t*)(client_lla+3) & 0x00ffffff) >> 8;
907 back = ntohl(*(uint32_t*)(client_lla) & 0x00ffffff);
908 packet.iph.ip6_dst.__in6_u.__u6_addr32[3] =
909 packet.iph.ip6_dst.__in6_u.__u6_addr32[3] | front;
910 packet.iph.ip6_dst.__in6_u.__u6_addr32[2] =
911 packet.iph.ip6_dst.__in6_u.__u6_addr32[2] | back;
912 htonl6(packet.iph.ip6_dst.__in6_u.__u6_addr32,packet.iph.ip6_dst.__in6_u.__u6_addr32);
914 packet.udph.source = htons(gconfig.port);
915 packet.udph.dest = htons(546);
916 packet.udph.len = htons(sizeof(dhcp6_raw_t) - sizeof(struct ip6_hdr) - padding);
917 packet.iph.ip6_ctlun.ip6_un1.ip6_un1_plen = htons(ntohs(packet.udph.len) + 0x11);
918 packet.udph.check = dhcp_checksum(&packet, sizeof(dhcp6_raw_t) - padding);
919 packet.iph.ip6_ctlun.ip6_un1.ip6_un1_flow = htonl(0x60000000);
920 packet.iph.ip6_ctlun.ip6_un1.ip6_un1_plen = packet.udph.len;
921 packet.iph.ip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_UDP;
922 packet.iph.ip6_ctlun.ip6_un1.ip6_un1_hlim = 0x64;
924 result = sendto(fd, &packet, sizeof(dhcp6_raw_t)-padding,
925 0, (struct sockaddr *) &dest_sll, sizeof(dest_sll));
927 dbg("sendto %d\n", result);
929 if (result < 0) dbg("PACKET send error\n");
933 // Sends data through raw socket.
934 static int send_packet(uint8_t broadcast)
936 struct sockaddr_ll dest_sll;
940 uint8_t bmacaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
942 memset(&packet, 0, sizeof(dhcp_raw_t));
943 memcpy(&packet.dhcp, &gstate.send.send_pkt, sizeof(dhcp_msg_t));
945 if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
946 dbg("SEND : socket failed\n");
949 memset(&dest_sll, 0, sizeof(dest_sll));
950 dest_sll.sll_family = AF_PACKET;
951 dest_sll.sll_protocol = htons(ETH_P_IP);
952 dest_sll.sll_ifindex = gconfig.ifindex;
953 dest_sll.sll_halen = 6;
954 memcpy(dest_sll.sll_addr, (broadcast)?bmacaddr:gstate.rcvd.rcvd_pkt.chaddr , 6);
956 if (bind(fd, (struct sockaddr *) &dest_sll, sizeof(dest_sll)) < 0) {
957 dbg("SEND : bind failed\n");
961 padding = 308 - 1 - dhcp_opt_size(gstate.send.send_pkt.options);
962 packet.iph.protocol = IPPROTO_UDP;
963 packet.iph.saddr = gconfig.server_nip;
964 packet.iph.daddr = (broadcast || (gstate.rcvd.rcvd_pkt.ciaddr == 0))?INADDR_BROADCAST:gstate.rcvd.rcvd_pkt.ciaddr;
965 packet.udph.source = htons(67);//SERVER_PORT
966 packet.udph.dest = htons(68); //CLIENT_PORT
967 packet.udph.len = htons(sizeof(dhcp_raw_t) - sizeof(struct iphdr) - padding);
968 packet.iph.tot_len = packet.udph.len;
969 packet.udph.check = dhcp_checksum(&packet, sizeof(dhcp_raw_t) - padding);
970 packet.iph.tot_len = htons(sizeof(dhcp_raw_t) - padding);
971 packet.iph.ihl = sizeof(packet.iph) >> 2;
972 packet.iph.version = IPVERSION;
973 packet.iph.ttl = IPDEFTTL;
974 packet.iph.check = dhcp_checksum(&packet.iph, sizeof(packet.iph));
976 result = sendto(fd, &packet, sizeof(dhcp_raw_t) - padding, 0,
977 (struct sockaddr *) &dest_sll, sizeof(dest_sll));
979 dbg("sendto %d\n", result);
981 if (result < 0) dbg("PACKET send error\n");
985 static int read_packet6(void)
989 memset(&gstate.rcvd.rcvd_pkt6, 0, sizeof(dhcp6_msg_t));
990 ret = read(gstate.listensock, &gstate.rcvd.rcvd_pkt6, sizeof(dhcp6_msg_t));
992 dbg("Packet read error, ignoring. \n");
993 return ret; // returns -1
995 if (gstate.rcvd.rcvd_pkt6.msgtype < 1) {
996 dbg("Bad message type, igroning. \n");
1000 dbg("Received an ipv6 packet. Size : %d \n", ret);
1004 // Reads from UDP socket
1005 static int read_packet(void)
1009 memset(&gstate.rcvd.rcvd_pkt, 0, sizeof(dhcp_msg_t));
1010 ret = read(gstate.listensock, &gstate.rcvd.rcvd_pkt, sizeof(dhcp_msg_t));
1012 dbg("Packet read error, ignoring. \n");
1013 return ret; // returns -1
1015 if (gstate.rcvd.rcvd_pkt.cookie != htonl(DHCP_MAGIC)) {
1016 dbg("Packet with bad magic, ignoring. \n");
1019 if (gstate.rcvd.rcvd_pkt.op != 1) { //BOOTPREQUEST
1020 dbg("Not a BOOT REQUEST ignoring. \n");
1023 if (gstate.rcvd.rcvd_pkt.hlen != 6) {
1024 dbg("hlen != 6 ignoring. \n");
1027 dbg("Received a packet. Size : %d \n", ret);
1031 // Preapres a dhcp packet with defaults and configs
1032 static uint8_t* prepare_send_pkt(void)
1034 memset((void*)&gstate.send.send_pkt, 0, sizeof(gstate.send.send_pkt));
1035 gstate.send.send_pkt.op = 2; //BOOTPREPLY
1036 gstate.send.send_pkt.htype = 1;
1037 gstate.send.send_pkt.hlen = 6;
1038 gstate.send.send_pkt.xid = gstate.rcvd.rcvd_pkt.xid;
1039 gstate.send.send_pkt.cookie = htonl(DHCP_MAGIC);
1040 gstate.send.send_pkt.nsiaddr = gconfig.server_nip;
1041 memcpy(gstate.send.send_pkt.chaddr, gstate.rcvd.rcvd_pkt.chaddr, 16);
1042 gstate.send.send_pkt.options[0] = DHCP_OPT_END;
1043 return gstate.send.send_pkt.options;
1046 static uint8_t* prepare_send_pkt6(uint16_t opt)
1048 memset((void*)&gstate.send.send_pkt6, 0, sizeof(gstate.send.send_pkt6));
1049 gstate.send.send_pkt6.msgtype = opt;
1050 memcpy(gstate.send.send_pkt6.transaction_id, gstate.rcvd.rcvd_pkt6.transaction_id, 3);
1051 return gstate.send.send_pkt6.options;
1054 // Sets a option value in dhcp packet's option field
1055 static uint8_t* set_optval(uint8_t *optptr, uint16_t opt, void *var, size_t len)
1057 while (*optptr != DHCP_OPT_END) optptr++;
1058 *optptr++ = (uint8_t)(opt & 0x00FF);
1059 *optptr++ = (uint8_t) len;
1060 memcpy(optptr, var, len);
1062 *optptr = DHCP_OPT_END;
1066 static uint8_t* set_optval6(uint8_t *optptr, uint16_t opt, void *var, size_t len)
1068 *((uint16_t*)optptr) = htons(opt);
1069 *(uint16_t*)(optptr+2) = htons(len);
1070 memcpy(optptr+4, var, len);
1075 // Gets a option value from dhcp packet's option field
1076 static uint8_t* get_optval(uint8_t *optptr, uint16_t opt, void *var)
1079 uint8_t overloaded = 0;
1082 while (*optptr == DHCP_OPT_PADDING) optptr++;
1083 if ((*optptr & 0x00FF) == DHCP_OPT_END) break;
1084 if ((*optptr & 0x00FF) == DHCP_OPT_OPTION_OVERLOAD) {
1085 overloaded = optptr[2];
1086 optptr += optptr[1] + 2;
1089 if (*optptr == (opt & 0x00FF))
1090 switch (opt & 0xFF00) {
1091 case DHCP_NUM32: // FALLTHROUGH
1093 memcpy(var, optptr+2, sizeof(uint32_t));
1098 memcpy(var, optptr+2, sizeof(uint16_t));
1103 memcpy(var, optptr+2, sizeof(uint8_t));
1108 var = xstrndup((char*) optptr, len);
1115 if ((overloaded == 1) | (overloaded == 3)) get_optval((uint8_t*)&gstate.rcvd.rcvd_pkt.file, opt, var);
1116 if ((overloaded == 2) | (overloaded == 3)) get_optval((uint8_t*)&gstate.rcvd.rcvd_pkt.sname, opt, var);
1120 static uint8_t* get_optval6(uint8_t *optptr, uint16_t opt, uint16_t *datalen, void **var)
1125 memcpy(&optcode, optptr, sizeof(uint16_t));
1126 memcpy(&len, optptr+2, sizeof(uint16_t));
1128 dbg("Option %d is not exist.\n", opt);
1131 optcode = ntohs(optcode);
1134 if (opt == optcode) {
1135 *var = xmalloc(len);
1136 memcpy(*var, optptr+4, len);
1137 optptr = optptr + len + 4;
1138 memcpy(datalen, &len, sizeof(uint16_t));
1141 optptr = get_optval6(optptr+len+4, opt, datalen, var);
1147 // Retrives Requested Parameter list from dhcp req packet.
1148 static uint8_t get_reqparam(uint8_t **list)
1150 uint8_t len, *optptr;
1151 if(*list) free(*list);
1152 for (optptr = gstate.rcvd.rcvd_pkt.options;
1153 *optptr && *optptr!=((DHCP_OPT_PARAM_REQ) & 0x00FF); optptr+=optptr[1]+2);
1155 *list = xzalloc(len+1);
1156 memcpy(*list, ++optptr, len);
1160 // Sets values of req param in dhcp offer packet.
1161 static uint8_t* set_reqparam(uint8_t *optptr, uint8_t *list)
1164 int count, size = ARRAY_LEN(options_list);
1168 for (count = 0; count < size; count++) {
1169 if ((options_list[count].code & 0X00FF)==reqcode) {
1170 if (!(options_list[count].len) || !(options_list[count].val)) break;
1171 for (; *optptr && *optptr!=DHCP_OPT_END; optptr+=optptr[1]+2);
1172 *optptr++ = (uint8_t) (options_list[count].code & 0x00FF);
1173 *optptr++ = (uint8_t) options_list[count].len;
1174 memcpy(optptr, options_list[count].val, options_list[count].len);
1175 optptr += options_list[count].len;
1176 *optptr = DHCP_OPT_END;
1184 static void run_notify(char **argv)
1187 volatile int error = 0;
1190 if (stat(argv[0], &sts) == -1 && errno == ENOENT) {
1191 infomsg(infomode, "notify file: %s : not exist.", argv[0]);
1198 dbg("Fork failed.\n");
1202 execvp(argv[0], argv);
1207 waitpid(pid, NULL, 0);
1210 dbg("script complete.\n");
1213 static void write_leasefile(void)
1216 uint32_t curr, tmp_time;
1218 struct arg_list *listdls = gstate.dleases;
1221 if ((fd = open(gconfig.lease_file, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
1222 perror_msg("can't open %s ", gconfig.lease_file);
1224 curr = timestamp = time(NULL);
1225 timestamp = SWAP_BE64(timestamp);
1226 writeall(fd, ×tamp, sizeof(timestamp));
1229 dls = (dyn_lease*)listdls->arg;
1230 tmp_time = dls->expires;
1231 dls->expires -= curr;
1232 if ((int32_t) dls->expires < 0) goto skip;
1233 dls->expires = htonl(dls->expires);
1234 writeall(fd, dls, sizeof(dyn_lease));
1236 dls->expires = tmp_time;
1237 listdls = listdls->next;
1240 if (gconfig.notify_file) {
1242 argv[0] = gconfig.notify_file;
1243 argv[1] = gconfig.lease_file;
1250 static void write_lease6file(void)
1253 uint32_t curr, tmp_time;
1255 struct arg_list *listdls = gstate.dleases;
1258 if ((fd = open(gconfig.lease6_file, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
1259 perror_msg("can't open %s ", gconfig.lease6_file);
1261 curr = timestamp = time(NULL);
1262 timestamp = SWAP_BE64(timestamp);
1263 writeall(fd, ×tamp, sizeof(timestamp));
1266 dls6 = (dyn_lease6*)listdls->arg;
1267 tmp_time = dls6->expires;
1268 dls6->expires -= curr;
1269 if ((int32_t) dls6->expires < 0) goto skip;
1270 dls6->expires = htonl(dls6->expires);
1271 writeall(fd, dls6, sizeof(dyn_lease6));
1273 dls6->expires = tmp_time;
1274 listdls = listdls->next;
1277 if (gconfig.notify_file) {
1279 argv[0] = gconfig.notify_file;
1280 argv[1] = gconfig.lease6_file;
1287 // Update max lease time from options.
1288 static void set_maxlease(void)
1290 int count, size = ARRAY_LEN(options_list);
1291 for (count = 0; count < size; count++)
1292 if (options_list[count].val && options_list[count].code == (DHCP_OPT_LEASE_TIME)) {
1293 gconfig.max_lease_sec = *((uint32_t*)options_list[count].val);
1296 if (!gconfig.max_lease_sec) gconfig.max_lease_sec = (60*60*24*10);// DEFAULT_LEASE_TIME;
1299 // Returns lease time for client.
1300 static uint32_t get_lease(uint32_t req_exp)
1302 uint32_t now = time(NULL);
1303 req_exp = req_exp - now;
1304 if(addr_version == AF_INET6) {
1305 if ((req_exp <= 0) || req_exp > gconfig.pref_lifetime ||
1306 req_exp > gconfig.valid_lifetime) {
1307 if ((gconfig.pref_lifetime > gconfig.valid_lifetime)) {
1308 error_msg("The valid lifetime must be greater than the preferred lifetime, \
1309 setting to valid lifetime", gconfig.valid_lifetime);
1310 return gconfig.valid_lifetime;
1312 return gconfig.pref_lifetime;
1315 if ((req_exp <= 0) || (req_exp > gconfig.max_lease_sec))
1316 return gconfig.max_lease_sec;
1318 if (req_exp < gconfig.min_lease_sec)
1319 return gconfig.min_lease_sec;
1325 static int verifyip6_in_lease(uint32_t *nip6, uint8_t *duid, uint16_t ia_type, uint32_t iaid)
1327 static_lease6 *sls6;
1328 struct arg_list *listdls;
1329 uint32_t tmpnip6[4] = {0,};
1331 for (listdls = gstate.dleases; listdls; listdls = listdls->next) {
1332 if (!memcmp(((dyn_lease6*) listdls->arg)->lease_nip6, nip6, sizeof(uint32_t)*4))
1335 if (!memcmp(((dyn_lease6*) listdls->arg)->duid, duid, ((dyn_lease6*) listdls->arg)->duid_len)
1336 && ((dyn_lease6*) listdls->arg)->ia_type == ia_type)
1339 for (sls6 = gstate.leases.sleases6; sls6; sls6 = sls6->next)
1340 if (memcmp(sls6->nip6, nip6, sizeof(uint32_t)*4)==0) return -2;
1342 ntohl6(nip6, tmpnip6);
1343 if (memcmp(tmpnip6, gconfig.start_ip6, sizeof(tmpnip6)) < 0 ||
1344 memcmp(tmpnip6, gconfig.end_ip6, sizeof(tmpnip6)) > 0)
1350 // Verify ip NIP in current leases ( assigned or not)
1351 static int verifyip_in_lease(uint32_t nip, uint8_t mac[6])
1354 struct arg_list *listdls;
1356 for (listdls = gstate.dleases; listdls; listdls = listdls->next) {
1357 if (((dyn_lease*) listdls->arg)->lease_nip == nip) {
1358 if (((int32_t)(((dyn_lease*) listdls->arg)->expires) - time(NULL)) < 0)
1362 if (!memcmp(((dyn_lease*) listdls->arg)->lease_mac, mac, 6)) return -1;
1364 for (sls = gstate.leases.sleases; sls; sls = sls->next)
1365 if (sls->nip == nip) return -2;
1367 if ((ntohl(nip) < gconfig.start_ip) || (ntohl(nip) > gconfig.end_ip))
1373 // add ip assigned_nip to dynamic lease.
1374 static int addip_to_lease(uint32_t assigned_nip, uint8_t mac[6], uint32_t *req_exp, char *hostname, uint8_t update)
1377 struct arg_list *listdls = gstate.dleases;
1378 uint32_t now = time(NULL);
1381 if (!memcmp(((dyn_lease*) listdls->arg)->lease_mac, mac, 6)) {
1382 if (update) *req_exp = get_lease(*req_exp + ((dyn_lease*) listdls->arg)->expires);
1383 ((dyn_lease*) listdls->arg)->expires = *req_exp + now;
1386 listdls = listdls->next;
1389 dls = xzalloc(sizeof(dyn_lease));
1390 memcpy(dls->lease_mac, mac, 6);
1391 dls->lease_nip = assigned_nip;
1392 if (hostname) memcpy(dls->hostname, hostname, 20);
1394 if (update) *req_exp = get_lease(*req_exp + now);
1395 dls->expires = *req_exp + now;
1397 listdls = xzalloc(sizeof(struct arg_list));
1398 listdls->next = gstate.dleases;
1399 listdls->arg = (char*)dls;
1400 gstate.dleases = listdls;
1405 static int addip6_to_lease(uint32_t *assigned_nip, uint8_t *duid, uint16_t ia_type, uint32_t iaid, uint32_t *lifetime, uint8_t update)
1408 struct arg_list *listdls = gstate.dleases;
1409 uint32_t now = time(NULL);
1412 if (!memcmp(((dyn_lease6*) listdls->arg)->duid, duid, ((dyn_lease6*) listdls->arg)->duid_len)) {
1413 if (update) *lifetime = get_lease(*lifetime + ((dyn_lease6*) listdls->arg)->expires);
1414 ((dyn_lease6*) listdls->arg)->expires = *lifetime + now;
1417 listdls = listdls->next;
1420 dls6 = xzalloc(sizeof(dyn_lease6));
1421 dls6->duid_len = sizeof(duid);
1422 memcpy(dls6->duid, duid, dls6->duid_len);
1423 dls6->ia_type = ia_type;
1425 memcpy(dls6->lease_nip6, assigned_nip, sizeof(uint32_t)*4);
1427 if (update) *lifetime = get_lease(*lifetime + now);
1428 dls6->expires = *lifetime + now;
1430 listdls = xzalloc(sizeof(struct arg_list));
1431 listdls->next = gstate.dleases;
1432 listdls->arg = (char*)dls6;
1433 gstate.dleases = listdls;
1438 // delete ip assigned_nip from dynamic lease.
1439 static int delip_from_lease(uint32_t assigned_nip, uint8_t mac[6], uint32_t del_time)
1441 struct arg_list *listdls = gstate.dleases;
1444 if (!memcmp(((dyn_lease*) listdls->arg)->lease_mac, mac, 6)) {
1445 ((dyn_lease*) listdls->arg)->expires = del_time + time(NULL);
1448 listdls = listdls->next;
1453 // returns a IP from static, dynamic leases or free ip pool, 0 otherwise.
1454 static uint32_t getip_from_pool(uint32_t req_nip, uint8_t mac[6], uint32_t *req_exp, char *hostname)
1457 static_lease *sls = gstate.leases.sleases;
1458 struct arg_list *listdls = gstate.dleases, *tmp = NULL;
1460 if (req_nip && (!verifyip_in_lease(req_nip, mac))) nip = req_nip;
1464 if (!memcmp(((dyn_lease*)listdls->arg)->lease_mac, mac, 6)) {
1465 nip = ((dyn_lease*)listdls->arg)->lease_nip;
1466 if (tmp) tmp->next = listdls->next;
1467 else gstate.dleases = listdls->next;
1470 if (verifyip_in_lease(nip, mac) < 0) nip = 0;
1474 listdls = listdls->next;
1479 if (memcmp(sls->mac, mac, 6) == 0) {
1487 for (nip = htonl(gconfig.start_ip); ntohl(nip) <= gconfig.end_ip; ) {
1488 if (!verifyip_in_lease(nip, mac)) break;
1492 if (ntohl(nip) > gconfig.end_ip) {
1494 infomsg(infomode, "can't find free IP in IP Pool.");
1497 if (nip) addip_to_lease(nip, mac, req_exp, hostname, 1);
1501 static uint32_t *getip6_from_pool(uint8_t *duid, uint16_t duid_len, uint16_t ia_type, uint32_t iaid, uint32_t *lifetime)
1503 uint32_t nip6[4] = {0,};
1504 static_lease6 *sls6 = gstate.leases.sleases6;
1505 struct arg_list *listdls6 = gstate.dleases, *tmp = NULL;
1508 if (!memcmp(((dyn_lease6*)listdls6->arg)->duid, duid, duid_len)) {
1509 memcpy(nip6, ((dyn_lease6*)listdls6->arg)->lease_nip6, sizeof(nip6));
1510 if(tmp) tmp->next = listdls6->next;
1511 else gstate.dleases = listdls6->next;
1512 free(listdls6->arg);
1515 if(verifyip6_in_lease(nip6, duid, ia_type, iaid) < 0)
1516 memset(nip6, 0, sizeof(nip6));
1520 listdls6 = listdls6->next;
1523 if(!nip6[0] && !nip6[1] && !nip6[2] && !nip6[3]) {
1525 if(!memcmp(sls6->duid, duid, 6)) {
1526 memcpy(nip6, sls6->nip6, sizeof(nip6));
1533 if(!nip6[0] && !nip6[1] && !nip6[2] && !nip6[3]) {
1534 uint32_t tmpip6[4] = {0,};
1536 memcpy(tmpip6, gconfig.start_ip6, sizeof(tmpip6));
1537 htonl6(gconfig.start_ip6, nip6);
1538 while(memcmp(tmpip6, gconfig.end_ip6, sizeof(tmpip6))<=0) {
1539 if(!verifyip6_in_lease(nip6, duid, ia_type, iaid)) break;
1540 ntohl6(nip6, tmpip6);
1542 if (tmpip6[i] == 0xffff) {
1549 htonl6(tmpip6, nip6);
1552 ntohl6(nip6, tmpip6);
1553 if (memcmp(tmpip6, gconfig.end_ip6, sizeof(tmpip6))>0) {
1554 memset(nip6, 0, sizeof(nip6));
1555 infomsg(infomode, "can't find free IP in IPv6 Pool.");
1559 if(nip6[0] && nip6[1] && nip6[2] && nip6[3])
1560 addip6_to_lease(nip6, duid, ia_type, iaid, lifetime, 1);
1564 static void read_leasefile(void)
1566 uint32_t passed, ip;
1570 int fd = open(gconfig.lease_file, O_RDONLY);
1572 dls = xzalloc(sizeof(dyn_lease));
1574 if (read(fd, ×tamp, sizeof(timestamp)) != sizeof(timestamp))
1575 goto lease_error_exit;
1577 timestamp = SWAP_BE64(timestamp);
1578 passed = time(NULL) - timestamp;
1579 if ((uint64_t)passed > 12 * 60 * 60) goto lease_error_exit;
1581 while (read(fd, dls, sizeof(dyn_lease)) == sizeof(dyn_lease)) {
1582 ip = ntohl(dls->lease_nip);
1583 if (ip >= gconfig.start_ip && ip <= gconfig.end_ip) {
1584 tmp_time = ntohl(dls->expires) - passed;
1585 if (tmp_time < 0) continue;
1586 addip_to_lease(dls->lease_nip, dls->lease_mac,
1587 (uint32_t*)&tmp_time, dls->hostname, 0);
1595 static void read_lease6file(void)
1597 uint32_t passed, ip6[4];
1601 int fd = open(gconfig.lease6_file, O_RDONLY);
1603 dls6 = xzalloc(sizeof(dyn_lease6));
1605 if (read(fd, ×tamp, sizeof(timestamp)) != sizeof(timestamp))
1606 goto lease6_error_exit;
1608 timestamp = SWAP_BE64(timestamp);
1609 passed = time(NULL) - timestamp;
1610 if ((uint64_t)passed > 12 * 60 * 60) goto lease6_error_exit;
1612 while (read(fd, dls6, sizeof(dyn_lease6)) == sizeof(dyn_lease6)) {
1613 ntohl6(dls6->lease_nip6, ip6);
1614 if (memcmp(ip6, gconfig.start_ip6, sizeof(ip6))<0 &&
1615 memcmp(ip6, gconfig.end_ip6, sizeof(ip6))>9) {
1616 tmp_time = ntohl(dls6->expires) - passed;
1617 if (tmp_time < 0U) continue;
1618 addip6_to_lease(dls6->lease_nip6, dls6->duid, dls6->ia_type, dls6->iaid,
1619 (uint32_t*)&tmp_time, 0);
1628 void dhcpd_main(void)
1632 uint8_t *optptr, msgtype = 0;
1633 uint16_t optlen = 0;
1634 uint32_t waited = 0, serverid = 0, requested_nip = 0;
1635 uint32_t requested_nip6[4] = {0,};
1636 uint8_t transactionid[3] = {0,};
1637 uint32_t reqested_lease = 0, ip_pool_size = 0;
1638 char *hstname = NULL;
1641 infomode = LOG_CONSOLE;
1642 if (!(flag_chk(FLAG_f))) {
1644 infomode = LOG_SILENT;
1646 if (flag_chk(FLAG_S)) {
1647 openlog("UDHCPD :", LOG_PID, LOG_DAEMON);
1648 infomode |= LOG_SYSTEM;
1652 parse_server_config((toys.optc==1)?toys.optargs[0]:"/etc/dhcpd.conf", keywords);
1653 infomsg(infomode, "toybox dhcpd started");
1655 if (flag_chk(FLAG_6)){
1656 addr_version = AF_INET6;
1657 ntohl6(gconfig.start_ip6, gconfig.start_ip6);
1658 ntohl6(gconfig.end_ip6, gconfig.end_ip6);
1659 gconfig.t1 = ntohl(gconfig.t1);
1660 gconfig.t2 = ntohl(gconfig.t2);
1661 gconfig.pref_lifetime = ntohl(gconfig.pref_lifetime);
1662 gconfig.valid_lifetime = ntohl(gconfig.valid_lifetime);
1664 ip_pool_size += (gconfig.end_ip6[i]-gconfig.start_ip6[i])<<((3-i)*8);
1666 gconfig.start_ip = ntohl(gconfig.start_ip);
1667 gconfig.end_ip = ntohl(gconfig.end_ip);
1668 ip_pool_size = gconfig.end_ip - gconfig.start_ip + 1;
1671 if (gconfig.max_leases > ip_pool_size) {
1672 error_msg("max_leases=%u is too big, setting to %u",
1673 (unsigned) gconfig.max_leases, ip_pool_size);
1674 gconfig.max_leases = ip_pool_size;
1676 write_pid(gconfig.pidfile);
1679 if(TT.iface) gconfig.interface = TT.iface;
1680 (addr_version==AF_INET6) ? read_lease6file() : read_leasefile();
1682 if (get_interface(gconfig.interface, &gconfig.ifindex,
1683 (addr_version==AF_INET6)? gconfig.server_nip6 : &gconfig.server_nip,
1684 gconfig.server_mac)<0)
1685 perror_exit("Failed to get interface %s", gconfig.interface);
1687 if (addr_version==AF_INET6) {
1688 htonl6(gconfig.server_nip6, gconfig.server_nip6);
1691 gconfig.server_nip = htonl(gconfig.server_nip);
1695 fcntl(gstate.listensock, F_SETFD, FD_CLOEXEC);
1698 uint32_t timestmp = time(NULL);
1700 FD_SET(gstate.listensock, &rfds);
1701 FD_SET(sigfd.rd, &rfds);
1702 tv.tv_sec = gconfig.auto_time - waited;
1708 int maxfd = (sigfd.rd > gstate.listensock)? sigfd.rd : gstate.listensock;
1709 dbg("select waiting ....\n");
1710 retval = select(maxfd + 1, &rfds, NULL, NULL, (gconfig.auto_time?&tv:NULL));
1712 if (errno == EINTR) {
1713 waited += (unsigned) time(NULL) - timestmp;
1716 dbg("Don't wait on Error in select\n");
1719 if (!retval) { // Timed out
1720 dbg("select wait Timed Out...\n");
1722 (addr_version==AF_INET6)? write_lease6file() : write_leasefile();
1723 if (get_interface(gconfig.interface, &gconfig.ifindex,
1724 (addr_version==AF_INET6)? gconfig.server_nip6 : &gconfig.server_nip,
1725 gconfig.server_mac)<0)
1726 perror_exit("Failed to get interface %s", gconfig.interface);
1727 if(addr_version == AF_INET6) {
1728 htonl6(gconfig.server_nip6, gconfig.server_nip6);
1729 } else gconfig.server_nip = htonl(gconfig.server_nip);
1732 if (FD_ISSET(sigfd.rd, &rfds)) { // Some Activity on RDFDs : is signal
1734 if (read(sigfd.rd, &sig, 1) != 1) {
1735 dbg("signal read failed.\n");
1740 infomsg(infomode, "Received SIGUSR1");
1741 (addr_version==AF_INET6)? write_lease6file() : write_leasefile();
1744 infomsg(infomode, "received sigterm");
1745 (addr_version==AF_INET6)? write_lease6file() : write_leasefile();
1746 unlink(gconfig.pidfile);
1752 if (FD_ISSET(gstate.listensock, &rfds)) { // Some Activity on RDFDs : is socke
1753 dbg("select listen sock read\n");
1754 if(addr_version==AF_INET6) {
1755 void *client_duid, *server_duid, *client_ia_na, *server_ia_na,
1756 *client_ia_pd, *server_ia_pd;
1757 uint8_t client_lla[6] = {0,};
1758 uint16_t client_duid_len = 0, server_duid_len = 0, server_ia_na_len = 0,
1759 client_ia_na_len = 0, client_ia_pd_len = 0;
1761 if(read_packet6() < 0) {
1765 waited += time(NULL) - timestmp;
1767 memcpy(&gstate.rqcode, &gstate.rcvd.rcvd_pkt6.msgtype, sizeof(uint8_t));
1768 memcpy(&transactionid, &gstate.rcvd.rcvd_pkt6.transaction_id,
1769 sizeof(transactionid));
1771 if (!gstate.rqcode || gstate.rqcode < DHCP6SOLICIT ||
1772 gstate.rqcode > DHCP6RELAYREPLY) {
1773 dbg("no or bad message type option, ignoring packet.\n");
1776 if (!gstate.rcvd.rcvd_pkt6.transaction_id ||
1777 memcmp(gstate.rcvd.rcvd_pkt6.transaction_id, transactionid, 3)) {
1778 dbg("no or bad transaction id, ignoring packet.\n");
1782 waited += time(NULL) - timestmp;
1783 switch (gstate.rqcode) {
1785 dbg("Message Type: DHCP6SOLICIT\n");
1786 optptr = prepare_send_pkt6(DHCP6ADVERTISE);
1790 //TODO Receive: ORO check (e.g. DNS)
1792 //Receive: Identity Association for Non-temporary Address
1793 if(get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
1794 DHCP6_OPT_IA_NA, &client_ia_na_len, &client_ia_na)) {
1795 uint16_t ia_addr_len = sizeof(struct optval_ia_addr);
1796 void *ia_addr, *status_code;
1797 char *status_code_msg;
1798 uint16_t status_code_len = 0;
1799 server_ia_na_len = sizeof(struct optval_ia_na)-sizeof(uint8_t*);
1802 ia_addr = xzalloc(ia_addr_len);
1803 struct optval_ia_addr *ia_addr_p = (struct optval_ia_addr*)ia_addr;
1804 (*ia_addr_p).pref_lifetime = gconfig.pref_lifetime;
1805 (*ia_addr_p).valid_lifetime = gconfig.valid_lifetime;
1806 memcpy(&(*ia_addr_p).ipv6_addr,
1807 getip6_from_pool(client_duid, client_duid_len,
1808 DHCP6_OPT_IA_NA, (*(struct optval_ia_na*) client_ia_na).iaid,
1809 &(*ia_addr_p).pref_lifetime), sizeof(uint32_t)*4);
1810 server_ia_na_len += (ia_addr_len+4);
1813 if(*(*ia_addr_p).ipv6_addr) {
1814 status_code_msg = xstrdup("Assigned an address.");
1815 status_code_len = strlen(status_code_msg)+1;
1816 status_code = xzalloc(status_code_len);
1817 struct optval_status_code *status_code_p =
1818 (struct optval_status_code*)status_code;
1819 (*status_code_p).status_code = htons(DHCP6_STATUS_SUCCESS);
1820 memcpy(&(*status_code_p).status_msg, status_code_msg,
1822 server_ia_na_len += (status_code_len+4);
1823 free(status_code_msg);
1825 status_code_msg = xstrdup("There's no available address.");
1826 status_code_len = strlen(status_code_msg)+1;
1827 status_code = xzalloc(status_code_len);
1828 struct optval_status_code *status_code_p =
1829 (struct optval_status_code*)status_code;
1830 (*status_code_p).status_code = htons(DHCP6_STATUS_NOADDRSAVAIL);
1831 memcpy(&(*status_code_p).status_msg, status_code_msg,
1833 server_ia_na_len += (status_code_len+4);
1834 server_ia_na_len -= (ia_addr_len+4);
1837 free(status_code_msg);
1838 //TODO send failed status code
1843 server_ia_na = xzalloc(server_ia_na_len);
1844 struct optval_ia_na *ia_na_p = (struct optval_ia_na*)server_ia_na;
1845 (*ia_na_p).iaid = (*(struct optval_ia_na*)client_ia_na).iaid;
1846 (*ia_na_p).t1 = gconfig.t1;
1847 (*ia_na_p).t2 = gconfig.t2;
1849 uint8_t* ia_na_optptr = &(*ia_na_p).optval;
1851 set_optval6(ia_na_optptr, DHCP6_OPT_IA_ADDR, ia_addr, ia_addr_len);
1852 ia_na_optptr += (ia_addr_len + 4);
1855 if(status_code_len) {
1856 set_optval6(ia_na_optptr, DHCP6_OPT_STATUS_CODE, status_code,
1858 ia_na_optptr += (status_code_len);
1862 //Response: Identity Association for Non-temporary Address
1863 optptr = set_optval6(optptr, DHCP6_OPT_IA_NA, server_ia_na,
1865 optlen += (server_ia_na_len + 4);
1866 free(client_ia_na);free(server_ia_na);
1868 //Receive: Identity Association for Prefix Delegation
1869 else if(get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
1870 DHCP6_OPT_IA_PD, &client_ia_pd_len, &client_ia_pd)) {
1873 //Response: Identity Association for Prefix Delegation
1876 //Receive: Client Identifier (DUID)
1877 get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
1878 DHCP6_OPT_CLIENTID, &client_duid_len, &client_duid);
1880 //DUID type: link-layer address plus time
1881 if(ntohs((*(struct optval_duid_llt*)client_duid).type) ==
1883 server_duid_len = 8+sizeof(gconfig.server_mac);
1884 server_duid = xzalloc(server_duid_len);
1885 struct optval_duid_llt *server_duid_p =
1886 (struct optval_duid_llt*)server_duid;
1887 (*server_duid_p).type = htons(1);
1888 (*server_duid_p).hwtype = htons(1);
1889 (*server_duid_p).time = htonl((uint32_t)
1890 (time(NULL) - 946684800) & 0xffffffff);
1891 memcpy(&(*server_duid_p).lladdr, gconfig.server_mac,
1892 sizeof(gconfig.server_mac));
1893 memcpy(&client_lla, &(*(struct optval_duid_llt*)client_duid).lladdr,
1894 sizeof(client_lla));
1896 //Response: Server Identifier (DUID)
1897 optptr = set_optval6(optptr, DHCP6_OPT_SERVERID, server_duid,
1899 optlen += (server_duid_len + 4);
1900 //Response: Client Identifier
1901 optptr = set_optval6(optptr, DHCP6_OPT_CLIENTID, client_duid,
1903 optlen += (client_duid_len + 4);
1904 free(client_duid);free(server_duid);
1907 send_packet6(0, client_lla, optlen);
1911 dbg("Message Type: DHCP6REQUEST\n");
1912 optptr = prepare_send_pkt6(DHCP6REPLY);
1915 //Receive: Client Identifier (DUID)
1916 get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
1917 DHCP6_OPT_CLIENTID, &client_duid_len, &client_duid);
1918 optptr = set_optval6(optptr, DHCP6_OPT_CLIENTID, client_duid,
1920 optlen += (client_duid_len + 4);
1921 memcpy(&client_lla, &(*(struct optval_duid_llt*)client_duid).lladdr,
1922 sizeof(client_lla));
1924 //Receive: Identity Association for Non-temporary Address
1925 if(get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
1926 DHCP6_OPT_IA_NA, &client_ia_na_len, &client_ia_na)) {
1927 uint16_t ia_addr_len = 0, status_code_len = 0;
1928 void *ia_addr, *status_code;
1929 uint16_t server_ia_na_len =
1930 sizeof(struct optval_ia_na)-sizeof(uint8_t*);
1931 char *status_code_msg;
1934 get_optval6((uint8_t*)&(*(struct optval_ia_na*)client_ia_na).optval,
1935 DHCP6_OPT_IA_ADDR, &ia_addr_len, &ia_addr);
1936 struct optval_ia_addr *ia_addr_p = (struct optval_ia_addr*)ia_addr;
1937 if(verifyip6_in_lease((*ia_addr_p).ipv6_addr, client_duid,
1938 DHCP6_OPT_IA_NA, (*(struct optval_ia_na*)client_ia_na).iaid)
1940 server_ia_na_len += (ia_addr_len + 4);
1942 status_code_msg = xstrdup("Assigned an address.");
1943 status_code_len = strlen(status_code_msg) + 1;
1944 status_code = xzalloc(status_code_len);
1945 struct optval_status_code *status_code_p =
1946 (struct optval_status_code*)status_code;
1947 (*status_code_p).status_code = htons(DHCP6_STATUS_SUCCESS);
1948 memcpy(&(*status_code_p).status_msg, status_code_msg,
1950 server_ia_na_len += (status_code_len+4);
1952 //TODO send failed status code
1957 server_ia_na = xzalloc(server_ia_na_len);
1958 struct optval_ia_na *ia_na_p = (struct optval_ia_na*)server_ia_na;
1959 (*ia_na_p).iaid = (*(struct optval_ia_na*)client_ia_na).iaid;
1960 (*ia_na_p).t1 = gconfig.t1;
1961 (*ia_na_p).t2 = gconfig.t2;
1963 uint8_t* ia_na_optptr = &(*ia_na_p).optval;
1964 ia_na_optptr = set_optval6(ia_na_optptr, DHCP6_OPT_IA_ADDR,
1965 ia_addr, ia_addr_len);
1968 if(status_code_len) {
1969 ia_na_optptr = set_optval6(ia_na_optptr, DHCP6_OPT_STATUS_CODE,
1970 status_code, status_code_len);
1974 //Response: Identity Association for Non-temporary Address
1975 //(Status Code added)
1976 optptr = set_optval6(optptr, DHCP6_OPT_IA_NA,
1977 server_ia_na, server_ia_na_len);
1978 optlen += (server_ia_na_len + 4);
1979 free(client_ia_na);free(server_ia_na);
1982 //Receive: Server Identifier (DUID)
1983 get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
1984 DHCP6_OPT_SERVERID, &server_duid_len, &server_duid);
1985 optptr = set_optval6(optptr, DHCP6_OPT_SERVERID,
1986 server_duid, server_duid_len);
1987 optlen += (server_duid_len + 4);
1989 free(client_duid); free(server_duid);
1991 send_packet6(0, client_lla, optlen);
1994 case DHCP6RENEW: //TODO
1995 case DHCP6REBIND: //TODO
1997 dbg("Message Type: DHCP6RELEASE\n");
1998 optptr = prepare_send_pkt6(DHCP6REPLY);
2001 dbg("Message Type : %u\n", gstate.rqcode);
2006 if(read_packet() < 0) {
2010 waited += time(NULL) - timestmp;
2012 get_optval((uint8_t*)&gstate.rcvd.rcvd_pkt.options,
2013 DHCP_OPT_MESSAGE_TYPE, &gstate.rqcode);
2014 if (gstate.rqcode == 0 || gstate.rqcode < DHCPDISCOVER
2015 || gstate.rqcode > DHCPINFORM) {
2016 dbg("no or bad message type option, ignoring packet.\n");
2019 get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
2020 DHCP_OPT_SERVER_ID, &serverid);
2021 if (serverid && (serverid != gconfig.server_nip)) {
2022 dbg("server ID doesn't match, ignoring packet.\n");
2026 waited += time(NULL) - timestmp;
2027 switch (gstate.rqcode) {
2029 msgtype = DHCPOFFER;
2030 dbg("Message Type : DHCPDISCOVER\n");
2031 get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
2032 DHCP_OPT_REQUESTED_IP, &requested_nip);
2033 get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
2034 DHCP_OPT_HOST_NAME, &hstname);
2035 reqested_lease = gconfig.offer_time;
2036 get_reqparam(&gstate.rqopt);
2037 optptr = prepare_send_pkt();
2038 gstate.send.send_pkt.yiaddr = getip_from_pool(requested_nip,
2039 gstate.rcvd.rcvd_pkt.chaddr, &reqested_lease, hstname);
2040 if(!gstate.send.send_pkt.yiaddr){
2042 optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1);
2046 get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
2047 DHCP_OPT_LEASE_TIME, &reqested_lease);
2048 reqested_lease = htonl(get_lease(reqested_lease + time(NULL)));
2049 optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1);
2050 optptr = set_optval(optptr, DHCP_OPT_SERVER_ID, &gconfig.server_nip, 4);
2051 optptr = set_optval(optptr, DHCP_OPT_LEASE_TIME, &reqested_lease, 4);
2052 optptr = set_reqparam(optptr, gstate.rqopt);
2057 dbg("Message Type : DHCPREQUEST\n");
2058 optptr = prepare_send_pkt();
2059 get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
2060 DHCP_OPT_REQUESTED_IP, &requested_nip);
2061 get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
2062 DHCP_OPT_LEASE_TIME, &reqested_lease);
2063 get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
2064 DHCP_OPT_HOST_NAME, &hstname);
2065 gstate.send.send_pkt.yiaddr = getip_from_pool(requested_nip,
2066 gstate.rcvd.rcvd_pkt.chaddr, &reqested_lease, hstname);
2067 if (!serverid) reqested_lease = gconfig.max_lease_sec;
2068 if (!gstate.send.send_pkt.yiaddr) {
2070 optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1);
2074 get_reqparam(&gstate.rqopt);
2075 optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1);
2076 optptr = set_optval(optptr, DHCP_OPT_SERVER_ID, &gconfig.server_nip, 4);
2077 reqested_lease = htonl(reqested_lease);
2078 optptr = set_optval(optptr, DHCP_OPT_LEASE_TIME, &reqested_lease, 4);
2079 optptr = set_reqparam(optptr, gstate.rqopt);
2083 case DHCPDECLINE:// FALL THROUGH
2085 dbg("Message Type : DHCPDECLINE or DHCPRELEASE \n");
2086 get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
2087 DHCP_OPT_SERVER_ID, &serverid);
2088 if (serverid != gconfig.server_nip) break;
2089 get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
2090 DHCP_OPT_REQUESTED_IP, &requested_nip);
2091 delip_from_lease(requested_nip, gstate.rcvd.rcvd_pkt.chaddr,
2092 (gstate.rqcode==DHCPRELEASE)?0:gconfig.decline_time);
2095 dbg("Message Type : %u\n", gstate.rqcode);