1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41#include <netinet/ether.h>
42#include <syslog.h>
43#include "common.h"
44#include "dhcpc.h"
45#include "dhcpd.h"
46
47
48#define g_leases ((struct dyn_lease*)ptr_to_globals)
49
50
51
52
53
54static void add_static_lease(struct static_lease **st_lease_pp,
55 uint8_t *mac,
56 uint32_t nip)
57{
58 struct static_lease *st_lease;
59
60
61 while ((st_lease = *st_lease_pp) != NULL) {
62 st_lease_pp = &st_lease->next;
63 }
64
65
66 *st_lease_pp = st_lease = xzalloc(sizeof(*st_lease));
67 memcpy(st_lease->mac, mac, 6);
68 st_lease->nip = nip;
69
70}
71
72
73static uint32_t get_static_nip_by_mac(struct static_lease *st_lease, void *mac)
74{
75 while (st_lease) {
76 if (memcmp(st_lease->mac, mac, 6) == 0)
77 return st_lease->nip;
78 st_lease = st_lease->next;
79 }
80
81 return 0;
82}
83
84static int is_nip_reserved(struct static_lease *st_lease, uint32_t nip)
85{
86 while (st_lease) {
87 if (st_lease->nip == nip)
88 return 1;
89 st_lease = st_lease->next;
90 }
91
92 return 0;
93}
94
95#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
96
97
98static void log_static_leases(struct static_lease **st_lease_pp)
99{
100 struct static_lease *cur;
101
102 if (dhcp_verbose < 2)
103 return;
104
105 cur = *st_lease_pp;
106 while (cur) {
107 bb_error_msg("static lease: mac:%02x:%02x:%02x:%02x:%02x:%02x nip:%x",
108 cur->mac[0], cur->mac[1], cur->mac[2],
109 cur->mac[3], cur->mac[4], cur->mac[5],
110 cur->nip
111 );
112 cur = cur->next;
113 }
114}
115#else
116# define log_static_leases(st_lease_pp) ((void)0)
117#endif
118
119
120static struct dyn_lease *oldest_expired_lease(void)
121{
122 struct dyn_lease *oldest_lease = NULL;
123 leasetime_t oldest_time = time(NULL);
124 unsigned i;
125
126
127
128 for (i = 0; i < server_config.max_leases; i++) {
129 if (g_leases[i].expires == 0
130 || g_leases[i].expires < oldest_time
131 ) {
132 oldest_time = g_leases[i].expires;
133 oldest_lease = &g_leases[i];
134 }
135 }
136 return oldest_lease;
137}
138
139
140
141
142static void clear_leases(const uint8_t *chaddr, uint32_t yiaddr)
143{
144 unsigned i;
145
146 for (i = 0; i < server_config.max_leases; i++) {
147 if ((chaddr && memcmp(g_leases[i].lease_mac, chaddr, 6) == 0)
148 || (yiaddr && g_leases[i].lease_nip == yiaddr)
149 ) {
150 memset(&g_leases[i], 0, sizeof(g_leases[i]));
151 }
152 }
153}
154
155
156
157
158static struct dyn_lease *add_lease(
159 const uint8_t *chaddr, uint32_t yiaddr,
160 leasetime_t leasetime,
161 const char *hostname, int hostname_len)
162{
163 struct dyn_lease *oldest;
164
165
166 clear_leases(chaddr, yiaddr);
167
168 oldest = oldest_expired_lease();
169
170 if (oldest) {
171 memset(oldest, 0, sizeof(*oldest));
172 if (hostname) {
173 char *p;
174
175 hostname_len++;
176 if (hostname_len > sizeof(oldest->hostname))
177 hostname_len = sizeof(oldest->hostname);
178 p = safe_strncpy(oldest->hostname, hostname, hostname_len);
179
180
181
182
183
184
185 while (*p) {
186 if (!isalnum(*p) && *p != '-' && *p != '_')
187 *p = '.';
188 p++;
189 }
190 }
191 if (chaddr)
192 memcpy(oldest->lease_mac, chaddr, 6);
193 oldest->lease_nip = yiaddr;
194 oldest->expires = time(NULL) + leasetime;
195 }
196
197 return oldest;
198}
199
200
201static int is_expired_lease(struct dyn_lease *lease)
202{
203 return (lease->expires < (leasetime_t) time(NULL));
204}
205
206
207static struct dyn_lease *find_lease_by_mac(const uint8_t *mac)
208{
209 unsigned i;
210
211 for (i = 0; i < server_config.max_leases; i++)
212 if (memcmp(g_leases[i].lease_mac, mac, 6) == 0)
213 return &g_leases[i];
214
215 return NULL;
216}
217
218
219static struct dyn_lease *find_lease_by_nip(uint32_t nip)
220{
221 unsigned i;
222
223 for (i = 0; i < server_config.max_leases; i++)
224 if (g_leases[i].lease_nip == nip)
225 return &g_leases[i];
226
227 return NULL;
228}
229
230
231static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac, unsigned arpping_ms)
232{
233 struct in_addr temp;
234 int r;
235
236 r = arpping(nip, safe_mac,
237 server_config.server_nip,
238 server_config.server_mac,
239 server_config.interface,
240 arpping_ms);
241 if (r)
242 return r;
243
244 temp.s_addr = nip;
245 bb_error_msg("%s belongs to someone, reserving it for %u seconds",
246 inet_ntoa(temp), (unsigned)server_config.conflict_time);
247 add_lease(NULL, nip, server_config.conflict_time, NULL, 0);
248 return 0;
249}
250
251
252static uint32_t find_free_or_expired_nip(const uint8_t *safe_mac, unsigned arpping_ms)
253{
254 uint32_t addr;
255 struct dyn_lease *oldest_lease = NULL;
256
257#if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC
258 uint32_t stop;
259 unsigned i, hash;
260
261
262
263
264 hash = 0;
265 for (i = 0; i < 6; i++)
266 hash += safe_mac[i] + (hash << 6) + (hash << 16) - hash;
267
268
269 addr = server_config.start_ip
270 + (hash % (1 + server_config.end_ip - server_config.start_ip));
271 stop = addr;
272#else
273 addr = server_config.start_ip;
274#define stop (server_config.end_ip + 1)
275#endif
276 do {
277 uint32_t nip;
278 struct dyn_lease *lease;
279
280
281 if ((addr & 0xff) == 0)
282 goto next_addr;
283
284 if ((addr & 0xff) == 0xff)
285 goto next_addr;
286 nip = htonl(addr);
287
288 if (nip == server_config.server_nip)
289 goto next_addr;
290
291 if (is_nip_reserved(server_config.static_leases, nip))
292 goto next_addr;
293
294 lease = find_lease_by_nip(nip);
295 if (!lease) {
296
297 if (nobody_responds_to_arp(nip, safe_mac, arpping_ms))
298 return nip;
299 } else {
300 if (!oldest_lease || lease->expires < oldest_lease->expires)
301 oldest_lease = lease;
302 }
303
304 next_addr:
305 addr++;
306#if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC
307 if (addr > server_config.end_ip)
308 addr = server_config.start_ip;
309#endif
310 } while (addr != stop);
311
312 if (oldest_lease
313 && is_expired_lease(oldest_lease)
314 && nobody_responds_to_arp(oldest_lease->lease_nip, safe_mac, arpping_ms)
315 ) {
316 return oldest_lease->lease_nip;
317 }
318
319 return 0;
320}
321
322
323static int FAST_FUNC read_str(const char *line, void *arg)
324{
325 char **dest = arg;
326
327 free(*dest);
328 *dest = xstrdup(line);
329 return 1;
330}
331
332static int FAST_FUNC read_u32(const char *line, void *arg)
333{
334 *(uint32_t*)arg = bb_strtou32(line, NULL, 10);
335 return errno == 0;
336}
337
338static int FAST_FUNC read_staticlease(const char *const_line, void *arg)
339{
340 char *line;
341 char *mac_string;
342 char *ip_string;
343 struct ether_addr mac_bytes;
344 uint32_t nip;
345
346
347 line = (char *) const_line;
348 mac_string = strtok_r(line, " \t", &line);
349 if (!mac_string || !ether_aton_r(mac_string, &mac_bytes))
350 return 0;
351
352
353 ip_string = strtok_r(NULL, " \t", &line);
354 if (!ip_string || !udhcp_str2nip(ip_string, &nip))
355 return 0;
356
357 add_static_lease(arg, (uint8_t*) &mac_bytes, nip);
358
359 log_static_leases(arg);
360
361 return 1;
362}
363
364static int FAST_FUNC read_optset(const char *line, void *arg) {
365 return udhcp_str2optset(line, arg,
366 dhcp_optflags, dhcp_option_strings,
367 0
368 );
369}
370
371struct config_keyword {
372 const char *keyword;
373 int (*handler)(const char *line, void *var) FAST_FUNC;
374 unsigned ofs;
375 const char *def;
376};
377
378#define OFS(field) offsetof(struct server_config_t, field)
379
380static const struct config_keyword keywords[] = {
381
382 {"start" , udhcp_str2nip , OFS(start_ip ), "192.168.0.20"},
383 {"end" , udhcp_str2nip , OFS(end_ip ), "192.168.0.254"},
384 {"interface" , read_str , OFS(interface ), "eth0"},
385
386
387 {"max_leases" , read_u32 , OFS(max_leases ), "235"},
388 {"auto_time" , read_u32 , OFS(auto_time ), "7200"},
389 {"decline_time" , read_u32 , OFS(decline_time ), "3600"},
390 {"conflict_time", read_u32 , OFS(conflict_time), "3600"},
391 {"offer_time" , read_u32 , OFS(offer_time ), "60"},
392 {"min_lease" , read_u32 , OFS(min_lease_sec), "60"},
393 {"lease_file" , read_str , OFS(lease_file ), LEASES_FILE},
394 {"pidfile" , read_str , OFS(pidfile ), "/var/run/udhcpd.pid"},
395 {"siaddr" , udhcp_str2nip , OFS(siaddr_nip ), "0.0.0.0"},
396
397 {"option" , read_optset , OFS(options ), ""},
398 {"opt" , read_optset , OFS(options ), ""},
399 {"notify_file" , read_str , OFS(notify_file ), NULL},
400 {"sname" , read_str , OFS(sname ), NULL},
401 {"boot_file" , read_str , OFS(boot_file ), NULL},
402 {"static_lease" , read_staticlease, OFS(static_leases), ""},
403};
404enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 };
405
406static NOINLINE void read_config(const char *file)
407{
408 parser_t *parser;
409 const struct config_keyword *k;
410 unsigned i;
411 char *token[2];
412
413 for (i = 0; i < KWS_WITH_DEFAULTS; i++)
414 keywords[i].handler(keywords[i].def, (char*)&server_config + keywords[i].ofs);
415
416 parser = config_open(file);
417 while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
418 for (k = keywords, i = 0; i < ARRAY_SIZE(keywords); k++, i++) {
419 if (strcasecmp(token[0], k->keyword) == 0) {
420 if (!k->handler(token[1], (char*)&server_config + k->ofs)) {
421 bb_error_msg("can't parse line %u in %s",
422 parser->lineno, file);
423
424 k->handler(k->def, (char*)&server_config + k->ofs);
425 }
426 break;
427 }
428 }
429 }
430 config_close(parser);
431
432 server_config.start_ip = ntohl(server_config.start_ip);
433 server_config.end_ip = ntohl(server_config.end_ip);
434}
435
436static void write_leases(void)
437{
438 int fd;
439 unsigned i;
440 leasetime_t curr;
441 int64_t written_at;
442
443 fd = open_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC);
444 if (fd < 0)
445 return;
446
447 curr = written_at = time(NULL);
448
449 written_at = SWAP_BE64(written_at);
450 full_write(fd, &written_at, sizeof(written_at));
451
452 for (i = 0; i < server_config.max_leases; i++) {
453 leasetime_t tmp_time;
454
455 if (g_leases[i].lease_nip == 0)
456 continue;
457
458
459 tmp_time = g_leases[i].expires;
460
461 g_leases[i].expires -= curr;
462 if ((signed_leasetime_t) g_leases[i].expires < 0)
463 g_leases[i].expires = 0;
464 g_leases[i].expires = htonl(g_leases[i].expires);
465
466
467
468 full_write(fd, &g_leases[i], sizeof(g_leases[i]));
469
470
471 g_leases[i].expires = tmp_time;
472 }
473 close(fd);
474
475 if (server_config.notify_file) {
476 char *argv[3];
477 argv[0] = server_config.notify_file;
478 argv[1] = server_config.lease_file;
479 argv[2] = NULL;
480 spawn_and_wait(argv);
481 }
482}
483
484static NOINLINE void read_leases(const char *file)
485{
486 struct dyn_lease lease;
487 int64_t written_at, time_passed;
488 int fd;
489#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
490 unsigned i = 0;
491#endif
492
493 fd = open_or_warn(file, O_RDONLY);
494 if (fd < 0)
495 return;
496
497 if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at))
498 goto ret;
499 written_at = SWAP_BE64(written_at);
500
501 time_passed = time(NULL) - written_at;
502
503
504 if ((uint64_t)time_passed > 12 * 60 * 60)
505 goto ret;
506
507 while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) {
508 uint32_t y = ntohl(lease.lease_nip);
509 if (y >= server_config.start_ip && y <= server_config.end_ip) {
510 signed_leasetime_t expires = ntohl(lease.expires) - (signed_leasetime_t)time_passed;
511 uint32_t static_nip;
512
513 if (expires <= 0)
514
515
516
517
518 expires = 0;
519
520
521 static_nip = get_static_nip_by_mac(server_config.static_leases, lease.lease_mac);
522 if (static_nip) {
523
524
525 continue;
526 }
527 if (is_nip_reserved(server_config.static_leases, lease.lease_nip))
528 continue;
529
530
531
532 if (add_lease(lease.lease_mac, lease.lease_nip,
533 expires,
534 lease.hostname, sizeof(lease.hostname)
535 ) == 0
536 ) {
537 bb_error_msg("too many leases while loading %s", file);
538 break;
539 }
540#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
541 i++;
542#endif
543 }
544 }
545 log1("read %d leases", i);
546 ret:
547 close(fd);
548}
549
550
551static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadcast)
552{
553 const uint8_t *chaddr;
554 uint32_t ciaddr;
555
556
557
558
559
560
561
562
563
564
565
566
567
568 if (force_broadcast
569 || (dhcp_pkt->flags & htons(BROADCAST_FLAG))
570 || dhcp_pkt->ciaddr == 0
571 ) {
572 log1("broadcasting packet to client");
573 ciaddr = INADDR_BROADCAST;
574 chaddr = MAC_BCAST_ADDR;
575 } else {
576 log1("unicasting packet to client ciaddr");
577 ciaddr = dhcp_pkt->ciaddr;
578 chaddr = dhcp_pkt->chaddr;
579 }
580
581 udhcp_send_raw_packet(dhcp_pkt,
582 server_config.server_nip, SERVER_PORT,
583 ciaddr, CLIENT_PORT, chaddr,
584 server_config.ifindex);
585}
586
587
588static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
589{
590 log1("forwarding packet to relay");
591
592 udhcp_send_kernel_packet(dhcp_pkt,
593 server_config.server_nip, SERVER_PORT,
594 dhcp_pkt->gateway_nip, SERVER_PORT);
595}
596
597static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
598{
599 if (dhcp_pkt->gateway_nip)
600 send_packet_to_relay(dhcp_pkt);
601 else
602 send_packet_to_client(dhcp_pkt, force_broadcast);
603}
604
605static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type)
606{
607
608
609 udhcp_init_header(packet, type);
610
611 packet->xid = oldpacket->xid;
612 memcpy(packet->chaddr, oldpacket->chaddr, sizeof(oldpacket->chaddr));
613 packet->flags = oldpacket->flags;
614 packet->gateway_nip = oldpacket->gateway_nip;
615 packet->ciaddr = oldpacket->ciaddr;
616 udhcp_add_simple_option(packet, DHCP_SERVER_ID, server_config.server_nip);
617}
618
619
620
621
622static void add_server_options(struct dhcp_packet *packet)
623{
624 struct option_set *curr = server_config.options;
625
626 while (curr) {
627 if (curr->data[OPT_CODE] != DHCP_LEASE_TIME)
628 udhcp_add_binary_option(packet, curr->data);
629 curr = curr->next;
630 }
631
632 packet->siaddr_nip = server_config.siaddr_nip;
633
634 if (server_config.sname)
635 strncpy((char*)packet->sname, server_config.sname, sizeof(packet->sname) - 1);
636 if (server_config.boot_file)
637 strncpy((char*)packet->file, server_config.boot_file, sizeof(packet->file) - 1);
638}
639
640static uint32_t select_lease_time(struct dhcp_packet *packet)
641{
642 uint32_t lease_time_sec = server_config.max_lease_sec;
643 uint8_t *lease_time_opt = udhcp_get_option32(packet, DHCP_LEASE_TIME);
644 if (lease_time_opt) {
645 move_from_unaligned32(lease_time_sec, lease_time_opt);
646 lease_time_sec = ntohl(lease_time_sec);
647 if (lease_time_sec > server_config.max_lease_sec)
648 lease_time_sec = server_config.max_lease_sec;
649 if (lease_time_sec < server_config.min_lease_sec)
650 lease_time_sec = server_config.min_lease_sec;
651 }
652 return lease_time_sec;
653}
654
655
656
657static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
658 uint32_t static_lease_nip,
659 struct dyn_lease *lease,
660 uint8_t *requested_ip_opt,
661 unsigned arpping_ms)
662{
663 struct dhcp_packet packet;
664 uint32_t lease_time_sec;
665 struct in_addr addr;
666
667 init_packet(&packet, oldpacket, DHCPOFFER);
668
669
670 packet.yiaddr = static_lease_nip;
671
672 if (!static_lease_nip) {
673
674 uint32_t req_nip;
675 const char *p_host_name;
676
677 if (lease) {
678
679
680
681
682 packet.yiaddr = lease->lease_nip;
683 }
684
685 else if (requested_ip_opt != NULL
686
687 && (move_from_unaligned32(req_nip, requested_ip_opt), 1)
688
689 && ntohl(req_nip) >= server_config.start_ip
690 && ntohl(req_nip) <= server_config.end_ip
691
692 && ( !(lease = find_lease_by_nip(req_nip))
693 || is_expired_lease(lease)
694 )
695 ) {
696 packet.yiaddr = req_nip;
697 }
698 else {
699
700 packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr, arpping_ms);
701 }
702
703 if (!packet.yiaddr) {
704 bb_error_msg("no free IP addresses. OFFER abandoned");
705 return;
706 }
707
708 p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
709 lease = add_lease(packet.chaddr, packet.yiaddr,
710 server_config.offer_time,
711 p_host_name,
712 p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
713 );
714 if (!lease) {
715 bb_error_msg("no free IP addresses. OFFER abandoned");
716 return;
717 }
718 }
719
720 lease_time_sec = select_lease_time(oldpacket);
721 udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
722 add_server_options(&packet);
723
724 addr.s_addr = packet.yiaddr;
725 bb_error_msg("sending OFFER of %s", inet_ntoa(addr));
726
727 send_packet(&packet, 0);
728}
729
730
731static NOINLINE void send_NAK(struct dhcp_packet *oldpacket)
732{
733 struct dhcp_packet packet;
734
735 init_packet(&packet, oldpacket, DHCPNAK);
736
737 log1("sending %s", "NAK");
738 send_packet(&packet, 1);
739}
740
741
742static NOINLINE void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr)
743{
744 struct dhcp_packet packet;
745 uint32_t lease_time_sec;
746 struct in_addr addr;
747 const char *p_host_name;
748
749 init_packet(&packet, oldpacket, DHCPACK);
750 packet.yiaddr = yiaddr;
751
752 lease_time_sec = select_lease_time(oldpacket);
753 udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
754
755 add_server_options(&packet);
756
757 addr.s_addr = yiaddr;
758 bb_error_msg("sending ACK to %s", inet_ntoa(addr));
759 send_packet(&packet, 0);
760
761 p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
762 add_lease(packet.chaddr, packet.yiaddr,
763 lease_time_sec,
764 p_host_name,
765 p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
766 );
767 if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) {
768
769 write_leases();
770 }
771}
772
773
774static NOINLINE void send_inform(struct dhcp_packet *oldpacket)
775{
776 struct dhcp_packet packet;
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795 init_packet(&packet, oldpacket, DHCPACK);
796 add_server_options(&packet);
797
798 send_packet(&packet, 0);
799}
800
801int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
802int udhcpd_main(int argc UNUSED_PARAM, char **argv)
803{
804 int server_socket = -1, retval;
805 uint8_t *state;
806 unsigned timeout_end;
807 unsigned num_ips;
808 unsigned opt;
809 struct option_set *option;
810 char *str_I = str_I;
811 const char *str_a = "2000";
812 unsigned arpping_ms;
813 IF_FEATURE_UDHCP_PORT(char *str_P;)
814
815 setup_common_bufsiz();
816
817 IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)
818 IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)
819
820 opt = getopt32(argv, "^"
821 "fSI:va:"IF_FEATURE_UDHCP_PORT("P:")
822 "\0"
823#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
824 "vv"
825#endif
826 , &str_I
827 , &str_a
828 IF_FEATURE_UDHCP_PORT(, &str_P)
829 IF_UDHCP_VERBOSE(, &dhcp_verbose)
830 );
831 if (!(opt & 1)) {
832 bb_daemonize_or_rexec(0, argv);
833 logmode = LOGMODE_NONE;
834 }
835
836 argv += optind;
837 if (opt & 2) {
838 openlog(applet_name, LOG_PID, LOG_DAEMON);
839 logmode |= LOGMODE_SYSLOG;
840 }
841 if (opt & 4) {
842 len_and_sockaddr *lsa = xhost_and_af2sockaddr(str_I, 0, AF_INET);
843 server_config.server_nip = lsa->u.sin.sin_addr.s_addr;
844 free(lsa);
845 }
846#if ENABLE_FEATURE_UDHCP_PORT
847 if (opt & 32) {
848 SERVER_PORT = xatou16(str_P);
849 CLIENT_PORT = SERVER_PORT + 1;
850 }
851#endif
852 arpping_ms = xatou(str_a);
853
854
855
856 read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE);
857
858 if (server_config.auto_time > INT_MAX / 1000)
859 server_config.auto_time = INT_MAX / 1000;
860
861
862 bb_sanitize_stdio();
863
864
865 write_pidfile(server_config.pidfile);
866
867
868 bb_error_msg("started, v"BB_VER);
869
870 option = udhcp_find_option(server_config.options, DHCP_LEASE_TIME);
871 server_config.max_lease_sec = DEFAULT_LEASE_TIME;
872 if (option) {
873 move_from_unaligned32(server_config.max_lease_sec, option->data + OPT_DATA);
874 server_config.max_lease_sec = ntohl(server_config.max_lease_sec);
875 }
876
877
878 num_ips = server_config.end_ip - server_config.start_ip + 1;
879 if (server_config.max_leases > num_ips) {
880 bb_error_msg("max_leases=%u is too big, setting to %u",
881 (unsigned)server_config.max_leases, num_ips);
882 server_config.max_leases = num_ips;
883 }
884
885
886 SET_PTR_TO_GLOBALS(xzalloc(server_config.max_leases * sizeof(g_leases[0])));
887
888 read_leases(server_config.lease_file);
889
890 if (udhcp_read_interface(server_config.interface,
891 &server_config.ifindex,
892 (server_config.server_nip == 0 ? &server_config.server_nip : NULL),
893 server_config.server_mac)
894 ) {
895 retval = 1;
896 goto ret;
897 }
898
899
900 udhcp_sp_setup();
901
902 continue_with_autotime:
903 timeout_end = monotonic_sec() + server_config.auto_time;
904 while (1) {
905 struct pollfd pfds[2];
906 struct dhcp_packet packet;
907 int bytes;
908 int tv;
909 uint8_t *server_id_opt;
910 uint8_t *requested_ip_opt;
911 uint32_t requested_nip = requested_nip;
912 uint32_t static_lease_nip;
913 struct dyn_lease *lease, fake_lease;
914
915 if (server_socket < 0) {
916 server_socket = udhcp_listen_socket( SERVER_PORT,
917 server_config.interface);
918 }
919
920 udhcp_sp_fd_set(pfds, server_socket);
921
922 new_tv:
923 tv = -1;
924 if (server_config.auto_time) {
925 tv = timeout_end - monotonic_sec();
926 if (tv <= 0) {
927 write_leases:
928 write_leases();
929 goto continue_with_autotime;
930 }
931 tv *= 1000;
932 }
933
934
935 retval = poll(pfds, 2, tv);
936 if (retval <= 0) {
937 if (retval == 0)
938 goto write_leases;
939 if (errno == EINTR)
940 goto new_tv;
941
942 bb_perror_msg_and_die("poll");
943 }
944
945 if (pfds[0].revents) switch (udhcp_sp_read()) {
946 case SIGUSR1:
947 bb_error_msg("received %s", "SIGUSR1");
948 write_leases();
949
950 goto continue_with_autotime;
951 case SIGTERM:
952 bb_error_msg("received %s", "SIGTERM");
953 write_leases();
954 goto ret0;
955 }
956
957
958 if (!pfds[1].revents)
959 continue;
960
961
962
963
964
965 bytes = udhcp_recv_kernel_packet(&packet, server_socket);
966 if (bytes < 0) {
967
968 if (bytes == -1 && errno != EINTR) {
969 log1("read error: "STRERROR_FMT", reopening socket" STRERROR_ERRNO);
970 close(server_socket);
971 server_socket = -1;
972 }
973 continue;
974 }
975 if (packet.hlen != 6) {
976 bb_error_msg("MAC length != 6, ignoring packet");
977 continue;
978 }
979 if (packet.op != BOOTREQUEST) {
980 bb_error_msg("not a REQUEST, ignoring packet");
981 continue;
982 }
983 state = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
984 if (state == NULL || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) {
985 bb_error_msg("no or bad message type option, ignoring packet");
986 continue;
987 }
988
989
990 server_id_opt = udhcp_get_option32(&packet, DHCP_SERVER_ID);
991 if (server_id_opt) {
992 uint32_t server_id_network_order;
993 move_from_unaligned32(server_id_network_order, server_id_opt);
994 if (server_id_network_order != server_config.server_nip) {
995
996 log1("server ID doesn't match, ignoring");
997 continue;
998 }
999 }
1000
1001
1002 static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr);
1003 if (static_lease_nip) {
1004 bb_error_msg("found static lease: %x", static_lease_nip);
1005 memcpy(&fake_lease.lease_mac, &packet.chaddr, 6);
1006 fake_lease.lease_nip = static_lease_nip;
1007 fake_lease.expires = 0;
1008 lease = &fake_lease;
1009 } else {
1010 lease = find_lease_by_mac(packet.chaddr);
1011 }
1012
1013
1014 requested_ip_opt = udhcp_get_option32(&packet, DHCP_REQUESTED_IP);
1015 if (requested_ip_opt) {
1016 move_from_unaligned32(requested_nip, requested_ip_opt);
1017 }
1018
1019 switch (state[0]) {
1020
1021 case DHCPDISCOVER:
1022 log1("received %s", "DISCOVER");
1023
1024 send_offer(&packet, static_lease_nip, lease, requested_ip_opt, arpping_ms);
1025 break;
1026
1027 case DHCPREQUEST:
1028 log1("received %s", "REQUEST");
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115 if (!requested_ip_opt) {
1116 requested_nip = packet.ciaddr;
1117 if (requested_nip == 0) {
1118 log1("no requested IP and no ciaddr, ignoring");
1119 break;
1120 }
1121 }
1122 if (lease && requested_nip == lease->lease_nip) {
1123
1124
1125 send_ACK(&packet, lease->lease_nip);
1126 break;
1127 }
1128
1129
1130 if (server_id_opt
1131 || requested_ip_opt
1132 ) {
1133
1134 send_NAK(&packet);
1135 }
1136
1137 break;
1138
1139 case DHCPDECLINE:
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153 log1("received %s", "DECLINE");
1154 if (server_id_opt
1155 && requested_ip_opt
1156 && lease
1157 && requested_nip == lease->lease_nip
1158 ) {
1159 memset(lease->lease_mac, 0, sizeof(lease->lease_mac));
1160 lease->expires = time(NULL) + server_config.decline_time;
1161 }
1162 break;
1163
1164 case DHCPRELEASE:
1165
1166
1167
1168
1169
1170
1171
1172
1173 log1("received %s", "RELEASE");
1174 if (server_id_opt
1175 && lease
1176 && packet.ciaddr == lease->lease_nip
1177 ) {
1178 lease->expires = time(NULL);
1179 }
1180 break;
1181
1182 case DHCPINFORM:
1183 log1("received %s", "INFORM");
1184 send_inform(&packet);
1185 break;
1186 }
1187 }
1188 ret0:
1189 retval = 0;
1190 ret:
1191
1192 remove_pidfile(server_config.pidfile);
1193 return retval;
1194}
1195