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#include <syslog.h>
35#include "common.h"
36#include "dhcpc.h"
37#include "dhcpd.h"
38
39
40
41static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadcast)
42{
43 const uint8_t *chaddr;
44 uint32_t ciaddr;
45
46
47
48
49
50
51
52
53
54
55
56
57
58 if (force_broadcast
59 || (dhcp_pkt->flags & htons(BROADCAST_FLAG))
60 || dhcp_pkt->ciaddr == 0
61 ) {
62 log1("Broadcasting packet to client");
63 ciaddr = INADDR_BROADCAST;
64 chaddr = MAC_BCAST_ADDR;
65 } else {
66 log1("Unicasting packet to client ciaddr");
67 ciaddr = dhcp_pkt->ciaddr;
68 chaddr = dhcp_pkt->chaddr;
69 }
70
71 udhcp_send_raw_packet(dhcp_pkt,
72 server_config.server_nip, SERVER_PORT,
73 ciaddr, CLIENT_PORT, chaddr,
74 server_config.ifindex);
75}
76
77
78static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
79{
80 log1("Forwarding packet to relay");
81
82 udhcp_send_kernel_packet(dhcp_pkt,
83 server_config.server_nip, SERVER_PORT,
84 dhcp_pkt->gateway_nip, SERVER_PORT);
85}
86
87static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
88{
89 if (dhcp_pkt->gateway_nip)
90 send_packet_to_relay(dhcp_pkt);
91 else
92 send_packet_to_client(dhcp_pkt, force_broadcast);
93}
94
95static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type)
96{
97
98
99 udhcp_init_header(packet, type);
100
101 packet->xid = oldpacket->xid;
102 memcpy(packet->chaddr, oldpacket->chaddr, sizeof(oldpacket->chaddr));
103 packet->flags = oldpacket->flags;
104 packet->gateway_nip = oldpacket->gateway_nip;
105 packet->ciaddr = oldpacket->ciaddr;
106 udhcp_add_simple_option(packet, DHCP_SERVER_ID, server_config.server_nip);
107}
108
109
110
111
112static void add_server_options(struct dhcp_packet *packet)
113{
114 struct option_set *curr = server_config.options;
115
116 while (curr) {
117 if (curr->data[OPT_CODE] != DHCP_LEASE_TIME)
118 udhcp_add_binary_option(packet, curr->data);
119 curr = curr->next;
120 }
121
122 packet->siaddr_nip = server_config.siaddr_nip;
123
124 if (server_config.sname)
125 strncpy((char*)packet->sname, server_config.sname, sizeof(packet->sname) - 1);
126 if (server_config.boot_file)
127 strncpy((char*)packet->file, server_config.boot_file, sizeof(packet->file) - 1);
128}
129
130static uint32_t select_lease_time(struct dhcp_packet *packet)
131{
132 uint32_t lease_time_sec = server_config.max_lease_sec;
133 uint8_t *lease_time_opt = udhcp_get_option(packet, DHCP_LEASE_TIME);
134 if (lease_time_opt) {
135 move_from_unaligned32(lease_time_sec, lease_time_opt);
136 lease_time_sec = ntohl(lease_time_sec);
137 if (lease_time_sec > server_config.max_lease_sec)
138 lease_time_sec = server_config.max_lease_sec;
139 if (lease_time_sec < server_config.min_lease_sec)
140 lease_time_sec = server_config.min_lease_sec;
141 }
142 return lease_time_sec;
143}
144
145
146
147static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
148 uint32_t static_lease_nip,
149 struct dyn_lease *lease,
150 uint8_t *requested_ip_opt)
151{
152 struct dhcp_packet packet;
153 uint32_t lease_time_sec;
154 struct in_addr addr;
155
156 init_packet(&packet, oldpacket, DHCPOFFER);
157
158
159 packet.yiaddr = static_lease_nip;
160
161 if (!static_lease_nip) {
162
163 uint32_t req_nip;
164 const char *p_host_name;
165
166 if (lease) {
167
168
169
170
171 packet.yiaddr = lease->lease_nip;
172 }
173
174 else if (requested_ip_opt != NULL
175
176 && (move_from_unaligned32(req_nip, requested_ip_opt), 1)
177
178 && ntohl(req_nip) >= server_config.start_ip
179 && ntohl(req_nip) <= server_config.end_ip
180
181 && ( !(lease = find_lease_by_nip(req_nip))
182 || is_expired_lease(lease)
183 )
184 ) {
185 packet.yiaddr = req_nip;
186 }
187 else {
188
189 packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr);
190 }
191
192 if (!packet.yiaddr) {
193 bb_error_msg("no free IP addresses. OFFER abandoned");
194 return;
195 }
196
197 p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
198 lease = add_lease(packet.chaddr, packet.yiaddr,
199 server_config.offer_time,
200 p_host_name,
201 p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
202 );
203 if (!lease) {
204 bb_error_msg("no free IP addresses. OFFER abandoned");
205 return;
206 }
207 }
208
209 lease_time_sec = select_lease_time(oldpacket);
210 udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
211 add_server_options(&packet);
212
213 addr.s_addr = packet.yiaddr;
214 bb_info_msg("Sending OFFER of %s", inet_ntoa(addr));
215
216 send_packet(&packet, 0);
217}
218
219
220static NOINLINE void send_NAK(struct dhcp_packet *oldpacket)
221{
222 struct dhcp_packet packet;
223
224 init_packet(&packet, oldpacket, DHCPNAK);
225
226 log1("Sending NAK");
227 send_packet(&packet, 1);
228}
229
230
231static NOINLINE void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr)
232{
233 struct dhcp_packet packet;
234 uint32_t lease_time_sec;
235 struct in_addr addr;
236 const char *p_host_name;
237
238 init_packet(&packet, oldpacket, DHCPACK);
239 packet.yiaddr = yiaddr;
240
241 lease_time_sec = select_lease_time(oldpacket);
242 udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
243
244 add_server_options(&packet);
245
246 addr.s_addr = yiaddr;
247 bb_info_msg("Sending ACK to %s", inet_ntoa(addr));
248 send_packet(&packet, 0);
249
250 p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
251 add_lease(packet.chaddr, packet.yiaddr,
252 lease_time_sec,
253 p_host_name,
254 p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
255 );
256 if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) {
257
258 write_leases();
259 }
260}
261
262
263static NOINLINE void send_inform(struct dhcp_packet *oldpacket)
264{
265 struct dhcp_packet packet;
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284 init_packet(&packet, oldpacket, DHCPACK);
285 add_server_options(&packet);
286
287 send_packet(&packet, 0);
288}
289
290
291
292struct dyn_lease *g_leases;
293
294
295
296int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
297int udhcpd_main(int argc UNUSED_PARAM, char **argv)
298{
299 int server_socket = -1, retval, max_sock;
300 uint8_t *state;
301 unsigned timeout_end;
302 unsigned num_ips;
303 unsigned opt;
304 struct option_set *option;
305 IF_FEATURE_UDHCP_PORT(char *str_P;)
306
307#if ENABLE_FEATURE_UDHCP_PORT
308 SERVER_PORT = 67;
309 CLIENT_PORT = 68;
310#endif
311
312#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
313 opt_complementary = "vv";
314#endif
315 opt = getopt32(argv, "fSv"
316 IF_FEATURE_UDHCP_PORT("P:", &str_P)
317#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
318 , &dhcp_verbose
319#endif
320 );
321 if (!(opt & 1)) {
322 bb_daemonize_or_rexec(0, argv);
323 logmode = LOGMODE_NONE;
324 }
325
326 argv += optind;
327 if (opt & 2) {
328 openlog(applet_name, LOG_PID, LOG_DAEMON);
329 logmode |= LOGMODE_SYSLOG;
330 }
331#if ENABLE_FEATURE_UDHCP_PORT
332 if (opt & 8) {
333 SERVER_PORT = xatou16(str_P);
334 CLIENT_PORT = SERVER_PORT + 1;
335 }
336#endif
337
338
339 read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE);
340
341
342 bb_sanitize_stdio();
343
344 setlinebuf(stdout);
345
346
347 write_pidfile(server_config.pidfile);
348
349
350 bb_info_msg("%s (v"BB_VER") started", applet_name);
351
352 option = udhcp_find_option(server_config.options, DHCP_LEASE_TIME);
353 server_config.max_lease_sec = DEFAULT_LEASE_TIME;
354 if (option) {
355 move_from_unaligned32(server_config.max_lease_sec, option->data + OPT_DATA);
356 server_config.max_lease_sec = ntohl(server_config.max_lease_sec);
357 }
358
359
360 num_ips = server_config.end_ip - server_config.start_ip + 1;
361 if (server_config.max_leases > num_ips) {
362 bb_error_msg("max_leases=%u is too big, setting to %u",
363 (unsigned)server_config.max_leases, num_ips);
364 server_config.max_leases = num_ips;
365 }
366
367 g_leases = xzalloc(server_config.max_leases * sizeof(g_leases[0]));
368 read_leases(server_config.lease_file);
369
370 if (udhcp_read_interface(server_config.interface,
371 &server_config.ifindex,
372 &server_config.server_nip,
373 server_config.server_mac)
374 ) {
375 retval = 1;
376 goto ret;
377 }
378
379
380 udhcp_sp_setup();
381
382 timeout_end = monotonic_sec() + server_config.auto_time;
383 while (1) {
384 fd_set rfds;
385 struct dhcp_packet packet;
386 int bytes;
387 struct timeval tv;
388 uint8_t *server_id_opt;
389 uint8_t *requested_ip_opt;
390 uint32_t requested_nip = requested_nip;
391 uint32_t static_lease_nip;
392 struct dyn_lease *lease, fake_lease;
393
394 if (server_socket < 0) {
395 server_socket = udhcp_listen_socket( SERVER_PORT,
396 server_config.interface);
397 }
398
399 max_sock = udhcp_sp_fd_set(&rfds, server_socket);
400 if (server_config.auto_time) {
401 tv.tv_sec = timeout_end - monotonic_sec();
402 tv.tv_usec = 0;
403 }
404 retval = 0;
405 if (!server_config.auto_time || tv.tv_sec > 0) {
406 retval = select(max_sock + 1, &rfds, NULL, NULL,
407 server_config.auto_time ? &tv : NULL);
408 }
409 if (retval == 0) {
410 write_leases();
411 timeout_end = monotonic_sec() + server_config.auto_time;
412 continue;
413 }
414 if (retval < 0 && errno != EINTR) {
415 log1("Error on select");
416 continue;
417 }
418
419 switch (udhcp_sp_read(&rfds)) {
420 case SIGUSR1:
421 bb_info_msg("Received SIGUSR1");
422 write_leases();
423
424 timeout_end = monotonic_sec() + server_config.auto_time;
425 continue;
426 case SIGTERM:
427 bb_info_msg("Received SIGTERM");
428 goto ret0;
429 case 0:
430 break;
431 default:
432 continue;
433 }
434
435 bytes = udhcp_recv_kernel_packet(&packet, server_socket);
436 if (bytes < 0) {
437
438 if (bytes == -1 && errno != EINTR) {
439 log1("Read error: %s, reopening socket", strerror(errno));
440 close(server_socket);
441 server_socket = -1;
442 }
443 continue;
444 }
445 if (packet.hlen != 6) {
446 bb_error_msg("MAC length != 6, ignoring packet");
447 continue;
448 }
449 if (packet.op != BOOTREQUEST) {
450 bb_error_msg("not a REQUEST, ignoring packet");
451 continue;
452 }
453 state = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
454 if (state == NULL || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) {
455 bb_error_msg("no or bad message type option, ignoring packet");
456 continue;
457 }
458
459
460 server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID);
461 if (server_id_opt) {
462 uint32_t server_id_network_order;
463 move_from_unaligned32(server_id_network_order, server_id_opt);
464 if (server_id_network_order != server_config.server_nip) {
465
466 log1("server ID doesn't match, ignoring");
467 continue;
468 }
469 }
470
471
472 static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr);
473 if (static_lease_nip) {
474 bb_info_msg("Found static lease: %x", static_lease_nip);
475 memcpy(&fake_lease.lease_mac, &packet.chaddr, 6);
476 fake_lease.lease_nip = static_lease_nip;
477 fake_lease.expires = 0;
478 lease = &fake_lease;
479 } else {
480 lease = find_lease_by_mac(packet.chaddr);
481 }
482
483
484 requested_ip_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP);
485 if (requested_ip_opt) {
486 move_from_unaligned32(requested_nip, requested_ip_opt);
487 }
488
489 switch (state[0]) {
490
491 case DHCPDISCOVER:
492 log1("Received DISCOVER");
493
494 send_offer(&packet, static_lease_nip, lease, requested_ip_opt);
495 break;
496
497 case DHCPREQUEST:
498 log1("Received REQUEST");
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585 if (!requested_ip_opt) {
586 requested_nip = packet.ciaddr;
587 if (requested_nip == 0) {
588 log1("no requested IP and no ciaddr, ignoring");
589 break;
590 }
591 }
592 if (lease && requested_nip == lease->lease_nip) {
593
594
595 send_ACK(&packet, lease->lease_nip);
596 break;
597 }
598
599
600 if (server_id_opt
601 || requested_ip_opt
602 ) {
603
604 send_NAK(&packet);
605 }
606
607 break;
608
609 case DHCPDECLINE:
610
611
612
613
614
615
616
617
618
619
620
621
622
623 log1("Received DECLINE");
624 if (server_id_opt
625 && requested_ip_opt
626 && lease
627 && requested_nip == lease->lease_nip
628 ) {
629 memset(lease->lease_mac, 0, sizeof(lease->lease_mac));
630 lease->expires = time(NULL) + server_config.decline_time;
631 }
632 break;
633
634 case DHCPRELEASE:
635
636
637
638
639
640
641
642
643 log1("Received RELEASE");
644 if (server_id_opt
645 && lease
646 && packet.ciaddr == lease->lease_nip
647 ) {
648 lease->expires = time(NULL);
649 }
650 break;
651
652 case DHCPINFORM:
653 log1("Received INFORM");
654 send_inform(&packet);
655 break;
656 }
657 }
658 ret0:
659 retval = 0;
660 ret:
661
662 remove_pidfile(server_config.pidfile);
663 return retval;
664}
665