busybox/networking/udhcp/dhcpd.c
<<
>>
Prefs
   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#define g_leases ((struct dyn_lease*)ptr_to_globals)
  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 */
  54static 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 */
  73static 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
  84static 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 */
  98static 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 */
 120static 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 */
 142static 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 */
 158static 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 */
 201static 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 */
 207static 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 */
 219static 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 */
 231static 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 */
 252static 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 */
 323static 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
 332static 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
 338static 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
 364static int FAST_FUNC read_optset(const char *line, void *arg) {
 365        return udhcp_str2optset(line, arg,
 366                        dhcp_optflags, dhcp_option_strings,
 367                        /*dhcpv6:*/ 0
 368        );
 369}
 370
 371struct config_keyword {
 372        const char *keyword;
 373        int (*handler)(const char *line, void *var) FAST_FUNC;
 374        unsigned ofs;
 375        const char *def;
 376};
 377
 378#define OFS(field) offsetof(struct server_config_t, field)
 379
 380static const struct config_keyword keywords[] = {
 381        /* keyword        handler           variable address    default */
 382        {"start"        , udhcp_str2nip   , OFS(start_ip     ), "192.168.0.20"},
 383        {"end"          , udhcp_str2nip   , OFS(end_ip       ), "192.168.0.254"},
 384        {"interface"    , read_str        , OFS(interface    ), "eth0"},
 385        /* Avoid "max_leases value not sane" warning by setting default
 386         * to default_end_ip - default_start_ip + 1: */
 387        {"max_leases"   , read_u32        , OFS(max_leases   ), "235"},
 388        {"auto_time"    , read_u32        , OFS(auto_time    ), "7200"},
 389        {"decline_time" , read_u32        , OFS(decline_time ), "3600"},
 390        {"conflict_time", read_u32        , OFS(conflict_time), "3600"},
 391        {"offer_time"   , read_u32        , OFS(offer_time   ), "60"},
 392        {"min_lease"    , read_u32        , OFS(min_lease_sec), "60"},
 393        {"lease_file"   , read_str        , OFS(lease_file   ), LEASES_FILE},
 394        {"pidfile"      , read_str        , OFS(pidfile      ), "/var/run/udhcpd.pid"},
 395        {"siaddr"       , udhcp_str2nip   , OFS(siaddr_nip   ), "0.0.0.0"},
 396        /* keywords with no defaults must be last! */
 397        {"option"       , read_optset     , OFS(options      ), ""},
 398        {"opt"          , read_optset     , OFS(options      ), ""},
 399        {"notify_file"  , read_str        , OFS(notify_file  ), NULL},
 400        {"sname"        , read_str        , OFS(sname        ), NULL},
 401        {"boot_file"    , read_str        , OFS(boot_file    ), NULL},
 402        {"static_lease" , read_staticlease, OFS(static_leases), ""},
 403};
 404enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 };
 405
 406static NOINLINE void read_config(const char *file)
 407{
 408        parser_t *parser;
 409        const struct config_keyword *k;
 410        unsigned i;
 411        char *token[2];
 412
 413        for (i = 0; i < KWS_WITH_DEFAULTS; i++)
 414                keywords[i].handler(keywords[i].def, (char*)&server_config + keywords[i].ofs);
 415
 416        parser = config_open(file);
 417        while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
 418                for (k = keywords, i = 0; i < ARRAY_SIZE(keywords); k++, i++) {
 419                        if (strcasecmp(token[0], k->keyword) == 0) {
 420                                if (!k->handler(token[1], (char*)&server_config + k->ofs)) {
 421                                        bb_error_msg("can't parse line %u in %s",
 422                                                        parser->lineno, file);
 423                                        /* reset back to the default value */
 424                                        k->handler(k->def, (char*)&server_config + k->ofs);
 425                                }
 426                                break;
 427                        }
 428                }
 429        }
 430        config_close(parser);
 431
 432        server_config.start_ip = ntohl(server_config.start_ip);
 433        server_config.end_ip = ntohl(server_config.end_ip);
 434}
 435
 436static void write_leases(void)
 437{
 438        int fd;
 439        unsigned i;
 440        leasetime_t curr;
 441        int64_t written_at;
 442
 443        fd = open_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC);
 444        if (fd < 0)
 445                return;
 446
 447        curr = written_at = time(NULL);
 448
 449        written_at = SWAP_BE64(written_at);
 450        full_write(fd, &written_at, sizeof(written_at));
 451
 452        for (i = 0; i < server_config.max_leases; i++) {
 453                leasetime_t tmp_time;
 454
 455                if (g_leases[i].lease_nip == 0)
 456                        continue;
 457
 458                /* Screw with the time in the struct, for easier writing */
 459                tmp_time = g_leases[i].expires;
 460
 461                g_leases[i].expires -= curr;
 462                if ((signed_leasetime_t) g_leases[i].expires < 0)
 463                        g_leases[i].expires = 0;
 464                g_leases[i].expires = htonl(g_leases[i].expires);
 465
 466                /* No error check. If the file gets truncated,
 467                 * we lose some leases on restart. Oh well. */
 468                full_write(fd, &g_leases[i], sizeof(g_leases[i]));
 469
 470                /* Then restore it when done */
 471                g_leases[i].expires = tmp_time;
 472        }
 473        close(fd);
 474
 475        if (server_config.notify_file) {
 476                char *argv[3];
 477                argv[0] = server_config.notify_file;
 478                argv[1] = server_config.lease_file;
 479                argv[2] = NULL;
 480                spawn_and_wait(argv);
 481        }
 482}
 483
 484static NOINLINE void read_leases(const char *file)
 485{
 486        struct dyn_lease lease;
 487        int64_t written_at, time_passed;
 488        int fd;
 489#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
 490        unsigned i = 0;
 491#endif
 492
 493        fd = open_or_warn(file, O_RDONLY);
 494        if (fd < 0)
 495                return;
 496
 497        if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at))
 498                goto ret;
 499        written_at = SWAP_BE64(written_at);
 500
 501        time_passed = time(NULL) - written_at;
 502        /* Strange written_at, or lease file from old version of udhcpd
 503         * which had no "written_at" field? */
 504        if ((uint64_t)time_passed > 12 * 60 * 60)
 505                goto ret;
 506
 507        while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) {
 508                uint32_t y = ntohl(lease.lease_nip);
 509                if (y >= server_config.start_ip && y <= server_config.end_ip) {
 510                        signed_leasetime_t expires = ntohl(lease.expires) - (signed_leasetime_t)time_passed;
 511                        uint32_t static_nip;
 512
 513                        if (expires <= 0)
 514                                /* We keep expired leases: add_lease() will add
 515                                 * a lease with 0 seconds remaining.
 516                                 * Fewer IP address changes this way for mass reboot scenario.
 517                                 */
 518                                expires = 0;
 519
 520                        /* Check if there is a different static lease for this IP or MAC */
 521                        static_nip = get_static_nip_by_mac(server_config.static_leases, lease.lease_mac);
 522                        if (static_nip) {
 523                                /* NB: we do not add lease even if static_nip == lease.lease_nip.
 524                                 */
 525                                continue;
 526                        }
 527                        if (is_nip_reserved(server_config.static_leases, lease.lease_nip))
 528                                continue;
 529
 530                        /* NB: add_lease takes "relative time", IOW,
 531                         * lease duration, not lease deadline. */
 532                        if (add_lease(lease.lease_mac, lease.lease_nip,
 533                                        expires,
 534                                        lease.hostname, sizeof(lease.hostname)
 535                                ) == 0
 536                        ) {
 537                                bb_error_msg("too many leases while loading %s", file);
 538                                break;
 539                        }
 540#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
 541                        i++;
 542#endif
 543                }
 544        }
 545        log1("read %d leases", i);
 546 ret:
 547        close(fd);
 548}
 549
 550/* Send a packet to a specific mac address and ip address by creating our own ip packet */
 551static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadcast)
 552{
 553        const uint8_t *chaddr;
 554        uint32_t ciaddr;
 555
 556        // Was:
 557        //if (force_broadcast) { /* broadcast */ }
 558        //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ }
 559        //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ }
 560        //else { /* unicast to dhcp_pkt->yiaddr */ }
 561        // But this is wrong: yiaddr is _our_ idea what client's IP is
 562        // (for example, from lease file). Client may not know that,
 563        // and may not have UDP socket listening on that IP!
 564        // We should never unicast to dhcp_pkt->yiaddr!
 565        // dhcp_pkt->ciaddr, OTOH, comes from client's request packet,
 566        // and can be used.
 567
 568        if (force_broadcast
 569         || (dhcp_pkt->flags & htons(BROADCAST_FLAG))
 570         || dhcp_pkt->ciaddr == 0
 571        ) {
 572                log1("broadcasting packet to client");
 573                ciaddr = INADDR_BROADCAST;
 574                chaddr = MAC_BCAST_ADDR;
 575        } else {
 576                log1("unicasting packet to client ciaddr");
 577                ciaddr = dhcp_pkt->ciaddr;
 578                chaddr = dhcp_pkt->chaddr;
 579        }
 580
 581        udhcp_send_raw_packet(dhcp_pkt,
 582                /*src*/ server_config.server_nip, SERVER_PORT,
 583                /*dst*/ ciaddr, CLIENT_PORT, chaddr,
 584                server_config.ifindex);
 585}
 586
 587/* Send a packet to gateway_nip using the kernel ip stack */
 588static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
 589{
 590        log1("forwarding packet to relay");
 591
 592        udhcp_send_kernel_packet(dhcp_pkt,
 593                        server_config.server_nip, SERVER_PORT,
 594                        dhcp_pkt->gateway_nip, SERVER_PORT);
 595}
 596
 597static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
 598{
 599        if (dhcp_pkt->gateway_nip)
 600                send_packet_to_relay(dhcp_pkt);
 601        else
 602                send_packet_to_client(dhcp_pkt, force_broadcast);
 603}
 604
 605static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type)
 606{
 607        /* Sets op, htype, hlen, cookie fields
 608         * and adds DHCP_MESSAGE_TYPE option */
 609        udhcp_init_header(packet, type);
 610
 611        packet->xid = oldpacket->xid;
 612        memcpy(packet->chaddr, oldpacket->chaddr, sizeof(oldpacket->chaddr));
 613        packet->flags = oldpacket->flags;
 614        packet->gateway_nip = oldpacket->gateway_nip;
 615        packet->ciaddr = oldpacket->ciaddr;
 616        udhcp_add_simple_option(packet, DHCP_SERVER_ID, server_config.server_nip);
 617}
 618
 619/* Fill options field, siaddr_nip, and sname and boot_file fields.
 620 * TODO: teach this code to use overload option.
 621 */
 622static void add_server_options(struct dhcp_packet *packet)
 623{
 624        struct option_set *curr = server_config.options;
 625
 626        while (curr) {
 627                if (curr->data[OPT_CODE] != DHCP_LEASE_TIME)
 628                        udhcp_add_binary_option(packet, curr->data);
 629                curr = curr->next;
 630        }
 631
 632        packet->siaddr_nip = server_config.siaddr_nip;
 633
 634        if (server_config.sname)
 635                strncpy((char*)packet->sname, server_config.sname, sizeof(packet->sname) - 1);
 636        if (server_config.boot_file)
 637                strncpy((char*)packet->file, server_config.boot_file, sizeof(packet->file) - 1);
 638}
 639
 640static uint32_t select_lease_time(struct dhcp_packet *packet)
 641{
 642        uint32_t lease_time_sec = server_config.max_lease_sec;
 643        uint8_t *lease_time_opt = udhcp_get_option32(packet, DHCP_LEASE_TIME);
 644        if (lease_time_opt) {
 645                move_from_unaligned32(lease_time_sec, lease_time_opt);
 646                lease_time_sec = ntohl(lease_time_sec);
 647                if (lease_time_sec > server_config.max_lease_sec)
 648                        lease_time_sec = server_config.max_lease_sec;
 649                if (lease_time_sec < server_config.min_lease_sec)
 650                        lease_time_sec = server_config.min_lease_sec;
 651        }
 652        return lease_time_sec;
 653}
 654
 655/* We got a DHCP DISCOVER. Send an OFFER. */
 656/* NOINLINE: limit stack usage in caller */
 657static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
 658                uint32_t static_lease_nip,
 659                struct dyn_lease *lease,
 660                uint8_t *requested_ip_opt,
 661                unsigned arpping_ms)
 662{
 663        struct dhcp_packet packet;
 664        uint32_t lease_time_sec;
 665        struct in_addr addr;
 666
 667        init_packet(&packet, oldpacket, DHCPOFFER);
 668
 669        /* If it is a static lease, use its IP */
 670        packet.yiaddr = static_lease_nip;
 671        /* Else: */
 672        if (!static_lease_nip) {
 673                /* We have no static lease for client's chaddr */
 674                uint32_t req_nip;
 675                const char *p_host_name;
 676
 677                if (lease) {
 678                        /* We have a dynamic lease for client's chaddr.
 679                         * Reuse its IP (even if lease is expired).
 680                         * Note that we ignore requested IP in this case.
 681                         */
 682                        packet.yiaddr = lease->lease_nip;
 683                }
 684                /* Or: if client has requested an IP */
 685                else if (requested_ip_opt != NULL
 686                 /* (read IP) */
 687                 && (move_from_unaligned32(req_nip, requested_ip_opt), 1)
 688                 /* and the IP is in the lease range */
 689                 && ntohl(req_nip) >= server_config.start_ip
 690                 && ntohl(req_nip) <= server_config.end_ip
 691                 /* and */
 692                 && (  !(lease = find_lease_by_nip(req_nip)) /* is not already taken */
 693                    || is_expired_lease(lease) /* or is taken, but expired */
 694                    )
 695                ) {
 696                        packet.yiaddr = req_nip;
 697                }
 698                else {
 699                        /* Otherwise, find a free IP */
 700                        packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr, arpping_ms);
 701                }
 702
 703                if (!packet.yiaddr) {
 704                        bb_error_msg("no free IP addresses. OFFER abandoned");
 705                        return;
 706                }
 707                /* Reserve the IP for a short time hoping to get DHCPREQUEST soon */
 708                p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
 709                lease = add_lease(packet.chaddr, packet.yiaddr,
 710                                server_config.offer_time,
 711                                p_host_name,
 712                                p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
 713                );
 714                if (!lease) {
 715                        bb_error_msg("no free IP addresses. OFFER abandoned");
 716                        return;
 717                }
 718        }
 719
 720        lease_time_sec = select_lease_time(oldpacket);
 721        udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
 722        add_server_options(&packet);
 723
 724        addr.s_addr = packet.yiaddr;
 725        bb_error_msg("sending OFFER of %s", inet_ntoa(addr));
 726        /* send_packet emits error message itself if it detects failure */
 727        send_packet(&packet, /*force_bcast:*/ 0);
 728}
 729
 730/* NOINLINE: limit stack usage in caller */
 731static NOINLINE void send_NAK(struct dhcp_packet *oldpacket)
 732{
 733        struct dhcp_packet packet;
 734
 735        init_packet(&packet, oldpacket, DHCPNAK);
 736
 737        log1("sending %s", "NAK");
 738        send_packet(&packet, /*force_bcast:*/ 1);
 739}
 740
 741/* NOINLINE: limit stack usage in caller */
 742static NOINLINE void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr)
 743{
 744        struct dhcp_packet packet;
 745        uint32_t lease_time_sec;
 746        struct in_addr addr;
 747        const char *p_host_name;
 748
 749        init_packet(&packet, oldpacket, DHCPACK);
 750        packet.yiaddr = yiaddr;
 751
 752        lease_time_sec = select_lease_time(oldpacket);
 753        udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
 754
 755        add_server_options(&packet);
 756
 757        addr.s_addr = yiaddr;
 758        bb_error_msg("sending ACK to %s", inet_ntoa(addr));
 759        send_packet(&packet, /*force_bcast:*/ 0);
 760
 761        p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
 762        add_lease(packet.chaddr, packet.yiaddr,
 763                lease_time_sec,
 764                p_host_name,
 765                p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
 766        );
 767        if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) {
 768                /* rewrite the file with leases at every new acceptance */
 769                write_leases();
 770        }
 771}
 772
 773/* NOINLINE: limit stack usage in caller */
 774static NOINLINE void send_inform(struct dhcp_packet *oldpacket)
 775{
 776        struct dhcp_packet packet;
 777
 778        /* "If a client has obtained a network address through some other means
 779         * (e.g., manual configuration), it may use a DHCPINFORM request message
 780         * to obtain other local configuration parameters.  Servers receiving a
 781         * DHCPINFORM message construct a DHCPACK message with any local
 782         * configuration parameters appropriate for the client without:
 783         * allocating a new address, checking for an existing binding, filling
 784         * in 'yiaddr' or including lease time parameters.  The servers SHOULD
 785         * unicast the DHCPACK reply to the address given in the 'ciaddr' field
 786         * of the DHCPINFORM message.
 787         * ...
 788         * The server responds to a DHCPINFORM message by sending a DHCPACK
 789         * message directly to the address given in the 'ciaddr' field
 790         * of the DHCPINFORM message.  The server MUST NOT send a lease
 791         * expiration time to the client and SHOULD NOT fill in 'yiaddr'."
 792         */
 793//TODO: do a few sanity checks: is ciaddr set?
 794//Better yet: is ciaddr == IP source addr?
 795        init_packet(&packet, oldpacket, DHCPACK);
 796        add_server_options(&packet);
 797
 798        send_packet(&packet, /*force_bcast:*/ 0);
 799}
 800
 801int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 802int udhcpd_main(int argc UNUSED_PARAM, char **argv)
 803{
 804        int server_socket = -1, retval;
 805        uint8_t *state;
 806        unsigned timeout_end;
 807        unsigned num_ips;
 808        unsigned opt;
 809        struct option_set *option;
 810        char *str_I = str_I;
 811        const char *str_a = "2000";
 812        unsigned arpping_ms;
 813        IF_FEATURE_UDHCP_PORT(char *str_P;)
 814
 815        setup_common_bufsiz();
 816
 817        IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)
 818        IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)
 819
 820        opt = getopt32(argv, "^"
 821                "fSI:va:"IF_FEATURE_UDHCP_PORT("P:")
 822                "\0"
 823#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
 824                "vv"
 825#endif
 826                , &str_I
 827                , &str_a
 828                IF_FEATURE_UDHCP_PORT(, &str_P)
 829                IF_UDHCP_VERBOSE(, &dhcp_verbose)
 830                );
 831        if (!(opt & 1)) { /* no -f */
 832                bb_daemonize_or_rexec(0, argv);
 833                logmode = LOGMODE_NONE;
 834        }
 835        /* update argv after the possible vfork+exec in daemonize */
 836        argv += optind;
 837        if (opt & 2) { /* -S */
 838                openlog(applet_name, LOG_PID, LOG_DAEMON);
 839                logmode |= LOGMODE_SYSLOG;
 840        }
 841        if (opt & 4) { /* -I */
 842                len_and_sockaddr *lsa = xhost_and_af2sockaddr(str_I, 0, AF_INET);
 843                server_config.server_nip = lsa->u.sin.sin_addr.s_addr;
 844                free(lsa);
 845        }
 846#if ENABLE_FEATURE_UDHCP_PORT
 847        if (opt & 32) { /* -P */
 848                SERVER_PORT = xatou16(str_P);
 849                CLIENT_PORT = SERVER_PORT + 1;
 850        }
 851#endif
 852        arpping_ms = xatou(str_a);
 853
 854        /* Would rather not do read_config before daemonization -
 855         * otherwise NOMMU machines will parse config twice */
 856        read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE);
 857        /* prevent poll timeout overflow */
 858        if (server_config.auto_time > INT_MAX / 1000)
 859                server_config.auto_time = INT_MAX / 1000;
 860
 861        /* Make sure fd 0,1,2 are open */
 862        bb_sanitize_stdio();
 863
 864        /* Create pidfile */
 865        write_pidfile(server_config.pidfile);
 866        /* if (!..) bb_perror_msg("can't create pidfile %s", pidfile); */
 867
 868        bb_error_msg("started, v"BB_VER);
 869
 870        option = udhcp_find_option(server_config.options, DHCP_LEASE_TIME);
 871        server_config.max_lease_sec = DEFAULT_LEASE_TIME;
 872        if (option) {
 873                move_from_unaligned32(server_config.max_lease_sec, option->data + OPT_DATA);
 874                server_config.max_lease_sec = ntohl(server_config.max_lease_sec);
 875        }
 876
 877        /* Sanity check */
 878        num_ips = server_config.end_ip - server_config.start_ip + 1;
 879        if (server_config.max_leases > num_ips) {
 880                bb_error_msg("max_leases=%u is too big, setting to %u",
 881                        (unsigned)server_config.max_leases, num_ips);
 882                server_config.max_leases = num_ips;
 883        }
 884
 885        /* this sets g_leases */
 886        SET_PTR_TO_GLOBALS(xzalloc(server_config.max_leases * sizeof(g_leases[0])));
 887
 888        read_leases(server_config.lease_file);
 889
 890        if (udhcp_read_interface(server_config.interface,
 891                        &server_config.ifindex,
 892                        (server_config.server_nip == 0 ? &server_config.server_nip : NULL),
 893                        server_config.server_mac)
 894        ) {
 895                retval = 1;
 896                goto ret;
 897        }
 898
 899        /* Setup the signal pipe */
 900        udhcp_sp_setup();
 901
 902 continue_with_autotime:
 903        timeout_end = monotonic_sec() + server_config.auto_time;
 904        while (1) { /* loop until universe collapses */
 905                struct pollfd pfds[2];
 906                struct dhcp_packet packet;
 907                int bytes;
 908                int tv;
 909                uint8_t *server_id_opt;
 910                uint8_t *requested_ip_opt;
 911                uint32_t requested_nip = requested_nip; /* for compiler */
 912                uint32_t static_lease_nip;
 913                struct dyn_lease *lease, fake_lease;
 914
 915                if (server_socket < 0) {
 916                        server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT,
 917                                        server_config.interface);
 918                }
 919
 920                udhcp_sp_fd_set(pfds, server_socket);
 921
 922 new_tv:
 923                tv = -1;
 924                if (server_config.auto_time) {
 925                        tv = timeout_end - monotonic_sec();
 926                        if (tv <= 0) {
 927 write_leases:
 928                                write_leases();
 929                                goto continue_with_autotime;
 930                        }
 931                        tv *= 1000;
 932                }
 933
 934                /* Block here waiting for either signal or packet */
 935                retval = poll(pfds, 2, tv);
 936                if (retval <= 0) {
 937                        if (retval == 0)
 938                                goto write_leases;
 939                        if (errno == EINTR)
 940                                goto new_tv;
 941                        /* < 0 and not EINTR: should not happen */
 942                        bb_perror_msg_and_die("poll");
 943                }
 944
 945                if (pfds[0].revents) switch (udhcp_sp_read()) {
 946                case SIGUSR1:
 947                        bb_error_msg("received %s", "SIGUSR1");
 948                        write_leases();
 949                        /* why not just reset the timeout, eh */
 950                        goto continue_with_autotime;
 951                case SIGTERM:
 952                        bb_error_msg("received %s", "SIGTERM");
 953                        write_leases();
 954                        goto ret0;
 955                }
 956
 957                /* Is it a packet? */
 958                if (!pfds[1].revents)
 959                        continue; /* no */
 960
 961                /* Note: we do not block here, we block on poll() instead.
 962                 * Blocking here would prevent SIGTERM from working:
 963                 * socket read inside this call is restarted on caught signals.
 964                 */
 965                bytes = udhcp_recv_kernel_packet(&packet, server_socket);
 966                if (bytes < 0) {
 967                        /* bytes can also be -2 ("bad packet data") */
 968                        if (bytes == -1 && errno != EINTR) {
 969                                log1("read error: "STRERROR_FMT", reopening socket" STRERROR_ERRNO);
 970                                close(server_socket);
 971                                server_socket = -1;
 972                        }
 973                        continue;
 974                }
 975                if (packet.hlen != 6) {
 976                        bb_error_msg("MAC length != 6, ignoring packet");
 977                        continue;
 978                }
 979                if (packet.op != BOOTREQUEST) {
 980                        bb_error_msg("not a REQUEST, ignoring packet");
 981                        continue;
 982                }
 983                state = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
 984                if (state == NULL || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) {
 985                        bb_error_msg("no or bad message type option, ignoring packet");
 986                        continue;
 987                }
 988
 989                /* Get SERVER_ID if present */
 990                server_id_opt = udhcp_get_option32(&packet, DHCP_SERVER_ID);
 991                if (server_id_opt) {
 992                        uint32_t server_id_network_order;
 993                        move_from_unaligned32(server_id_network_order, server_id_opt);
 994                        if (server_id_network_order != server_config.server_nip) {
 995                                /* client talks to somebody else */
 996                                log1("server ID doesn't match, ignoring");
 997                                continue;
 998                        }
 999                }
