ash: retain envvars with bad names in initial environment. Closes 10231
[oweals/busybox.git] / networking / udhcp / dhcpd.c
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]" IF_FEATURE_UDHCP_PORT(" [-P N]") " [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 N    Use port N (default 67)"
39 //usage:        )
40
41 #include <netinet/ether.h>
42 #include <syslog.h>
43 #include "common.h"
44 #include "dhcpc.h"
45 #include "dhcpd.h"
46
47 /* globals */
48 struct dyn_lease *g_leases;
49 /* struct server_config_t server_config is in bb_common_bufsiz1 */
50
51 /* Takes the address of the pointer to the static_leases linked list,
52  * address to a 6 byte mac address,
53  * 4 byte IP address */
54 static void add_static_lease(struct static_lease **st_lease_pp,
55                 uint8_t *mac,
56                 uint32_t nip)
57 {
58         struct static_lease *st_lease;
59
60         /* Find the tail of the list */
61         while ((st_lease = *st_lease_pp) != NULL) {
62                 st_lease_pp = &st_lease->next;
63         }
64
65         /* Add new node */
66         *st_lease_pp = st_lease = xzalloc(sizeof(*st_lease));
67         memcpy(st_lease->mac, mac, 6);
68         st_lease->nip = nip;
69         /*st_lease->next = NULL;*/
70 }
71
72 /* Find static lease IP by mac */
73 static uint32_t get_static_nip_by_mac(struct static_lease *st_lease, void *mac)
74 {
75         while (st_lease) {
76                 if (memcmp(st_lease->mac, mac, 6) == 0)
77                         return st_lease->nip;
78                 st_lease = st_lease->next;
79         }
80
81         return 0;
82 }
83
84 static int is_nip_reserved(struct static_lease *st_lease, uint32_t nip)
85 {
86         while (st_lease) {
87                 if (st_lease->nip == nip)
88                         return 1;
89                 st_lease = st_lease->next;
90         }
91
92         return 0;
93 }
94
95 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
96 /* Print out static leases just to check what's going on */
97 /* Takes the address of the pointer to the static_leases linked list */
98 static void log_static_leases(struct static_lease **st_lease_pp)
99 {
100         struct static_lease *cur;
101
102         if (dhcp_verbose < 2)
103                 return;
104
105         cur = *st_lease_pp;
106         while (cur) {
107                 bb_error_msg("static lease: mac:%02x:%02x:%02x:%02x:%02x:%02x nip:%x",
108                         cur->mac[0], cur->mac[1], cur->mac[2],
109                         cur->mac[3], cur->mac[4], cur->mac[5],
110                         cur->nip
111                 );
112                 cur = cur->next;
113         }
114 }
115 #else
116 # define log_static_leases(st_lease_pp) ((void)0)
117 #endif
118
119 /* Find the oldest expired lease, NULL if there are no expired leases */
120 static struct dyn_lease *oldest_expired_lease(void)
121 {
122         struct dyn_lease *oldest_lease = NULL;
123         leasetime_t oldest_time = time(NULL);
124         unsigned i;
125
126         /* Unexpired leases have g_leases[i].expires >= current time
127          * and therefore can't ever match */
128         for (i = 0; i < server_config.max_leases; i++) {
129                 if (g_leases[i].expires == 0 /* empty entry */
130                  || g_leases[i].expires < oldest_time
131                 ) {
132                         oldest_time = g_leases[i].expires;
133                         oldest_lease = &g_leases[i];
134                 }
135         }
136         return oldest_lease;
137 }
138
139 /* Clear out all leases with matching nonzero chaddr OR yiaddr.
140  * If chaddr == NULL, this is a conflict lease.
141  */
142 static void clear_leases(const uint8_t *chaddr, uint32_t yiaddr)
143 {
144         unsigned i;
145
146         for (i = 0; i < server_config.max_leases; i++) {
147                 if ((chaddr && memcmp(g_leases[i].lease_mac, chaddr, 6) == 0)
148                  || (yiaddr && g_leases[i].lease_nip == yiaddr)
149                 ) {
150                         memset(&g_leases[i], 0, sizeof(g_leases[i]));
151                 }
152         }
153 }
154
155 /* Add a lease into the table, clearing out any old ones.
156  * If chaddr == NULL, this is a conflict lease.
157  */
158 static struct dyn_lease *add_lease(
159                 const uint8_t *chaddr, uint32_t yiaddr,
160                 leasetime_t leasetime,
161                 const char *hostname, int hostname_len)
162 {
163         struct dyn_lease *oldest;
164
165         /* clean out any old ones */
166         clear_leases(chaddr, yiaddr);
167
168         oldest = oldest_expired_lease();
169
170         if (oldest) {
171                 memset(oldest, 0, sizeof(*oldest));
172                 if (hostname) {
173                         char *p;
174
175                         hostname_len++; /* include NUL */
176                         if (hostname_len > sizeof(oldest->hostname))
177                                 hostname_len = sizeof(oldest->hostname);
178                         p = safe_strncpy(oldest->hostname, hostname, hostname_len);
179                         /*
180                          * Sanitization (s/bad_char/./g).
181                          * The intent is not to allow only "DNS-valid" hostnames,
182                          * but merely make dumpleases output safe for shells to use.
183                          * We accept "0-9A-Za-z._-", all other chars turn to dots.
184                          */
185                         while (*p) {
186                                 if (!isalnum(*p) && *p != '-' && *p != '_')
187                                         *p = '.';
188                                 p++;
189                         }
190                 }
191                 if (chaddr)
192                         memcpy(oldest->lease_mac, chaddr, 6);
193                 oldest->lease_nip = yiaddr;
194                 oldest->expires = time(NULL) + leasetime;
195         }
196
197         return oldest;
198 }
199
200 /* True if a lease has expired */
201 static int is_expired_lease(struct dyn_lease *lease)
202 {
203         return (lease->expires < (leasetime_t) time(NULL));
204 }
205
206 /* Find the first lease that matches MAC, NULL if no match */
207 static struct dyn_lease *find_lease_by_mac(const uint8_t *mac)
208 {
209         unsigned i;
210
211         for (i = 0; i < server_config.max_leases; i++)
212                 if (memcmp(g_leases[i].lease_mac, mac, 6) == 0)
213                         return &g_leases[i];
214
215         return NULL;
216 }
217
218 /* Find the first lease that matches IP, NULL is no match */
219 static struct dyn_lease *find_lease_by_nip(uint32_t nip)
220 {
221         unsigned i;
222
223         for (i = 0; i < server_config.max_leases; i++)
224                 if (g_leases[i].lease_nip == nip)
225                         return &g_leases[i];
226
227         return NULL;
228 }
229
230 /* Check if the IP is taken; if it is, add it to the lease table */
231 static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac, unsigned arpping_ms)
232 {
233         struct in_addr temp;
234         int r;
235
236         r = arpping(nip, safe_mac,
237                         server_config.server_nip,
238                         server_config.server_mac,
239                         server_config.interface,
240                         arpping_ms);
241         if (r)
242                 return r;
243
244         temp.s_addr = nip;
245         bb_error_msg("%s belongs to someone, reserving it for %u seconds",
246                 inet_ntoa(temp), (unsigned)server_config.conflict_time);
247         add_lease(NULL, nip, server_config.conflict_time, NULL, 0);
248         return 0;
249 }
250
251 /* Find a new usable (we think) address */
252 static uint32_t find_free_or_expired_nip(const uint8_t *safe_mac, unsigned arpping_ms)
253 {
254         uint32_t addr;
255         struct dyn_lease *oldest_lease = NULL;
256
257 #if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC
258         uint32_t stop;
259         unsigned i, hash;
260
261         /* hash hwaddr: use the SDBM hashing algorithm.  Seems to give good
262          * dispersal even with similarly-valued "strings".
263          */
264         hash = 0;
265         for (i = 0; i < 6; i++)
266                 hash += safe_mac[i] + (hash << 6) + (hash << 16) - hash;
267
268         /* pick a seed based on hwaddr then iterate until we find a free address. */
269         addr = server_config.start_ip
270                 + (hash % (1 + server_config.end_ip - server_config.start_ip));
271         stop = addr;
272 #else
273         addr = server_config.start_ip;
274 #define stop (server_config.end_ip + 1)
275 #endif
276         do {
277                 uint32_t nip;
278                 struct dyn_lease *lease;
279
280                 /* ie, 192.168.55.0 */
281                 if ((addr & 0xff) == 0)
282                         goto next_addr;
283                 /* ie, 192.168.55.255 */
284                 if ((addr & 0xff) == 0xff)
285                         goto next_addr;
286                 nip = htonl(addr);
287                 /* skip our own address */
288                 if (nip == server_config.server_nip)
289                         goto next_addr;
290                 /* is this a static lease addr? */
291                 if (is_nip_reserved(server_config.static_leases, nip))
292                         goto next_addr;
293
294                 lease = find_lease_by_nip(nip);
295                 if (!lease) {
296 //TODO: DHCP servers do not always sit on the same subnet as clients: should *ping*, not arp-ping!
297                         if (nobody_responds_to_arp(nip, safe_mac, arpping_ms))
298                                 return nip;
299                 } else {
300                         if (!oldest_lease || lease->expires < oldest_lease->expires)
301                                 oldest_lease = lease;
302                 }
303
304  next_addr:
305                 addr++;
306 #if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC
307                 if (addr > server_config.end_ip)
308                         addr = server_config.start_ip;
309 #endif
310         } while (addr != stop);
311
312         if (oldest_lease
313          && is_expired_lease(oldest_lease)
314          && nobody_responds_to_arp(oldest_lease->lease_nip, safe_mac, arpping_ms)
315         ) {
316                 return oldest_lease->lease_nip;
317         }
318
319         return 0;
320 }
321
322 /* On these functions, make sure your datatype matches */
323 static int FAST_FUNC read_str(const char *line, void *arg)
324 {
325         char **dest = arg;
326
327         free(*dest);
328         *dest = xstrdup(line);
329         return 1;
330 }
331
332 static int FAST_FUNC read_u32(const char *line, void *arg)
333 {
334         *(uint32_t*)arg = bb_strtou32(line, NULL, 10);
335         return errno == 0;
336 }
337
338 static int FAST_FUNC read_staticlease(const char *const_line, void *arg)
339 {
340         char *line;
341         char *mac_string;
342         char *ip_string;
343         struct ether_addr mac_bytes; /* it's "struct { uint8_t mac[6]; }" */
344         uint32_t nip;
345
346         /* Read mac */
347         line = (char *) const_line;
348         mac_string = strtok_r(line, " \t", &line);
349         if (!mac_string || !ether_aton_r(mac_string, &mac_bytes))
350                 return 0;
351
352         /* Read ip */
353         ip_string = strtok_r(NULL, " \t", &line);
354         if (!ip_string || !udhcp_str2nip(ip_string, &nip))
355                 return 0;
356
357         add_static_lease(arg, (uint8_t*) &mac_bytes, nip);
358
359         log_static_leases(arg);
360
361         return 1;
362 }
363
364 static int FAST_FUNC read_optset(const char *line, void *arg) {
365         return udhcp_str2optset(line, arg, dhcp_optflags, dhcp_option_strings);
366 }
367
368 struct config_keyword {
369         const char *keyword;
370         int (*handler)(const char *line, void *var) FAST_FUNC;
371         unsigned ofs;
372         const char *def;
373 };
374
375 #define OFS(field) offsetof(struct server_config_t, field)
376
377 static const struct config_keyword keywords[] = {
378         /* keyword        handler           variable address               default */
379         {"start"        , udhcp_str2nip   , OFS(start_ip     ), "192.168.0.20"},
380         {"end"          , udhcp_str2nip   , OFS(end_ip       ), "192.168.0.254"},
381         {"interface"    , read_str        , OFS(interface    ), "eth0"},
382         /* Avoid "max_leases value not sane" warning by setting default
383          * to default_end_ip - default_start_ip + 1: */
384         {"max_leases"   , read_u32        , OFS(max_leases   ), "235"},
385         {"auto_time"    , read_u32        , OFS(auto_time    ), "7200"},
386         {"decline_time" , read_u32        , OFS(decline_time ), "3600"},
387         {"conflict_time", read_u32        , OFS(conflict_time), "3600"},
388         {"offer_time"   , read_u32        , OFS(offer_time   ), "60"},
389         {"min_lease"    , read_u32        , OFS(min_lease_sec), "60"},
390         {"lease_file"   , read_str        , OFS(lease_file   ), LEASES_FILE},
391         {"pidfile"      , read_str        , OFS(pidfile      ), "/var/run/udhcpd.pid"},
392         {"siaddr"       , udhcp_str2nip   , OFS(siaddr_nip   ), "0.0.0.0"},
393         /* keywords with no defaults must be last! */
394         {"option"       , read_optset     , OFS(options      ), ""},
395         {"opt"          , read_optset     , OFS(options      ), ""},
396         {"notify_file"  , read_str        , OFS(notify_file  ), NULL},
397         {"sname"        , read_str        , OFS(sname        ), NULL},
398         {"boot_file"    , read_str        , OFS(boot_file    ), NULL},
399         {"static_lease" , read_staticlease, OFS(static_leases), ""},
400 };
401 enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 };
402
403 static NOINLINE void read_config(const char *file)
404 {
405         parser_t *parser;
406         const struct config_keyword *k;
407         unsigned i;
408         char *token[2];
409
410         for (i = 0; i < KWS_WITH_DEFAULTS; i++)
411                 keywords[i].handler(keywords[i].def, (char*)&server_config + keywords[i].ofs);
412
413         parser = config_open(file);
414         while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
415                 for (k = keywords, i = 0; i < ARRAY_SIZE(keywords); k++, i++) {
416                         if (strcasecmp(token[0], k->keyword) == 0) {
417                                 if (!k->handler(token[1], (char*)&server_config + k->ofs)) {
418                                         bb_error_msg("can't parse line %u in %s",
419                                                         parser->lineno, file);
420                                         /* reset back to the default value */
421                                         k->handler(k->def, (char*)&server_config + k->ofs);
422                                 }
423                                 break;
424                         }
425                 }
426         }
427         config_close(parser);
428
429         server_config.start_ip = ntohl(server_config.start_ip);
430         server_config.end_ip = ntohl(server_config.end_ip);
431 }
432
433 static void write_leases(void)
434 {
435         int fd;
436         unsigned i;
437         leasetime_t curr;
438         int64_t written_at;
439
440         fd = open_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC);
441         if (fd < 0)
442                 return;
443
444         curr = written_at = time(NULL);
445
446         written_at = SWAP_BE64(written_at);
447         full_write(fd, &written_at, sizeof(written_at));
448
449         for (i = 0; i < server_config.max_leases; i++) {
450                 leasetime_t tmp_time;
451
452                 if (g_leases[i].lease_nip == 0)
453                         continue;
454
455                 /* Screw with the time in the struct, for easier writing */
456                 tmp_time = g_leases[i].expires;
457
458                 g_leases[i].expires -= curr;
459                 if ((signed_leasetime_t) g_leases[i].expires < 0)
460                         g_leases[i].expires = 0;
461                 g_leases[i].expires = htonl(g_leases[i].expires);
462
463                 /* No error check. If the file gets truncated,
464                  * we lose some leases on restart. Oh well. */
465                 full_write(fd, &g_leases[i], sizeof(g_leases[i]));
466
467                 /* Then restore it when done */
468                 g_leases[i].expires = tmp_time;
469         }
470         close(fd);
471
472         if (server_config.notify_file) {
473                 char *argv[3];
474                 argv[0] = server_config.notify_file;
475                 argv[1] = server_config.lease_file;
476                 argv[2] = NULL;
477                 spawn_and_wait(argv);
478         }
479 }
480
481 static NOINLINE void read_leases(const char *file)
482 {
483         struct dyn_lease lease;
484         int64_t written_at, time_passed;
485         int fd;
486 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
487         unsigned i = 0;
488 #endif
489
490         fd = open_or_warn(file, O_RDONLY);
491         if (fd < 0)
492                 return;
493
494         if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at))
495                 goto ret;
496         written_at = SWAP_BE64(written_at);
497
498         time_passed = time(NULL) - written_at;
499         /* Strange written_at, or lease file from old version of udhcpd
500          * which had no "written_at" field? */
501         if ((uint64_t)time_passed > 12 * 60 * 60)
502                 goto ret;
503
504         while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) {
505                 uint32_t y = ntohl(lease.lease_nip);
506                 if (y >= server_config.start_ip && y <= server_config.end_ip) {
507                         signed_leasetime_t expires = ntohl(lease.expires) - (signed_leasetime_t)time_passed;
508                         uint32_t static_nip;
509
510                         if (expires <= 0)
511                                 /* We keep expired leases: add_lease() will add
512                                  * a lease with 0 seconds remaining.
513                                  * Fewer IP address changes this way for mass reboot scenario.
514                                  */
515                                 expires = 0;
516
517                         /* Check if there is a different static lease for this IP or MAC */
518                         static_nip = get_static_nip_by_mac(server_config.static_leases, lease.lease_mac);
519                         if (static_nip) {
520                                 /* NB: we do not add lease even if static_nip == lease.lease_nip.
521                                  */
522                                 continue;
523                         }
524                         if (is_nip_reserved(server_config.static_leases, lease.lease_nip))
525                                 continue;
526
527                         /* NB: add_lease takes "relative time", IOW,
528                          * lease duration, not lease deadline. */
529                         if (add_lease(lease.lease_mac, lease.lease_nip,
530                                         expires,
531                                         lease.hostname, sizeof(lease.hostname)
532                                 ) == 0
533                         ) {
534                                 bb_error_msg("too many leases while loading %s", file);
535                                 break;
536                         }
537 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
538                         i++;
539 #endif
540                 }
541         }
542         log1("read %d leases", i);
543  ret:
544         close(fd);
545 }
546
547 /* Send a packet to a specific mac address and ip address by creating our own ip packet */
548 static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadcast)
549 {
550         const uint8_t *chaddr;
551         uint32_t ciaddr;
552
553         // Was:
554         //if (force_broadcast) { /* broadcast */ }
555         //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ }
556         //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ }
557         //else { /* unicast to dhcp_pkt->yiaddr */ }
558         // But this is wrong: yiaddr is _our_ idea what client's IP is
559         // (for example, from lease file). Client may not know that,
560         // and may not have UDP socket listening on that IP!
561         // We should never unicast to dhcp_pkt->yiaddr!
562         // dhcp_pkt->ciaddr, OTOH, comes from client's request packet,
563         // and can be used.
564
565         if (force_broadcast
566          || (dhcp_pkt->flags & htons(BROADCAST_FLAG))
567          || dhcp_pkt->ciaddr == 0
568         ) {
569                 log1("broadcasting packet to client");
570                 ciaddr = INADDR_BROADCAST;
571                 chaddr = MAC_BCAST_ADDR;
572         } else {
573                 log1("unicasting packet to client ciaddr");
574                 ciaddr = dhcp_pkt->ciaddr;
575                 chaddr = dhcp_pkt->chaddr;
576         }
577
578         udhcp_send_raw_packet(dhcp_pkt,
579                 /*src*/ server_config.server_nip, SERVER_PORT,
580                 /*dst*/ ciaddr, CLIENT_PORT, chaddr,
581                 server_config.ifindex);
582 }
583
584 /* Send a packet to gateway_nip using the kernel ip stack */
585 static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
586 {
587         log1("forwarding packet to relay");
588
589         udhcp_send_kernel_packet(dhcp_pkt,
590                         server_config.server_nip, SERVER_PORT,
591                         dhcp_pkt->gateway_nip, SERVER_PORT,
592                         /*send_flags:*/ 0
593         );
594 }
595
596 static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
597 {
598         if (dhcp_pkt->gateway_nip)
599                 send_packet_to_relay(dhcp_pkt);
600         else
601                 send_packet_to_client(dhcp_pkt, force_broadcast);
602 }
603
604 static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type)
605 {
606         /* Sets op, htype, hlen, cookie fields
607          * and adds DHCP_MESSAGE_TYPE option */
608         udhcp_init_header(packet, type);
609
610         packet->xid = oldpacket->xid;
611         memcpy(packet->chaddr, oldpacket->chaddr, sizeof(oldpacket->chaddr));
612         packet->flags = oldpacket->flags;
613         packet->gateway_nip = oldpacket->gateway_nip;
614         packet->ciaddr = oldpacket->ciaddr;
615         udhcp_add_simple_option(packet, DHCP_SERVER_ID, server_config.server_nip);
616 }
617
618 /* Fill options field, siaddr_nip, and sname and boot_file fields.
619  * TODO: teach this code to use overload option.
620  */
621 static void add_server_options(struct dhcp_packet *packet)
622 {
623         struct option_set *curr = server_config.options;
624
625         while (curr) {
626                 if (curr->data[OPT_CODE] != DHCP_LEASE_TIME)
627                         udhcp_add_binary_option(packet, curr->data);
628                 curr = curr->next;
629         }
630
631         packet->siaddr_nip = server_config.siaddr_nip;
632
633         if (server_config.sname)
634                 strncpy((char*)packet->sname, server_config.sname, sizeof(packet->sname) - 1);
635         if (server_config.boot_file)
636                 strncpy((char*)packet->file, server_config.boot_file, sizeof(packet->file) - 1);
637 }
638
639 static uint32_t select_lease_time(struct dhcp_packet *packet)
640 {
641         uint32_t lease_time_sec = server_config.max_lease_sec;
642         uint8_t *lease_time_opt = udhcp_get_option(packet, DHCP_LEASE_TIME);
643         if (lease_time_opt) {
644                 move_from_unaligned32(lease_time_sec, lease_time_opt);
645                 lease_time_sec = ntohl(lease_time_sec);
646                 if (lease_time_sec > server_config.max_lease_sec)
647                         lease_time_sec = server_config.max_lease_sec;
648                 if (lease_time_sec < server_config.min_lease_sec)
649                         lease_time_sec = server_config.min_lease_sec;
650         }
651         return lease_time_sec;
652 }
653
654 /* We got a DHCP DISCOVER. Send an OFFER. */
655 /* NOINLINE: limit stack usage in caller */
656 static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
657                 uint32_t static_lease_nip,
658                 struct dyn_lease *lease,
659                 uint8_t *requested_ip_opt,
660                 unsigned arpping_ms)
661 {
662         struct dhcp_packet packet;
663         uint32_t lease_time_sec;
664         struct in_addr addr;
665
666         init_packet(&packet, oldpacket, DHCPOFFER);
667
668         /* If it is a static lease, use its IP */
669         packet.yiaddr = static_lease_nip;
670         /* Else: */
671         if (!static_lease_nip) {
672                 /* We have no static lease for client's chaddr */
673                 uint32_t req_nip;
674                 const char *p_host_name;
675
676                 if (lease) {
677                         /* We have a dynamic lease for client's chaddr.
678                          * Reuse its IP (even if lease is expired).
679                          * Note that we ignore requested IP in this case.
680                          */
681                         packet.yiaddr = lease->lease_nip;
682                 }
683                 /* Or: if client has requested an IP */
684                 else if (requested_ip_opt != NULL
685                  /* (read IP) */
686                  && (move_from_unaligned32(req_nip, requested_ip_opt), 1)
687                  /* and the IP is in the lease range */
688                  && ntohl(req_nip) >= server_config.start_ip
689                  && ntohl(req_nip) <= server_config.end_ip
690                  /* and */
691                  && (  !(lease = find_lease_by_nip(req_nip)) /* is not already taken */
692                     || is_expired_lease(lease) /* or is taken, but expired */
693                     )
694                 ) {
695                         packet.yiaddr = req_nip;
696                 }
697                 else {
698                         /* Otherwise, find a free IP */
699                         packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr, arpping_ms);
700                 }
701
702                 if (!packet.yiaddr) {
703                         bb_error_msg("no free IP addresses. OFFER abandoned");
704                         return;
705                 }
706                 /* Reserve the IP for a short time hoping to get DHCPREQUEST soon */
707                 p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
708                 lease = add_lease(packet.chaddr, packet.yiaddr,
709                                 server_config.offer_time,
710                                 p_host_name,
711                                 p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
712                 );
713                 if (!lease) {
714                         bb_error_msg("no free IP addresses. OFFER abandoned");
715                         return;
716                 }
717         }
718
719         lease_time_sec = select_lease_time(oldpacket);
720         udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
721         add_server_options(&packet);
722
723         addr.s_addr = packet.yiaddr;
724         bb_error_msg("sending OFFER of %s", inet_ntoa(addr));
725         /* send_packet emits error message itself if it detects failure */
726         send_packet(&packet, /*force_bcast:*/ 0);
727 }
728
729 /* NOINLINE: limit stack usage in caller */
730 static NOINLINE void send_NAK(struct dhcp_packet *oldpacket)
731 {
732         struct dhcp_packet packet;
733
734         init_packet(&packet, oldpacket, DHCPNAK);
735
736         log1("sending %s", "NAK");
737         send_packet(&packet, /*force_bcast:*/ 1);
738 }
739
740 /* NOINLINE: limit stack usage in caller */
741 static NOINLINE void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr)
742 {
743         struct dhcp_packet packet;
744         uint32_t lease_time_sec;
745         struct in_addr addr;
746         const char *p_host_name;
747
748         init_packet(&packet, oldpacket, DHCPACK);
749         packet.yiaddr = yiaddr;
750
751         lease_time_sec = select_lease_time(oldpacket);
752         udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
753
754         add_server_options(&packet);
755
756         addr.s_addr = yiaddr;
757         bb_error_msg("sending ACK to %s", inet_ntoa(addr));
758         send_packet(&packet, /*force_bcast:*/ 0);
759
760         p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
761         add_lease(packet.chaddr, packet.yiaddr,
762                 lease_time_sec,
763                 p_host_name,
764                 p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
765         );
766         if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) {
767                 /* rewrite the file with leases at every new acceptance */
768                 write_leases();
769         }
770 }
771
772 /* NOINLINE: limit stack usage in caller */
773 static NOINLINE void send_inform(struct dhcp_packet *oldpacket)
774 {
775         struct dhcp_packet packet;
776
777         /* "If a client has obtained a network address through some other means
778          * (e.g., manual configuration), it may use a DHCPINFORM request message
779          * to obtain other local configuration parameters.  Servers receiving a
780          * DHCPINFORM message construct a DHCPACK message with any local
781          * configuration parameters appropriate for the client without:
782          * allocating a new address, checking for an existing binding, filling
783          * in 'yiaddr' or including lease time parameters.  The servers SHOULD
784          * unicast the DHCPACK reply to the address given in the 'ciaddr' field
785          * of the DHCPINFORM message.
786          * ...
787          * The server responds to a DHCPINFORM message by sending a DHCPACK
788          * message directly to the address given in the 'ciaddr' field
789          * of the DHCPINFORM message.  The server MUST NOT send a lease
790          * expiration time to the client and SHOULD NOT fill in 'yiaddr'."
791          */
792 //TODO: do a few sanity checks: is ciaddr set?
793 //Better yet: is ciaddr == IP source addr?
794         init_packet(&packet, oldpacket, DHCPACK);
795         add_server_options(&packet);
796
797         send_packet(&packet, /*force_bcast:*/ 0);
798 }
799
800 int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
801 int udhcpd_main(int argc UNUSED_PARAM, char **argv)
802 {
803         int server_socket = -1, retval;
804         uint8_t *state;
805         unsigned timeout_end;
806         unsigned num_ips;
807         unsigned opt;
808         struct option_set *option;
809         char *str_I = str_I;
810         const char *str_a = "2000";
811         unsigned arpping_ms;
812         IF_FEATURE_UDHCP_PORT(char *str_P;)
813
814         setup_common_bufsiz();
815
816         IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)
817         IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)
818
819         opt = getopt32(argv, "^"
820                 "fSI:va:"IF_FEATURE_UDHCP_PORT("P:")
821                 "\0"
822 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
823                 "vv"
824 #endif
825                 , &str_I
826                 , &str_a
827                 IF_FEATURE_UDHCP_PORT(, &str_P)
828                 IF_UDHCP_VERBOSE(, &dhcp_verbose)
829                 );
830         if (!(opt & 1)) { /* no -f */
831                 bb_daemonize_or_rexec(0, argv);
832                 logmode = LOGMODE_NONE;
833         }
834         /* update argv after the possible vfork+exec in daemonize */
835         argv += optind;
836         if (opt & 2) { /* -S */
837                 openlog(applet_name, LOG_PID, LOG_DAEMON);
838                 logmode |= LOGMODE_SYSLOG;
839         }
840         if (opt & 4) { /* -I */
841                 len_and_sockaddr *lsa = xhost_and_af2sockaddr(str_I, 0, AF_INET);
842                 server_config.server_nip = lsa->u.sin.sin_addr.s_addr;
843                 free(lsa);
844         }
845 #if ENABLE_FEATURE_UDHCP_PORT
846         if (opt & 32) { /* -P */
847                 SERVER_PORT = xatou16(str_P);
848                 CLIENT_PORT = SERVER_PORT + 1;
849         }
850 #endif
851         arpping_ms = xatou(str_a);
852
853         /* Would rather not do read_config before daemonization -
854          * otherwise NOMMU machines will parse config twice */
855         read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE);
856
857         /* Make sure fd 0,1,2 are open */
858         bb_sanitize_stdio();
859         /* Equivalent of doing a fflush after every \n */
860         setlinebuf(stdout);
861
862         /* Create pidfile */
863         write_pidfile(server_config.pidfile);
864         /* if (!..) bb_perror_msg("can't create pidfile %s", pidfile); */
865
866         bb_error_msg("started, v"BB_VER);
867
868         option = udhcp_find_option(server_config.options, DHCP_LEASE_TIME);
869         server_config.max_lease_sec = DEFAULT_LEASE_TIME;
870         if (option) {
871                 move_from_unaligned32(server_config.max_lease_sec, option->data + OPT_DATA);
872                 server_config.max_lease_sec = ntohl(server_config.max_lease_sec);
873         }
874
875         /* Sanity check */
876         num_ips = server_config.end_ip - server_config.start_ip + 1;
877         if (server_config.max_leases > num_ips) {
878                 bb_error_msg("max_leases=%u is too big, setting to %u",
879                         (unsigned)server_config.max_leases, num_ips);
880                 server_config.max_leases = num_ips;
881         }
882
883         g_leases = xzalloc(server_config.max_leases * sizeof(g_leases[0]));
884         read_leases(server_config.lease_file);
885
886         if (udhcp_read_interface(server_config.interface,
887                         &server_config.ifindex,
888                         (server_config.server_nip == 0 ? &server_config.server_nip : NULL),
889                         server_config.server_mac)
890         ) {
891                 retval = 1;
892                 goto ret;
893         }
894
895         /* Setup the signal pipe */
896         udhcp_sp_setup();
897
898  continue_with_autotime:
899         timeout_end = monotonic_sec() + server_config.auto_time;
900         while (1) { /* loop until universe collapses */
901                 struct pollfd pfds[2];
902                 struct dhcp_packet packet;
903                 int bytes;
904                 int tv;
905                 uint8_t *server_id_opt;
906                 uint8_t *requested_ip_opt;
907                 uint32_t requested_nip = requested_nip; /* for compiler */
908                 uint32_t static_lease_nip;
909                 struct dyn_lease *lease, fake_lease;
910
911                 if (server_socket < 0) {
912                         server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT,
913                                         server_config.interface);
914                 }
915
916                 udhcp_sp_fd_set(pfds, server_socket);
917                 tv = timeout_end - monotonic_sec();
918                 retval = 0;
919                 if (!server_config.auto_time || tv > 0) {
920                         retval = poll(pfds, 2, server_config.auto_time ? tv * 1000 : -1);
921                 }
922                 if (retval == 0) {
923                         write_leases();
924                         goto continue_with_autotime;
925                 }
926                 if (retval < 0 && errno != EINTR) {
927                         log1("error on select");
928                         continue;
929                 }
930
931                 switch (udhcp_sp_read(pfds)) {
932                 case SIGUSR1:
933                         bb_error_msg("received %s", "SIGUSR1");
934                         write_leases();
935                         /* why not just reset the timeout, eh */
936                         goto continue_with_autotime;
937                 case SIGTERM:
938                         bb_error_msg("received %s", "SIGTERM");
939                         write_leases();
940                         goto ret0;
941                 case 0: /* no signal: read a packet */
942                         break;
943                 default: /* signal or error (probably EINTR): back to select */
944                         continue;
945                 }
946
947                 bytes = udhcp_recv_kernel_packet(&packet, server_socket);
948                 if (bytes < 0) {
949                         /* bytes can also be -2 ("bad packet data") */
950                         if (bytes == -1 && errno != EINTR) {
951                                 log1("read error: "STRERROR_FMT", reopening socket" STRERROR_ERRNO);
952                                 close(server_socket);
953                                 server_socket = -1;
954                         }
955                         continue;
956                 }
957                 if (packet.hlen != 6) {
958                         bb_error_msg("MAC length != 6, ignoring packet");
959                         continue;
960                 }
961                 if (packet.op != BOOTREQUEST) {
962                         bb_error_msg("not a REQUEST, ignoring packet");
963                         continue;
964                 }
965                 state = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
966                 if (state == NULL || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) {
967                         bb_error_msg("no or bad message type option, ignoring packet");
968                         continue;
969                 }
970
971                 /* Get SERVER_ID if present */
972                 server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID);
973                 if (server_id_opt) {
974                         uint32_t server_id_network_order;
975                         move_from_unaligned32(server_id_network_order, server_id_opt);
976                         if (server_id_network_order != server_config.server_nip) {
977                                 /* client talks to somebody else */
978                                 log1("server ID doesn't match, ignoring");
979                                 continue;
980                         }
981                 }
982
983                 /* Look for a static/dynamic lease */
984                 static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr);
985                 if (static_lease_nip) {
986                         bb_error_msg("found static lease: %x", static_lease_nip);
987                         memcpy(&fake_lease.lease_mac, &packet.chaddr, 6);
988                         fake_lease.lease_nip = static_lease_nip;
989                         fake_lease.expires = 0;
990                         lease = &fake_lease;
991                 } else {
992                         lease = find_lease_by_mac(packet.chaddr);
993                 }
994
995                 /* Get REQUESTED_IP if present */
996                 requested_ip_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP);
997                 if (requested_ip_opt) {
998                         move_from_unaligned32(requested_nip, requested_ip_opt);
999                 }
1000
1001                 switch (state[0]) {
1002
1003                 case DHCPDISCOVER:
1004                         log1("received %s", "DISCOVER");
1005
1006                         send_offer(&packet, static_lease_nip, lease, requested_ip_opt, arpping_ms);
1007                         break;
1008
1009                 case DHCPREQUEST:
1010                         log1("received %s", "REQUEST");
1011 /* RFC 2131:
1012
1013 o DHCPREQUEST generated during SELECTING state:
1014
1015    Client inserts the address of the selected server in 'server
1016    identifier', 'ciaddr' MUST be zero, 'requested IP address' MUST be
1017    filled in with the yiaddr value from the chosen DHCPOFFER.
1018
1019    Note that the client may choose to collect several DHCPOFFER
1020    messages and select the "best" offer.  The client indicates its
1021    selection by identifying the offering server in the DHCPREQUEST
1022    message.  If the client receives no acceptable offers, the client
1023    may choose to try another DHCPDISCOVER message.  Therefore, the
1024    servers may not receive a specific DHCPREQUEST from which they can
1025    decide whether or not the client has accepted the offer.
1026
1027 o DHCPREQUEST generated during INIT-REBOOT state:
1028
1029    'server identifier' MUST NOT be filled in, 'requested IP address'
1030    option MUST be filled in with client's notion of its previously
1031    assigned address. 'ciaddr' MUST be zero. The client is seeking to
1032    verify a previously allocated, cached configuration. Server SHOULD
1033    send a DHCPNAK message to the client if the 'requested IP address'
1034    is incorrect, or is on the wrong network.
1035
1036    Determining whether a client in the INIT-REBOOT state is on the
1037    correct network is done by examining the contents of 'giaddr', the
1038    'requested IP address' option, and a database lookup. If the DHCP
1039    server detects that the client is on the wrong net (i.e., the
1040    result of applying the local subnet mask or remote subnet mask (if
1041    'giaddr' is not zero) to 'requested IP address' option value
1042    doesn't match reality), then the server SHOULD send a DHCPNAK
1043    message to the client.
1044
1045    If the network is correct, then the DHCP server should check if
1046    the client's notion of its IP address is correct. If not, then the
1047    server SHOULD send a DHCPNAK message to the client. If the DHCP
1048    server has no record of this client, then it MUST remain silent,
1049    and MAY output a warning to the network administrator. This
1050    behavior is necessary for peaceful coexistence of non-
1051    communicating DHCP servers on the same wire.
1052
1053    If 'giaddr' is 0x0 in the DHCPREQUEST message, the client is on
1054    the same subnet as the server.  The server MUST broadcast the
1055    DHCPNAK message to the 0xffffffff broadcast address because the
1056    client may not have a correct network address or subnet mask, and
1057    the client may not be answering ARP requests.
1058
1059    If 'giaddr' is set in the DHCPREQUEST message, the client is on a
1060    different subnet.  The server MUST set the broadcast bit in the
1061    DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
1062    client, because the client may not have a correct network address
1063    or subnet mask, and the client may not be answering ARP requests.
1064
1065 o DHCPREQUEST generated during RENEWING state:
1066
1067    'server identifier' MUST NOT be filled in, 'requested IP address'
1068    option MUST NOT be filled in, 'ciaddr' MUST be filled in with
1069    client's IP address. In this situation, the client is completely
1070    configured, and is trying to extend its lease. This message will
1071    be unicast, so no relay agents will be involved in its
1072    transmission.  Because 'giaddr' is therefore not filled in, the
1073    DHCP server will trust the value in 'ciaddr', and use it when
1074    replying to the client.
1075
1076    A client MAY choose to renew or extend its lease prior to T1.  The
1077    server may choose not to extend the lease (as a policy decision by
1078    the network administrator), but should return a DHCPACK message
1079    regardless.
1080
1081 o DHCPREQUEST generated during REBINDING state:
1082
1083    'server identifier' MUST NOT be filled in, 'requested IP address'
1084    option MUST NOT be filled in, 'ciaddr' MUST be filled in with
1085    client's IP address. In this situation, the client is completely
1086    configured, and is trying to extend its lease. This message MUST
1087    be broadcast to the 0xffffffff IP broadcast address.  The DHCP
1088    server SHOULD check 'ciaddr' for correctness before replying to
1089    the DHCPREQUEST.
1090
1091    The DHCPREQUEST from a REBINDING client is intended to accommodate
1092    sites that have multiple DHCP servers and a mechanism for
1093    maintaining consistency among leases managed by multiple servers.
1094    A DHCP server MAY extend a client's lease only if it has local
1095    administrative authority to do so.
1096 */
1097                         if (!requested_ip_opt) {
1098                                 requested_nip = packet.ciaddr;
1099                                 if (requested_nip == 0) {
1100                                         log1("no requested IP and no ciaddr, ignoring");
1101                                         break;
1102                                 }
1103                         }
1104                         if (lease && requested_nip == lease->lease_nip) {
1105                                 /* client requested or configured IP matches the lease.
1106                                  * ACK it, and bump lease expiration time. */
1107                                 send_ACK(&packet, lease->lease_nip);
1108                                 break;
1109                         }
1110                         /* No lease for this MAC, or lease IP != requested IP */
1111
1112                         if (server_id_opt    /* client is in SELECTING state */
1113                          || requested_ip_opt /* client is in INIT-REBOOT state */
1114                         ) {
1115                                 /* "No, we don't have this IP for you" */
1116                                 send_NAK(&packet);
1117                         } /* else: client is in RENEWING or REBINDING, do not answer */
1118
1119                         break;
1120
1121                 case DHCPDECLINE:
1122                         /* RFC 2131:
1123                          * "If the server receives a DHCPDECLINE message,
1124                          * the client has discovered through some other means
1125                          * that the suggested network address is already
1126                          * in use. The server MUST mark the network address
1127                          * as not available and SHOULD notify the local
1128                          * sysadmin of a possible configuration problem."
1129                          *
1130                          * SERVER_ID must be present,
1131                          * REQUESTED_IP must be present,
1132                          * chaddr must be filled in,
1133                          * ciaddr must be 0 (we do not check this)
1134                          */
1135                         log1("received %s", "DECLINE");
1136                         if (server_id_opt
1137                          && requested_ip_opt
1138                          && lease  /* chaddr matches this lease */
1139                          && requested_nip == lease->lease_nip
1140                         ) {
1141                                 memset(lease->lease_mac, 0, sizeof(lease->lease_mac));
1142                                 lease->expires = time(NULL) + server_config.decline_time;
1143                         }
1144                         break;
1145
1146                 case DHCPRELEASE:
1147                         /* "Upon receipt of a DHCPRELEASE message, the server
1148                          * marks the network address as not allocated."
1149                          *
1150                          * SERVER_ID must be present,
1151                          * REQUESTED_IP must not be present (we do not check this),
1152                          * chaddr must be filled in,
1153                          * ciaddr must be filled in
1154                          */
1155                         log1("received %s", "RELEASE");
1156                         if (server_id_opt
1157                          && lease  /* chaddr matches this lease */
1158                          && packet.ciaddr == lease->lease_nip
1159                         ) {
1160                                 lease->expires = time(NULL);
1161                         }
1162                         break;
1163
1164                 case DHCPINFORM:
1165                         log1("received %s", "INFORM");
1166                         send_inform(&packet);
1167                         break;
1168                 }
1169         }
1170  ret0:
1171         retval = 0;
1172  ret:
1173         /*if (server_config.pidfile) - server_config.pidfile is never NULL */
1174                 remove_pidfile(server_config.pidfile);
1175         return retval;
1176 }