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