1000
1001                /* Look for a static/dynamic lease */
1002                static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr);
1003                if (static_lease_nip) {
1004                        bb_error_msg("found static lease: %x", static_lease_nip);
1005                        memcpy(&fake_lease.lease_mac, &packet.chaddr, 6);
1006                        fake_lease.lease_nip = static_lease_nip;
1007                        fake_lease.expires = 0;
1008                        lease = &fake_lease;
1009                } else {
1010                        lease = find_lease_by_mac(packet.chaddr);
1011                }
1012
1013                /* Get REQUESTED_IP if present */
1014                requested_ip_opt = udhcp_get_option32(&packet, DHCP_REQUESTED_IP);
1015                if (requested_ip_opt) {
1016                        move_from_unaligned32(requested_nip, requested_ip_opt);
1017                }
1018
1019                switch (state[0]) {
1020
1021                case DHCPDISCOVER:
1022                        log1("received %s", "DISCOVER");
1023
1024                        send_offer(&packet, static_lease_nip, lease, requested_ip_opt, arpping_ms);
1025                        break;
1026
1027                case DHCPREQUEST:
1028                        log1("received %s", "REQUEST");
1029/* RFC 2131:
1030
1031o DHCPREQUEST generated during SELECTING state:
1032
1033   Client inserts the address of the selected server in 'server
1034   identifier', 'ciaddr' MUST be zero, 'requested IP address' MUST be
1035   filled in with the yiaddr value from the chosen DHCPOFFER.
1036
1037   Note that the client may choose to collect several DHCPOFFER
1038   messages and select the "best" offer.  The client indicates its
1039   selection by identifying the offering server in the DHCPREQUEST
1040   message.  If the client receives no acceptable offers, the client
1041   may choose to try another DHCPDISCOVER message.  Therefore, the
1042   servers may not receive a specific DHCPREQUEST from which they can
1043   decide whether or not the client has accepted the offer.
1044
1045o DHCPREQUEST generated during INIT-REBOOT state:
1046
1047   'server identifier' MUST NOT be filled in, 'requested IP address'
1048   option MUST be filled in with client's notion of its previously
1049   assigned address. 'ciaddr' MUST be zero. The client is seeking to
1050   verify a previously allocated, cached configuration. Server SHOULD
1051   send a DHCPNAK message to the client if the 'requested IP address'
1052   is incorrect, or is on the wrong network.
1053
1054   Determining whether a client in the INIT-REBOOT state is on the
1055   correct network is done by examining the contents of 'giaddr', the
1056   'requested IP address' option, and a database lookup. If the DHCP
1057   server detects that the client is on the wrong net (i.e., the
1058   result of applying the local subnet mask or remote subnet mask (if
1059   'giaddr' is not zero) to 'requested IP address' option value
1060   doesn't match reality), then the server SHOULD send a DHCPNAK
1061   message to the client.
1062
1063   If the network is correct, then the DHCP server should check if
1064   the client's notion of its IP address is correct. If not, then the
1065   server SHOULD send a DHCPNAK message to the client. If the DHCP
1066   server has no record of this client, then it MUST remain silent,
1067   and MAY output a warning to the network administrator. This
1068   behavior is necessary for peaceful coexistence of non-
1069   communicating DHCP servers on the same wire.
1070
1071   If 'giaddr' is 0x0 in the DHCPREQUEST message, the client is on
1072   the same subnet as the server.  The server MUST broadcast the
1073   DHCPNAK message to the 0xffffffff broadcast address because the
1074   client may not have a correct network address or subnet mask, and
1075   the client may not be answering ARP requests.
1076
1077   If 'giaddr' is set in the DHCPREQUEST message, the client is on a
1078   different subnet.  The server MUST set the broadcast bit in the
1079   DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
1080   client, because the client may not have a correct network address
1081   or subnet mask, and the client may not be answering ARP requests.
1082
1083o DHCPREQUEST generated during RENEWING state:
1084
1085   'server identifier' MUST NOT be filled in, 'requested IP address'
1086   option MUST NOT be filled in, 'ciaddr' MUST be filled in with
1087   client's IP address. In this situation, the client is completely
1088   configured, and is trying to extend its lease. This message will
1089   be unicast, so no relay agents will be involved in its
1090   transmission.  Because 'giaddr' is therefore not filled in, the
1091   DHCP server will trust the value in 'ciaddr', and use it when
1092   replying to the client.
1093
1094   A client MAY choose to renew or extend its lease prior to T1.  The
1095   server may choose not to extend the lease (as a policy decision by
1096   the network administrator), but should return a DHCPACK message
1097   regardless.
1098
1099o DHCPREQUEST generated during REBINDING state:
1100
1101   'server identifier' MUST NOT be filled in, 'requested IP address'
1102   option MUST NOT be filled in, 'ciaddr' MUST be filled in with
1103   client's IP address. In this situation, the client is completely
1104   configured, and is trying to extend its lease. This message MUST
1105   be broadcast to the 0xffffffff IP broadcast address.  The DHCP
1106   server SHOULD check 'ciaddr' for correctness before replying to
1107   the DHCPREQUEST.
1108
1109   The DHCPREQUEST from a REBINDING client is intended to accommodate
1110   sites that have multiple DHCP servers and a mechanism for
1111   maintaining consistency among leases managed by multiple servers.
1112   A DHCP server MAY extend a client's lease only if it has local
1113   administrative authority to do so.
1114*/
1115                        if (!requested_ip_opt) {
1116                                requested_nip = packet.ciaddr;
1117                                if (requested_nip == 0) {
1118                                        log1("no requested IP and no ciaddr, ignoring");
1119                                        break;
1120                                }
1121                        }
1122                        if (lease && requested_nip == lease->lease_nip) {
1123                                /* client requested or configured IP matches the lease.
1124                                 * ACK it, and bump lease expiration time. */
1125                                send_ACK(&packet, lease->lease_nip);
1126                                break;
1127                        }
1128                        /* No lease for this MAC, or lease IP != requested IP */
1129
1130                        if (server_id_opt    /* client is in SELECTING state */
1131                         || requested_ip_opt /* client is in INIT-REBOOT state */
1132                        ) {
1133                                /* "No, we don't have this IP for you" */
1134                                send_NAK(&packet);
1135                        } /* else: client is in RENEWING or REBINDING, do not answer */
1136
1137                        break;
1138
1139                case DHCPDECLINE:
1140                        /* RFC 2131:
1141                         * "If the server receives a DHCPDECLINE message,
1142                         * the client has discovered through some other means
1143                         * that the suggested network address is already
1144                         * in use. The server MUST mark the network address
1145                         * as not available and SHOULD notify the local
1146                         * sysadmin of a possible configuration problem."
1147                         *
1148                         * SERVER_ID must be present,
1149                         * REQUESTED_IP must be present,
1150                         * chaddr must be filled in,
1151                         * ciaddr must be 0 (we do not check this)
1152                         */
1153                        log1("received %s", "DECLINE");
1154                        if (server_id_opt
1155                         && requested_ip_opt
1156                         && lease  /* chaddr matches this lease */
1157                         && requested_nip == lease->lease_nip
1158                        ) {
1159                                memset(lease->lease_mac, 0, sizeof(lease->lease_mac));
1160                                lease->expires = time(NULL) + server_config.decline_time;
1161                        }
1162                        break;
1163
1164                case DHCPRELEASE:
1165                        /* "Upon receipt of a DHCPRELEASE message, the server
1166                         * marks the network address as not allocated."
1167                         *
1168                         * SERVER_ID must be present,
1169                         * REQUESTED_IP must not be present (we do not check this),
1170                         * chaddr must be filled in,
1171                         * ciaddr must be filled in
1172                         */
1173                        log1("received %s", "RELEASE");
1174                        if (server_id_opt
1175                         && lease  /* chaddr matches this lease */
1176                         && packet.ciaddr == lease->lease_nip
1177                        ) {
1178                                lease->expires = time(NULL);
1179                        }
1180                        break;
1181
1182                case DHCPINFORM:
1183                        log1("received %s", "INFORM");
1184                        send_inform(&packet);
1185                        break;
1186                }
1187        }
1188 ret0:
1189        retval = 0;
1190 ret:
1191        /*if (server_config.pidfile) - server_config.pidfile is never NULL */
1192                remove_pidfile(server_config.pidfile);
1193        return retval;
1194}
1195