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