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, ×tamp, 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, ×tamp, 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, ×tamp, 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, ×tamp, 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