1 /* vi: set sw=4 ts=4: */
2 /*
3 * udhcp server
4 * Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
5 * Chris Trew <ctrew@moreton.com.au>
6 *
7 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 //applet:IF_UDHCPD(APPLET(udhcpd, BB_DIR_USR_SBIN, BB_SUID_DROP))
24
25 //kbuild:lib-$(CONFIG_UDHCPD) += common.o packet.o signalpipe.o socket.o
26 //kbuild:lib-$(CONFIG_UDHCPD) += dhcpd.o arpping.o
27 //kbuild:lib-$(CONFIG_FEATURE_UDHCP_RFC3397) += domain_codec.o
28
29 //usage:#define udhcpd_trivial_usage
30 //usage: "[-fS] [-I ADDR] [-a MSEC]" IF_FEATURE_UDHCP_PORT(" [-P PORT]") " [CONFFILE]"
31 //usage:#define udhcpd_full_usage "\n\n"
32 //usage: "DHCP server\n"
33 //usage: "\n -f Run in foreground"
34 //usage: "\n -S Log to syslog too"
35 //usage: "\n -I ADDR Local address"
36 //usage: "\n -a MSEC Timeout for ARP ping (default 2000)"
37 //usage: IF_FEATURE_UDHCP_PORT(
38 //usage: "\n -P PORT Use PORT (default 67)"
39 //usage: )
40 //usage: "\nSignals:"
41 //usage: "\n USR1 Update lease file"
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 /* globals */
56 #define g_leases ((struct dyn_lease*)ptr_to_globals)
57 /* struct server_data_t server_data is in bb_common_bufsiz1 */
58
59 struct static_lease {
60 struct static_lease *next;
61 uint32_t nip;
62 uint8_t mac[6];
63 uint8_t opt[1];
64 };
65
66 /* Takes the address of the pointer to the static_leases linked list,
67 * address to a 6 byte mac address,
68 * 4 byte IP address */
add_static_lease(struct static_lease ** st_lease_pp,uint8_t * mac,uint32_t nip,const char * opts)69 static 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 /* Find the tail of the list */
80 while ((st_lease = *st_lease_pp) != NULL) {
81 st_lease_pp = &st_lease->next;
82 }
83
84 /* Add new node */
85 *st_lease_pp = st_lease = xzalloc(sizeof(*st_lease) + optlen);
86 memcpy(st_lease->mac, mac, 6);
87 st_lease->nip = nip;
88 /*st_lease->next = NULL;*/
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 /* Print out static leases just to check what's going on */
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 /* Find static lease IP by mac */
get_static_nip_by_mac(void * mac)109 static 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
is_nip_reserved_as_static(uint32_t nip)122 static 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 /* Find the oldest expired lease, NULL if there are no expired leases */
oldest_expired_lease(void)136 static 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 /* Unexpired leases have g_leases[i].expires >= current time
143 * and therefore can't ever match */
144 for (i = 0; i < server_data.max_leases; i++) {
145 if (g_leases[i].expires == 0 /* empty entry */
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 /* Clear out all leases with matching nonzero chaddr OR yiaddr.
156 * If chaddr == NULL, this is a conflict lease.
157 */
clear_leases(const uint8_t * chaddr,uint32_t yiaddr)158 static 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 /* Add a lease into the table, clearing out any old ones.
172 * If chaddr == NULL, this is a conflict lease.
173 */
add_lease(const uint8_t * chaddr,uint32_t yiaddr,leasetime_t leasetime,const char * hostname,int hostname_len)174 static 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 /* clean out any old ones */
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++; /* include NUL */
192 if (hostname_len > sizeof(oldest->hostname))
193 hostname_len = sizeof(oldest->hostname);
194 p = safe_strncpy(oldest->hostname, hostname, hostname_len);
195 /*
196 * Sanitization (s/bad_char/./g).
197 * The intent is not to allow only "DNS-valid" hostnames,
198 * but merely make dumpleases output safe for shells to use.
199 * We accept "0-9A-Za-z._-", all other chars turn to dots.
200 */
201 if (*p == '-')
202 *p = '.'; /* defeat "-option" attacks too */
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 /* True if a lease has expired */
is_expired_lease(struct dyn_lease * lease)219 static int is_expired_lease(struct dyn_lease *lease)
220 {
221 return (lease->expires < (leasetime_t) time(NULL));
222 }
223
224 /* Find the first lease that matches MAC, NULL if no match */
find_lease_by_mac(const uint8_t * mac)225 static 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 /* Find the first lease that matches IP, NULL is no match */
find_lease_by_nip(uint32_t nip)237 static 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 /* Check if the IP is taken; if it is, add it to the lease table */
nobody_responds_to_arp(uint32_t nip,const uint8_t * safe_mac,unsigned arpping_ms)249 static 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 /* Find a new usable (we think) address */
find_free_or_expired_nip(const uint8_t * safe_mac,unsigned arpping_ms)270 static 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 /* hash hwaddr: use the SDBM hashing algorithm. Seems to give good
280 * dispersal even with similarly-valued "strings".
281 */
282 hash = 0;
283 for (i = 0; i < 6; i++)
284 hash += safe_mac[i] + (hash << 6) + (hash << 16) - hash;
285
286 /* pick a seed based on hwaddr then iterate until we find a free address. */
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 /* (Addresses ending in .0 or .255 can legitimately be allocated
299 * in various situations, so _don't_ skip these. The user needs
300 * to choose start_ip and end_ip correctly for a particular
301 * network environment.) */
302
303 nip = htonl(addr);
304 /* skip our own address */
305 if (nip == server_data.server_nip)
306 goto next_addr;
307 /* is this a static lease addr? */
308 if (is_nip_reserved_as_static(nip))
309 goto next_addr;
310
311 lease = find_lease_by_nip(nip);
312 if (!lease) {
313 //TODO: DHCP servers do not always sit on the same subnet as clients: should *ping*, not arp-ping!
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 /* On these functions, make sure your datatype matches */
read_str(const char * line,void * arg)340 static 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
read_u32(const char * line,void * arg)349 static 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
read_staticlease(const char * const_line,void * arg)355 static 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; /* it's "struct { uint8_t mac[6]; }" */
362 uint32_t nip;
363
364 /* Read mac */
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 /* Read ip */
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 /* opts might be NULL, that's not an error */
377
378 add_static_lease(arg, (uint8_t*) &mac_bytes, nip, opts);
379
380 return 1;
381 }
382
read_optset(const char * line,void * arg)383 static int FAST_FUNC read_optset(const char *line, void *arg)
384 {
385 return udhcp_str2optset(line, arg,
386 dhcp_optflags, dhcp_option_strings,
387 /*dhcpv6:*/ 0
388 );
389 }
390
391 struct 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
400 static const struct config_keyword keywords[] ALIGN_PTR = {
401 /* keyword handler variable address default */
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 /* Avoid "max_leases value not sane" warning by setting default
406 * to default_end_ip - default_start_ip + 1: */
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 /* keywords with no defaults must be last! */
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 };
424 enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 };
425
read_config(const char * file)426 static 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 /* reset back to the default value */
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
write_leases(void)458 static 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 /* Screw with the time in the struct, for easier writing */
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 /* No error check. If the file gets truncated,
489 * we lose some leases on restart. Oh well. */
490 full_write(fd, &g_leases[i], sizeof(g_leases[i]));
491
492 /* Then restore it when done */
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
read_leases(const char * file)506 static 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 /* Strange written_at, or lease file from old version of udhcpd
525 * which had no "written_at" field? */
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 /* We keep expired leases: add_lease() will add
537 * a lease with 0 seconds remaining.
538 * Fewer IP address changes this way for mass reboot scenario.
539 */
540 expires = 0;
541
542 /* Check if there is a different static lease for this IP or MAC */
543 static_nip = get_static_nip_by_mac(lease.lease_mac);
544 if (static_nip) {
545 /* NB: we do not add lease even if static_nip == lease.lease_nip.
546 */
547 continue;
548 }
549 if (is_nip_reserved_as_static(lease.lease_nip))
550 continue;
551
552 /* NB: add_lease takes "relative time", IOW,
553 * lease duration, not lease deadline. */
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 /* Send a packet to a specific mac address and ip address by creating our own ip packet */
send_packet_to_client(struct dhcp_packet * dhcp_pkt,int force_broadcast)573 static 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 // Was:
579 //if (force_broadcast) { /* broadcast */ }
580 //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ }
581 //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ }
582 //else { /* unicast to dhcp_pkt->yiaddr */ }
583 // But this is wrong: yiaddr is _our_ idea what client's IP is
584 // (for example, from lease file). Client may not know that,
585 // and may not have UDP socket listening on that IP!
586 // We should never unicast to dhcp_pkt->yiaddr!
587 // dhcp_pkt->ciaddr, OTOH, comes from client's request packet,
588 // and can be used.
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 /*src*/ server_data.server_nip, SERVER_PORT,
605 /*dst*/ ciaddr, CLIENT_PORT, chaddr,
606 server_data.ifindex);
607 }
608
609 /* Send a packet to gateway_nip using the kernel ip stack */
send_packet_to_relay(struct dhcp_packet * dhcp_pkt)610 static 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 /* Yes, relay agents receive (and send) all their packets on SERVER_PORT,
618 * even those which are clients' requests and would normally
619 * (i.e. without relay) use CLIENT_PORT. See RFC 1542.
620 */
621 server_data.interface);
622 }
623
send_packet(struct dhcp_packet * dhcp_pkt,int force_broadcast)624 static 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
send_packet_verbose(struct dhcp_packet * dhcp_pkt,const char * fmt)632 static 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 /* send_packet emits error message itself if it detects failure */
638 send_packet(dhcp_pkt, /*force_bcast:*/ 0);
639 }
640
init_packet(struct dhcp_packet * packet,struct dhcp_packet * oldpacket,char type)641 static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type)
642 {
643 /* Sets op, htype, hlen, cookie fields
644 * and adds DHCP_MESSAGE_TYPE option */
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 /* Fill options field, siaddr_nip, and sname and boot_file fields.
656 * TODO: teach this code to use overload option.
657 */
add_server_options(struct dhcp_packet * packet)658 static 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) { /* if we aren't from send_inform()... */
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 * DHCP_LEASE_TIME is already filled, or in case of
681 * send_inform(), should not be filled at all.
682 */
683 if (config_opts->data[OPT_CODE] != DHCP_HOST_NAME
684 || !client_hostname_opt
685 ) {
686 /* Why "!client_hostname_opt":
687 * add hostname only if client has no hostname
688 * on its static lease line.
689 * (Not that "opt hostname HOST"
690 * makes much sense in udhcpd.conf,
691 * that'd give all clients the same hostname,
692 * but it's a valid configuration).
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
select_lease_time(struct dhcp_packet * packet)711 static 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 /* We got a DHCP DISCOVER. Send an OFFER. */
727 /* NOINLINE: limit stack usage in caller */
send_offer(struct dhcp_packet * oldpacket,uint32_t static_lease_nip,struct dyn_lease * lease,uint32_t requested_nip,unsigned arpping_ms)728 static 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 /* If it is a static lease, use its IP */
740 packet.yiaddr = static_lease_nip;
741 /* Else: */
742 if (!static_lease_nip) {
743 /* We have no static lease for client's chaddr */
744 const char *p_host_name;
745
746 if (lease) {
747 /* We have a dynamic lease for client's chaddr.
748 * Reuse its IP (even if lease is expired).
749 * Note that we ignore requested IP in this case.
750 */
751 packet.yiaddr = lease->lease_nip;
752 }
753 /* Or: if client has requested an IP */
754 else if (requested_nip != 0
755 /* and the IP is in the lease range */
756 && ntohl(requested_nip) >= server_data.start_ip
757 && ntohl(requested_nip) <= server_data.end_ip
758 /* and */
759 && ( !(lease = find_lease_by_nip(requested_nip)) /* is not already taken */
760 || is_expired_lease(lease) /* or is taken, but expired */
761 )
762 ) {
763 packet.yiaddr = requested_nip;
764 }
765 else {
766 /* Otherwise, find a free IP */
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 /* Reserve the IP for a short time hoping to get DHCPREQUEST soon */
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 /* send_packet emits error message itself if it detects failure */
792 send_packet_verbose(&packet, "sending OFFER to %s");
793 }
794
795 /* NOINLINE: limit stack usage in caller */
send_NAK(struct dhcp_packet * oldpacket)796 static 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, /*force_bcast:*/ 1);
804 }
805
806 /* NOINLINE: limit stack usage in caller */
send_ACK(struct dhcp_packet * oldpacket,uint32_t yiaddr)807 static 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 /* rewrite the file with leases at every new acceptance */
830 write_leases();
831 }
832 }
833
834 /* NOINLINE: limit stack usage in caller */
send_inform(struct dhcp_packet * oldpacket)835 static NOINLINE void send_inform(struct dhcp_packet *oldpacket)
836 {
837 struct dhcp_packet packet;
838
839 /* "If a client has obtained a network address through some other means
840 * (e.g., manual configuration), it may use a DHCPINFORM request message
841 * to obtain other local configuration parameters. Servers receiving a
842 * DHCPINFORM message construct a DHCPACK message with any local
843 * configuration parameters appropriate for the client without:
844 * allocating a new address, checking for an existing binding, filling
845 * in 'yiaddr' or including lease time parameters. The servers SHOULD
846 * unicast the DHCPACK reply to the address given in the 'ciaddr' field
847 * of the DHCPINFORM message.
848 * ...
849 * The server responds to a DHCPINFORM message by sending a DHCPACK
850 * message directly to the address given in the 'ciaddr' field
851 * of the DHCPINFORM message. The server MUST NOT send a lease
852 * expiration time to the client and SHOULD NOT fill in 'yiaddr'."
853 */
854 //TODO: do a few sanity checks: is ciaddr set?
855 //Better yet: is ciaddr == IP source addr?
856 init_packet(&packet, oldpacket, DHCPACK);
857 add_server_options(&packet);
858
859 send_packet(&packet, /*force_bcast:*/ 0);
860 // or maybe? send_packet_verbose(&packet, "sending ACK to %s");
861 }
862
863 int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
udhcpd_main(int argc UNUSED_PARAM,char ** argv)864 int 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 /* Make sure fd 0,1,2 are open */
882 /* Setup the signal pipe on fds 3,4 - must be before openlog() */
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)) { /* no -f */
903 bb_daemonize_or_rexec(0, argv);
904 logmode = LOGMODE_NONE;
905 }
906 /* update argv after the possible vfork+exec in daemonize */
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 /* Would rather not do read_config before daemonization -
926 * otherwise NOMMU machines will parse config twice */
927 read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE);
928 /* prevent poll timeout overflow */
929 if (server_data.auto_time > INT_MAX / 1000)
930 server_data.auto_time = INT_MAX / 1000;
931
932 /* Create pidfile */
933 write_pidfile(server_data.pidfile);
934 /* if (!..) bb_perror_msg("can't create pidfile %s", pidfile); */
935
936 bb_simple_info_msg("started, v"BB_VER);
937
938 option = udhcp_find_option(server_data.options, DHCP_LEASE_TIME, /*dhcpv6:*/ 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 /* Sanity check */
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 /* this sets g_leases */
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) { /* loop until universe collapses */
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(/*INADDR_ANY,*/ 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 /* Block here waiting for either signal or packet */
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 /* < 0 and not EINTR: should not happen */
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 /* why not just reset the timeout, eh */
1016 goto continue_with_autotime;
1017 case SIGTERM:
1018 bb_info_msg("received %s", "SIGTERM");
1019 write_leases();
1020 goto ret0;
1021 }
1022
1023 /* Is it a packet? */
1024 if (!pfds[1].revents)
1025 continue; /* no */
1026
1027 /* Note: we do not block here, we block on poll() instead.
1028 * Blocking here would prevent SIGTERM from working:
1029 * socket read inside this call is restarted on caught signals.
1030 */
1031 bytes = udhcp_recv_kernel_packet(&packet, server_socket);
1032 //NB: we do not check source port here. Should we?
1033 //It should be CLIENT_PORT for clients,
1034 //or SERVER_PORT for relay agents (in which case giaddr must be != 0.0.0.0)
1035 if (bytes < 0) {
1036 /* bytes can also be -2 ("bad packet data") */
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 /* Get SERVER_ID if present */
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 /* client talks to somebody else */
1065 log1("server ID doesn't match%s", ", ignoring packet");
1066 continue;
1067 }
1068 }
1069
1070 /* Look for a static/dynamic lease */
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 /* Get REQUESTED_IP if present */
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 /* RFC 2131:
1100
1101 o DHCPREQUEST generated during SELECTING state:
1102
1103 Client inserts the address of the selected server in 'server
1104 identifier', 'ciaddr' MUST be zero, 'requested IP address' MUST be
1105 filled in with the yiaddr value from the chosen DHCPOFFER.
1106
1107 Note that the client may choose to collect several DHCPOFFER
1108 messages and select the "best" offer. The client indicates its
1109 selection by identifying the offering server in the DHCPREQUEST
1110 message. If the client receives no acceptable offers, the client
1111 may choose to try another DHCPDISCOVER message. Therefore, the
1112 servers may not receive a specific DHCPREQUEST from which they can
1113 decide whether or not the client has accepted the offer.
1114
1115 o DHCPREQUEST generated during INIT-REBOOT state:
1116
1117 'server identifier' MUST NOT be filled in, 'requested IP address'
1118 option MUST be filled in with client's notion of its previously
1119 assigned address. 'ciaddr' MUST be zero. The client is seeking to
1120 verify a previously allocated, cached configuration. Server SHOULD
1121 send a DHCPNAK message to the client if the 'requested IP address'
1122 is incorrect, or is on the wrong network.
1123
1124 Determining whether a client in the INIT-REBOOT state is on the
1125 correct network is done by examining the contents of 'giaddr', the
1126 'requested IP address' option, and a database lookup. If the DHCP
1127 server detects that the client is on the wrong net (i.e., the
1128 result of applying the local subnet mask or remote subnet mask (if
1129 'giaddr' is not zero) to 'requested IP address' option value
1130 doesn't match reality), then the server SHOULD send a DHCPNAK
1131 message to the client.
1132
1133 If the network is correct, then the DHCP server should check if
1134 the client's notion of its IP address is correct. If not, then the
1135 server SHOULD send a DHCPNAK message to the client. If the DHCP
1136 server has no record of this client, then it MUST remain silent,
1137 and MAY output a warning to the network administrator. This
1138 behavior is necessary for peaceful coexistence of non-
1139 communicating DHCP servers on the same wire.
1140
1141 If 'giaddr' is 0x0 in the DHCPREQUEST message, the client is on
1142 the same subnet as the server. The server MUST broadcast the
1143 DHCPNAK message to the 0xffffffff broadcast address because the
1144 client may not have a correct network address or subnet mask, and
1145 the client may not be answering ARP requests.
1146
1147 If 'giaddr' is set in the DHCPREQUEST message, the client is on a
1148 different subnet. The server MUST set the broadcast bit in the
1149 DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
1150 client, because the client may not have a correct network address
1151 or subnet mask, and the client may not be answering ARP requests.
1152
1153 o DHCPREQUEST generated during RENEWING state:
1154
1155 'server identifier' MUST NOT be filled in, 'requested IP address'
1156 option MUST NOT be filled in, 'ciaddr' MUST be filled in with
1157 client's IP address. In this situation, the client is completely
1158 configured, and is trying to extend its lease. This message will
1159 be unicast, so no relay agents will be involved in its
1160 transmission. Because 'giaddr' is therefore not filled in, the
1161 DHCP server will trust the value in 'ciaddr', and use it when
1162 replying to the client.
1163
1164 A client MAY choose to renew or extend its lease prior to T1. The
1165 server may choose not to extend the lease (as a policy decision by
1166 the network administrator), but should return a DHCPACK message
1167 regardless.
1168
1169 o DHCPREQUEST generated during REBINDING state:
1170
1171 'server identifier' MUST NOT be filled in, 'requested IP address'
1172 option MUST NOT be filled in, 'ciaddr' MUST be filled in with
1173 client's IP address. In this situation, the client is completely
1174 configured, and is trying to extend its lease. This message MUST
1175 be broadcast to the 0xffffffff IP broadcast address. The DHCP
1176 server SHOULD check 'ciaddr' for correctness before replying to
1177 the DHCPREQUEST.
1178
1179 The DHCPREQUEST from a REBINDING client is intended to accommodate
1180 sites that have multiple DHCP servers and a mechanism for
1181 maintaining consistency among leases managed by multiple servers.
1182 A DHCP server MAY extend a client's lease only if it has local
1183 administrative authority to do so.
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 /* client requested or configured IP matches the lease.
1194 * ACK it, and bump lease expiration time. */
1195 send_ACK(&packet, lease->lease_nip);
1196 break;
1197 }
1198 /* No lease for this MAC, or lease IP != requested IP */
1199
1200 if (server_id_opt /* client is in SELECTING state */
1201 || requested_ip_opt /* client is in INIT-REBOOT state */
1202 ) {
1203 /* "No, we don't have this IP for you" */
1204 send_NAK(&packet);
1205 } /* else: client is in RENEWING or REBINDING, do not answer */
1206
1207 break;
1208
1209 case DHCPDECLINE:
1210 /* RFC 2131:
1211 * "If the server receives a DHCPDECLINE message,
1212 * the client has discovered through some other means
1213 * that the suggested network address is already
1214 * in use. The server MUST mark the network address
1215 * as not available and SHOULD notify the local
1216 * sysadmin of a possible configuration problem."
1217 *
1218 * SERVER_ID must be present,
1219 * REQUESTED_IP must be present,
1220 * chaddr must be filled in,
1221 * ciaddr must be 0 (we do not check this)
1222 */
1223 log1("received %s", "DECLINE");
1224 if (server_id_opt
1225 && requested_ip_opt
1226 && lease /* chaddr matches this 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 /* "Upon receipt of a DHCPRELEASE message, the server
1236 * marks the network address as not allocated."
1237 *
1238 * SERVER_ID must be present,
1239 * REQUESTED_IP must not be present (we do not check this),
1240 * chaddr must be filled in,
1241 * ciaddr must be filled in
1242 */
1243 log1("received %s", "RELEASE");
1244 if (server_id_opt
1245 && lease /* chaddr matches this 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 /*if (server_data.pidfile) - server_data.pidfile is never NULL */
1262 remove_pidfile(server_data.pidfile);
1263 return retval;
1264 }
1265