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