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
  24//usage:#define udhcpd_trivial_usage
  25//usage:       "[-fS]" 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:        IF_FEATURE_UDHCP_PORT(
  31//usage:     "\n        -P N    Use port N (default 67)"
  32//usage:        )
  33
  34#include <syslog.h>
  35#include "common.h"
  36#include "dhcpc.h"
  37#include "dhcpd.h"
  38
  39
  40/* Send a packet to a specific mac address and ip address by creating our own ip packet */
  41static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadcast)
  42{
  43        const uint8_t *chaddr;
  44        uint32_t ciaddr;
  45
  46        // Was:
  47        //if (force_broadcast) { /* broadcast */ }
  48        //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ }
  49        //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ }
  50        //else { /* unicast to dhcp_pkt->yiaddr */ }
  51        // But this is wrong: yiaddr is _our_ idea what client's IP is
  52        // (for example, from lease file). Client may not know that,
  53        // and may not have UDP socket listening on that IP!
  54        // We should never unicast to dhcp_pkt->yiaddr!
  55        // dhcp_pkt->ciaddr, OTOH, comes from client's request packet,
  56        // and can be used.
  57
  58        if (force_broadcast
  59         || (dhcp_pkt->flags & htons(BROADCAST_FLAG))
  60         || dhcp_pkt->ciaddr == 0
  61        ) {
  62                log1("Broadcasting packet to client");
  63                ciaddr = INADDR_BROADCAST;
  64                chaddr = MAC_BCAST_ADDR;
  65        } else {
  66                log1("Unicasting packet to client ciaddr");
  67                ciaddr = dhcp_pkt->ciaddr;
  68                chaddr = dhcp_pkt->chaddr;
  69        }
  70
  71        udhcp_send_raw_packet(dhcp_pkt,
  72                /*src*/ server_config.server_nip, SERVER_PORT,
  73                /*dst*/ ciaddr, CLIENT_PORT, chaddr,
  74                server_config.ifindex);
  75}
  76
  77/* Send a packet to gateway_nip using the kernel ip stack */
  78static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
  79{
  80        log1("Forwarding packet to relay");
  81
  82        udhcp_send_kernel_packet(dhcp_pkt,
  83                        server_config.server_nip, SERVER_PORT,
  84                        dhcp_pkt->gateway_nip, SERVER_PORT);
  85}
  86
  87static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
  88{
  89        if (dhcp_pkt->gateway_nip)
  90                send_packet_to_relay(dhcp_pkt);
  91        else
  92                send_packet_to_client(dhcp_pkt, force_broadcast);
  93}
  94
  95static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type)
  96{
  97        /* Sets op, htype, hlen, cookie fields
  98         * and adds DHCP_MESSAGE_TYPE option */
  99        udhcp_init_header(packet, type);
 100
 101        packet->xid = oldpacket->xid;
 102        memcpy(packet->chaddr, oldpacket->chaddr, sizeof(oldpacket->chaddr));
 103        packet->flags = oldpacket->flags;
 104        packet->gateway_nip = oldpacket->gateway_nip;
 105        packet->ciaddr = oldpacket->ciaddr;
 106        udhcp_add_simple_option(packet, DHCP_SERVER_ID, server_config.server_nip);
 107}
 108
 109/* Fill options field, siaddr_nip, and sname and boot_file fields.
 110 * TODO: teach this code to use overload option.
 111 */
 112static void add_server_options(struct dhcp_packet *packet)
 113{
 114        struct option_set *curr = server_config.options;
 115
 116        while (curr) {
 117                if (curr->data[OPT_CODE] != DHCP_LEASE_TIME)
 118                        udhcp_add_binary_option(packet, curr->data);
 119                curr = curr->next;
 120        }
 121
 122        packet->siaddr_nip = server_config.siaddr_nip;
 123
 124        if (server_config.sname)
 125                strncpy((char*)packet->sname, server_config.sname, sizeof(packet->sname) - 1);
 126        if (server_config.boot_file)
 127                strncpy((char*)packet->file, server_config.boot_file, sizeof(packet->file) - 1);
 128}
 129
 130static uint32_t select_lease_time(struct dhcp_packet *packet)
 131{
 132        uint32_t lease_time_sec = server_config.max_lease_sec;
 133        uint8_t *lease_time_opt = udhcp_get_option(packet, DHCP_LEASE_TIME);
 134        if (lease_time_opt) {
 135                move_from_unaligned32(lease_time_sec, lease_time_opt);
 136                lease_time_sec = ntohl(lease_time_sec);
 137                if (lease_time_sec > server_config.max_lease_sec)
 138                        lease_time_sec = server_config.max_lease_sec;
 139                if (lease_time_sec < server_config.min_lease_sec)
 140                        lease_time_sec = server_config.min_lease_sec;
 141        }
 142        return lease_time_sec;
 143}
 144
 145/* We got a DHCP DISCOVER. Send an OFFER. */
 146/* NOINLINE: limit stack usage in caller */
 147static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
 148                uint32_t static_lease_nip,
 149                struct dyn_lease *lease,
 150                uint8_t *requested_ip_opt)
 151{
 152        struct dhcp_packet packet;
 153        uint32_t lease_time_sec;
 154        struct in_addr addr;
 155
 156        init_packet(&packet, oldpacket, DHCPOFFER);
 157
 158        /* If it is a static lease, use its IP */
 159        packet.yiaddr = static_lease_nip;
 160        /* Else: */
 161        if (!static_lease_nip) {
 162                /* We have no static lease for client's chaddr */
 163                uint32_t req_nip;
 164                const char *p_host_name;
 165
 166                if (lease) {
 167                        /* We have a dynamic lease for client's chaddr.
 168                         * Reuse its IP (even if lease is expired).
 169                         * Note that we ignore requested IP in this case.
 170                         */
 171                        packet.yiaddr = lease->lease_nip;
 172                }
 173                /* Or: if client has requested an IP */
 174                else if (requested_ip_opt != NULL
 175                 /* (read IP) */
 176                 && (move_from_unaligned32(req_nip, requested_ip_opt), 1)
 177                 /* and the IP is in the lease range */
 178                 && ntohl(req_nip) >= server_config.start_ip
 179                 && ntohl(req_nip) <= server_config.end_ip
 180                 /* and */
 181                 && (  !(lease = find_lease_by_nip(req_nip)) /* is not already taken */
 182                    || is_expired_lease(lease) /* or is taken, but expired */
 183                    )
 184                ) {
 185                        packet.yiaddr = req_nip;
 186                }
 187                else {
 188                        /* Otherwise, find a free IP */
 189                        packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr);
 190                }
 191
 192                if (!packet.yiaddr) {
 193                        bb_error_msg("no free IP addresses. OFFER abandoned");
 194                        return;
 195                }
 196                /* Reserve the IP for a short time hoping to get DHCPREQUEST soon */
 197                p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
 198                lease = add_lease(packet.chaddr, packet.yiaddr,
 199                                server_config.offer_time,
 200                                p_host_name,
 201                                p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
 202                );
 203                if (!lease) {
 204                        bb_error_msg("no free IP addresses. OFFER abandoned");
 205                        return;
 206                }
 207        }
 208
 209        lease_time_sec = select_lease_time(oldpacket);
 210        udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
 211        add_server_options(&packet);
 212
 213        addr.s_addr = packet.yiaddr;
 214        bb_info_msg("Sending OFFER of %s", inet_ntoa(addr));
 215        /* send_packet emits error message itself if it detects failure */
 216        send_packet(&packet, /*force_bcast:*/ 0);
 217}
 218
 219/* NOINLINE: limit stack usage in caller */
 220static NOINLINE void send_NAK(struct dhcp_packet *oldpacket)
 221{
 222        struct dhcp_packet packet;
 223
 224        init_packet(&packet, oldpacket, DHCPNAK);
 225
 226        log1("Sending NAK");
 227        send_packet(&packet, /*force_bcast:*/ 1);
 228}
 229
 230/* NOINLINE: limit stack usage in caller */
 231static NOINLINE void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr)
 232{
 233        struct dhcp_packet packet;
 234        uint32_t lease_time_sec;
 235        struct in_addr addr;
 236        const char *p_host_name;
 237
 238        init_packet(&packet, oldpacket, DHCPACK);
 239        packet.yiaddr = yiaddr;
 240
 241        lease_time_sec = select_lease_time(oldpacket);
 242        udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
 243
 244        add_server_options(&packet);
 245
 246        addr.s_addr = yiaddr;
 247        bb_info_msg("Sending ACK to %s", inet_ntoa(addr));
 248        send_packet(&packet, /*force_bcast:*/ 0);
 249
 250        p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
 251        add_lease(packet.chaddr, packet.yiaddr,
 252                lease_time_sec,
 253                p_host_name,
 254                p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
 255        );
 256        if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) {
 257                /* rewrite the file with leases at every new acceptance */
 258                write_leases();
 259        }
 260}
 261
 262/* NOINLINE: limit stack usage in caller */
 263static NOINLINE void send_inform(struct dhcp_packet *oldpacket)
 264{
 265        struct dhcp_packet packet;
 266
 267        /* "If a client has obtained a network address through some other means
 268         * (e.g., manual configuration), it may use a DHCPINFORM request message
 269         * to obtain other local configuration parameters.  Servers receiving a
 270         * DHCPINFORM message construct a DHCPACK message with any local
 271         * configuration parameters appropriate for the client without:
 272         * allocating a new address, checking for an existing binding, filling
 273         * in 'yiaddr' or including lease time parameters.  The servers SHOULD
 274         * unicast the DHCPACK reply to the address given in the 'ciaddr' field
 275         * of the DHCPINFORM message.
 276         * ...
 277         * The server responds to a DHCPINFORM message by sending a DHCPACK
 278         * message directly to the address given in the 'ciaddr' field
 279         * of the DHCPINFORM message.  The server MUST NOT send a lease
 280         * expiration time to the client and SHOULD NOT fill in 'yiaddr'."
 281         */
 282//TODO: do a few sanity checks: is ciaddr set?
 283//Better yet: is ciaddr == IP source addr?
 284        init_packet(&packet, oldpacket, DHCPACK);
 285        add_server_options(&packet);
 286
 287        send_packet(&packet, /*force_bcast:*/ 0);
 288}
 289
 290
 291/* globals */
 292struct dyn_lease *g_leases;
 293/* struct server_config_t server_config is in bb_common_bufsiz1 */
 294
 295
 296int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 297int udhcpd_main(int argc UNUSED_PARAM, char **argv)
 298{
 299        int server_socket = -1, retval, max_sock;
 300        uint8_t *state;
 301        unsigned timeout_end;
 302        unsigned num_ips;
 303        unsigned opt;
 304        struct option_set *option;
 305        IF_FEATURE_UDHCP_PORT(char *str_P;)
 306
 307#if ENABLE_FEATURE_UDHCP_PORT
 308        SERVER_PORT = 67;
 309        CLIENT_PORT = 68;
 310#endif
 311
 312#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
 313        opt_complementary = "vv";
 314#endif
 315        opt = getopt32(argv, "fSv"
 316                IF_FEATURE_UDHCP_PORT("P:", &str_P)
 317#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
 318                , &dhcp_verbose
 319#endif
 320                );
 321        if (!(opt & 1)) { /* no -f */
 322                bb_daemonize_or_rexec(0, argv);
 323                logmode = LOGMODE_NONE;
 324        }
 325        /* update argv after the possible vfork+exec in daemonize */
 326        argv += optind;
 327        if (opt & 2) { /* -S */
 328                openlog(applet_name, LOG_PID, LOG_DAEMON);
 329                logmode |= LOGMODE_SYSLOG;
 330        }
 331#if ENABLE_FEATURE_UDHCP_PORT
 332        if (opt & 8) { /* -P */
 333                SERVER_PORT = xatou16(str_P);
 334                CLIENT_PORT = SERVER_PORT + 1;
 335        }
 336#endif
 337        /* Would rather not do read_config before daemonization -
 338         * otherwise NOMMU machines will parse config twice */
 339        read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE);
 340
 341        /* Make sure fd 0,1,2 are open */
 342        bb_sanitize_stdio();
 343        /* Equivalent of doing a fflush after every \n */
 344        setlinebuf(stdout);
 345
 346        /* Create pidfile */
 347        write_pidfile(server_config.pidfile);
 348        /* if (!..) bb_perror_msg("can't create pidfile %s", pidfile); */
 349
 350        bb_info_msg("%s (v"BB_VER") started", applet_name);
 351
 352        option = udhcp_find_option(server_config.options, DHCP_LEASE_TIME);
 353        server_config.max_lease_sec = DEFAULT_LEASE_TIME;
 354        if (option) {
 355                move_from_unaligned32(server_config.max_lease_sec, option->data + OPT_DATA);
 356                server_config.max_lease_sec = ntohl(server_config.max_lease_sec);
 357        }
 358
 359        /* Sanity check */
 360        num_ips = server_config.end_ip - server_config.start_ip + 1;
 361        if (server_config.max_leases > num_ips) {
 362                bb_error_msg("max_leases=%u is too big, setting to %u",
 363                        (unsigned)server_config.max_leases, num_ips);
 364                server_config.max_leases = num_ips;
 365        }
 366
 367        g_leases = xzalloc(server_config.max_leases * sizeof(g_leases[0]));
 368        read_leases(server_config.lease_file);
 369
 370        if (udhcp_read_interface(server_config.interface,
 371                        &server_config.ifindex,
 372                        &server_config.server_nip,
 373                        server_config.server_mac)
 374        ) {
 375                retval = 1;
 376                goto ret;
 377        }
 378
 379        /* Setup the signal pipe */
 380        udhcp_sp_setup();
 381
 382        timeout_end = monotonic_sec() + server_config.auto_time;
 383        while (1) { /* loop until universe collapses */
 384                fd_set rfds;
 385                struct dhcp_packet packet;
 386                int bytes;
 387                struct timeval tv;
 388                uint8_t *server_id_opt;
 389                uint8_t *requested_ip_opt;
 390                uint32_t requested_nip = requested_nip; /* for compiler */
 391                uint32_t static_lease_nip;
 392                struct dyn_lease *lease, fake_lease;
 393
 394                if (server_socket < 0) {
 395                        server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT,
 396                                        server_config.interface);
 397                }
 398
 399                max_sock = udhcp_sp_fd_set(&rfds, server_socket);
 400                if (server_config.auto_time) {
 401                        tv.tv_sec = timeout_end - monotonic_sec();
 402                        tv.tv_usec = 0;
 403                }
 404                retval = 0;
 405                if (!server_config.auto_time || tv.tv_sec > 0) {
 406                        retval = select(max_sock + 1, &rfds, NULL, NULL,
 407                                        server_config.auto_time ? &tv : NULL);
 408                }
 409                if (retval == 0) {
 410                        write_leases();
 411                        timeout_end = monotonic_sec() + server_config.auto_time;
 412                        continue;
 413                }
 414                if (retval < 0 && errno != EINTR) {
 415                        log1("Error on select");
 416                        continue;
 417                }
 418
 419                switch (udhcp_sp_read(&rfds)) {
 420                case SIGUSR1:
 421                        bb_info_msg("Received SIGUSR1");
 422                        write_leases();
 423                        /* why not just reset the timeout, eh */
 424                        timeout_end = monotonic_sec() + server_config.auto_time;
 425                        continue;
 426                case SIGTERM:
 427                        bb_info_msg("Received SIGTERM");
 428                        goto ret0;
 429                case 0: /* no signal: read a packet */
 430                        break;
 431                default: /* signal or error (probably EINTR): back to select */
 432                        continue;
 433                }
 434
 435                bytes = udhcp_recv_kernel_packet(&packet, server_socket);
 436                if (bytes < 0) {
 437                        /* bytes can also be -2 ("bad packet data") */
 438                        if (bytes == -1 && errno != EINTR) {
 439                                log1("Read error: %s, reopening socket", strerror(errno));
 440                                close(server_socket);
 441                                server_socket = -1;
 442                        }
 443                        continue;
 444                }
 445                if (packet.hlen != 6) {
 446                        bb_error_msg("MAC length != 6, ignoring packet");
 447                        continue;
 448                }
 449                if (packet.op != BOOTREQUEST) {
 450                        bb_error_msg("not a REQUEST, ignoring packet");
 451                        continue;
 452                }
 453                state = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
 454                if (state == NULL || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) {
 455                        bb_error_msg("no or bad message type option, ignoring packet");
 456                        continue;
 457                }
 458
 459                /* Get SERVER_ID if present */
 460                server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID);
 461                if (server_id_opt) {
 462                        uint32_t server_id_network_order;
 463                        move_from_unaligned32(server_id_network_order, server_id_opt);
 464                        if (server_id_network_order != server_config.server_nip) {
 465                                /* client talks to somebody else */
 466                                log1("server ID doesn't match, ignoring");
 467                                continue;
 468                        }
 469                }
 470
 471                /* Look for a static/dynamic lease */
 472                static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr);
 473                if (static_lease_nip) {
 474                        bb_info_msg("Found static lease: %x", static_lease_nip);
 475                        memcpy(&fake_lease.lease_mac, &packet.chaddr, 6);
 476                        fake_lease.lease_nip = static_lease_nip;
 477                        fake_lease.expires = 0;
 478                        lease = &fake_lease;
 479                } else {
 480                        lease = find_lease_by_mac(packet.chaddr);
 481                }
 482
 483                /* Get REQUESTED_IP if present */
 484                requested_ip_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP);
 485                if (requested_ip_opt) {
 486                        move_from_unaligned32(requested_nip, requested_ip_opt);
 487                }
 488
 489                switch (state[0]) {
 490
 491                case DHCPDISCOVER:
 492                        log1("Received DISCOVER");
 493
 494                        send_offer(&packet, static_lease_nip, lease, requested_ip_opt);
 495                        break;
 496
 497                case DHCPREQUEST:
 498                        log1("Received REQUEST");
 499/* RFC 2131:
 500
 501o DHCPREQUEST generated during SELECTING state:
 502
 503   Client inserts the address of the selected server in 'server
 504   identifier', 'ciaddr' MUST be zero, 'requested IP address' MUST be
 505   filled in with the yiaddr value from the chosen DHCPOFFER.
 506
 507   Note that the client may choose to collect several DHCPOFFER
 508   messages and select the "best" offer.  The client indicates its
 509   selection by identifying the offering server in the DHCPREQUEST
 510   message.  If the client receives no acceptable offers, the client
 511   may choose to try another DHCPDISCOVER message.  Therefore, the
 512   servers may not receive a specific DHCPREQUEST from which they can
 513   decide whether or not the client has accepted the offer.
 514
 515o DHCPREQUEST generated during INIT-REBOOT state:
 516
 517   'server identifier' MUST NOT be filled in, 'requested IP address'
 518   option MUST be filled in with client's notion of its previously
 519   assigned address. 'ciaddr' MUST be zero. The client is seeking to
 520   verify a previously allocated, cached configuration. Server SHOULD
 521   send a DHCPNAK message to the client if the 'requested IP address'
 522   is incorrect, or is on the wrong network.
 523
 524   Determining whether a client in the INIT-REBOOT state is on the
 525   correct network is done by examining the contents of 'giaddr', the
 526   'requested IP address' option, and a database lookup. If the DHCP
 527   server detects that the client is on the wrong net (i.e., the
 528   result of applying the local subnet mask or remote subnet mask (if
 529   'giaddr' is not zero) to 'requested IP address' option value
 530   doesn't match reality), then the server SHOULD send a DHCPNAK
 531   message to the client.
 532
 533   If the network is correct, then the DHCP server should check if
 534   the client's notion of its IP address is correct. If not, then the
 535   server SHOULD send a DHCPNAK message to the client. If the DHCP
 536   server has no record of this client, then it MUST remain silent,
 537   and MAY output a warning to the network administrator. This
 538   behavior is necessary for peaceful coexistence of non-
 539   communicating DHCP servers on the same wire.
 540
 541   If 'giaddr' is 0x0 in the DHCPREQUEST message, the client is on
 542   the same subnet as the server.  The server MUST broadcast the
 543   DHCPNAK message to the 0xffffffff broadcast address because the
 544   client may not have a correct network address or subnet mask, and
 545   the client may not be answering ARP requests.
 546
 547   If 'giaddr' is set in the DHCPREQUEST message, the client is on a
 548   different subnet.  The server MUST set the broadcast bit in the
 549   DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
 550   client, because the client may not have a correct network address
 551   or subnet mask, and the client may not be answering ARP requests.
 552
 553o DHCPREQUEST generated during RENEWING state:
 554
 555   'server identifier' MUST NOT be filled in, 'requested IP address'
 556   option MUST NOT be filled in, 'ciaddr' MUST be filled in with
 557   client's IP address. In this situation, the client is completely
 558   configured, and is trying to extend its lease. This message will
 559   be unicast, so no relay agents will be involved in its
 560   transmission.  Because 'giaddr' is therefore not filled in, the
 561   DHCP server will trust the value in 'ciaddr', and use it when
 562   replying to the client.
 563
 564   A client MAY choose to renew or extend its lease prior to T1.  The
 565   server may choose not to extend the lease (as a policy decision by
 566   the network administrator), but should return a DHCPACK message
 567   regardless.
 568
 569o DHCPREQUEST generated during REBINDING state:
 570
 571   'server identifier' MUST NOT be filled in, 'requested IP address'
 572   option MUST NOT be filled in, 'ciaddr' MUST be filled in with
 573   client's IP address. In this situation, the client is completely
 574   configured, and is trying to extend its lease. This message MUST
 575   be broadcast to the 0xffffffff IP broadcast address.  The DHCP
 576   server SHOULD check 'ciaddr' for correctness before replying to
 577   the DHCPREQUEST.
 578
 579   The DHCPREQUEST from a REBINDING client is intended to accommodate
 580   sites that have multiple DHCP servers and a mechanism for
 581   maintaining consistency among leases managed by multiple servers.
 582   A DHCP server MAY extend a client's lease only if it has local
 583   administrative authority to do so.
 584*/
 585                        if (!requested_ip_opt) {
 586                                requested_nip = packet.ciaddr;
 587                                if (requested_nip == 0) {
 588                                        log1("no requested IP and no ciaddr, ignoring");
 589                                        break;
 590                                }
 591                        }
 592                        if (lease && requested_nip == lease->lease_nip) {
 593                                /* client requested or configured IP matches the lease.
 594                                 * ACK it, and bump lease expiration time. */
 595                                send_ACK(&packet, lease->lease_nip);
 596                                break;
 597                        }
 598                        /* No lease for this MAC, or lease IP != requested IP */
 599
 600                        if (server_id_opt    /* client is in SELECTING state */
 601                         || requested_ip_opt /* client is in INIT-REBOOT state */
 602                        ) {
 603                                /* "No, we don't have this IP for you" */
 604                                send_NAK(&packet);
 605                        } /* else: client is in RENEWING or REBINDING, do not answer */
 606
 607                        break;
 608
 609                case DHCPDECLINE:
 610                        /* RFC 2131:
 611                         * "If the server receives a DHCPDECLINE message,
 612                         * the client has discovered through some other means
 613                         * that the suggested network address is already
 614                         * in use. The server MUST mark the network address
 615                         * as not available and SHOULD notify the local
 616                         * sysadmin of a possible configuration problem."
 617                         *
 618                         * SERVER_ID must be present,
 619                         * REQUESTED_IP must be present,
 620                         * chaddr must be filled in,
 621                         * ciaddr must be 0 (we do not check this)
 622                         */
 623                        log1("Received DECLINE");
 624                        if (server_id_opt
 625                         && requested_ip_opt
 626                         && lease  /* chaddr matches this lease */
 627                         && requested_nip == lease->lease_nip
 628                        ) {
 629                                memset(lease->lease_mac, 0, sizeof(lease->lease_mac));
 630                                lease->expires = time(NULL) + server_config.decline_time;
 631                        }
 632                        break;
 633
 634                case DHCPRELEASE:
 635                        /* "Upon receipt of a DHCPRELEASE message, the server
 636                         * marks the network address as not allocated."
 637                         *
 638                         * SERVER_ID must be present,
 639                         * REQUESTED_IP must not be present (we do not check this),
 640                         * chaddr must be filled in,
 641                         * ciaddr must be filled in
 642                         */
 643                        log1("Received RELEASE");
 644                        if (server_id_opt
 645                         && lease  /* chaddr matches this lease */
 646                         && packet.ciaddr == lease->lease_nip
 647                        ) {
 648                                lease->expires = time(NULL);
 649                        }
 650                        break;
 651
 652                case DHCPINFORM:
 653                        log1("Received INFORM");
 654                        send_inform(&packet);
 655                        break;
 656                }
 657        }
 658 ret0:
 659        retval = 0;
 660 ret:
 661        /*if (server_config.pidfile) - server_config.pidfile is never NULL */
 662                remove_pidfile(server_config.pidfile);
 663        return retval;
 664}
 665