Annotation of embedaddon/dhcp/server/bootp.c, revision 1.1

1.1     ! misho       1: /* bootp.c
        !             2: 
        !             3:    BOOTP Protocol support. */
        !             4: 
        !             5: /*
        !             6:  * Copyright (c) 2004,2005,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
        !             7:  * Copyright (c) 1995-2003 by Internet Software Consortium
        !             8:  *
        !             9:  * Permission to use, copy, modify, and distribute this software for any
        !            10:  * purpose with or without fee is hereby granted, provided that the above
        !            11:  * copyright notice and this permission notice appear in all copies.
        !            12:  *
        !            13:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
        !            14:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            15:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
        !            16:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            17:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            18:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
        !            19:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            20:  *
        !            21:  *   Internet Systems Consortium, Inc.
        !            22:  *   950 Charter Street
        !            23:  *   Redwood City, CA 94063
        !            24:  *   <info@isc.org>
        !            25:  *   https://www.isc.org/
        !            26:  *
        !            27:  * This software has been written for Internet Systems Consortium
        !            28:  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
        !            29:  * To learn more about Internet Systems Consortium, see
        !            30:  * ``https://www.isc.org/''.  To learn more about Vixie Enterprises,
        !            31:  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
        !            32:  * ``http://www.nominum.com''.
        !            33:  */
        !            34: 
        !            35: #include "dhcpd.h"
        !            36: #include <errno.h>
        !            37: 
        !            38: #if defined (TRACING)
        !            39: # define send_packet trace_packet_send
        !            40: #endif
        !            41: 
        !            42: void bootp (packet)
        !            43:        struct packet *packet;
        !            44: {
        !            45:        int result;
        !            46:        struct host_decl *hp = (struct host_decl *)0;
        !            47:        struct host_decl *host = (struct host_decl *)0;
        !            48:        struct packet outgoing;
        !            49:        struct dhcp_packet raw;
        !            50:        struct sockaddr_in to;
        !            51:        struct in_addr from;
        !            52:        struct hardware hto;
        !            53:        struct option_state *options = (struct option_state *)0;
        !            54:        struct lease *lease = (struct lease *)0;
        !            55:        unsigned i;
        !            56:        struct data_string d1;
        !            57:        struct option_cache *oc;
        !            58:        char msgbuf [1024];
        !            59:        int ignorep;
        !            60:        int peer_has_leases = 0;
        !            61: 
        !            62:        if (packet -> raw -> op != BOOTREQUEST)
        !            63:                return;
        !            64: 
        !            65:        /* %Audit% This is log output. %2004.06.17,Safe%
        !            66:         * If we truncate we hope the user can get a hint from the log.
        !            67:         */
        !            68:        snprintf (msgbuf, sizeof msgbuf, "BOOTREQUEST from %s via %s",
        !            69:                 print_hw_addr (packet -> raw -> htype,
        !            70:                                packet -> raw -> hlen,
        !            71:                                packet -> raw -> chaddr),
        !            72:                 packet -> raw -> giaddr.s_addr
        !            73:                 ? inet_ntoa (packet -> raw -> giaddr)
        !            74:                 : packet -> interface -> name);
        !            75: 
        !            76:        if (!locate_network (packet)) {
        !            77:                log_info ("%s: network unknown", msgbuf);
        !            78:                return;
        !            79:        }
        !            80: 
        !            81:        find_lease (&lease, packet, packet -> shared_network,
        !            82:                    0, 0, (struct lease *)0, MDL);
        !            83: 
        !            84:        if (lease && lease->host)
        !            85:                host_reference(&hp, lease->host, MDL);
        !            86: 
        !            87:        if (!lease || ((lease->flags & STATIC_LEASE) == 0)) {
        !            88:                struct host_decl *h;
        !            89: 
        !            90:                /* We didn't find an applicable fixed-address host
        !            91:                   declaration.  Just in case we may be able to dynamically
        !            92:                   assign an address, see if there's a host declaration
        !            93:                   that doesn't have an ip address associated with it. */
        !            94: 
        !            95:                if (!hp)
        !            96:                        find_hosts_by_haddr(&hp, packet->raw->htype,
        !            97:                                            packet->raw->chaddr,
        !            98:                                            packet->raw->hlen, MDL);
        !            99: 
        !           100:                for (h = hp; h; h = h -> n_ipaddr) {
        !           101:                        if (!h -> fixed_addr) {
        !           102:                                host_reference(&host, h, MDL);
        !           103:                                break;
        !           104:                        }
        !           105:                }
        !           106: 
        !           107:                if (hp)
        !           108:                        host_dereference(&hp, MDL);
        !           109: 
        !           110:                if (host) {
        !           111:                        host_reference(&hp, host, MDL);
        !           112:                        host_dereference(&host, MDL);
        !           113:                }
        !           114: 
        !           115:                /* Allocate a lease if we have not yet found one. */
        !           116:                if (!lease)
        !           117:                        allocate_lease (&lease, packet,
        !           118:                                        packet -> shared_network -> pools,
        !           119:                                        &peer_has_leases);
        !           120: 
        !           121:                if (lease == NULL) {
        !           122:                        log_info("%s: BOOTP from dynamic client and no "
        !           123:                                 "dynamic leases", msgbuf);
        !           124:                        goto out;
        !           125:                }
        !           126: 
        !           127: #if defined(FAILOVER_PROTOCOL)
        !           128:                if ((lease->pool != NULL) &&
        !           129:                    (lease->pool->failover_peer != NULL)) {
        !           130:                        dhcp_failover_state_t *peer;
        !           131: 
        !           132:                        peer = lease->pool->failover_peer;
        !           133: 
        !           134:                        /* If we are in a failover state that bars us from
        !           135:                         * answering, do not do so.
        !           136:                         * If we are in a cooperative state, load balance
        !           137:                         * (all) responses.
        !           138:                         */
        !           139:                        if ((peer->service_state == not_responding) ||
        !           140:                            (peer->service_state == service_startup)) {
        !           141:                                log_info("%s: not responding%s",
        !           142:                                         msgbuf, peer->nrr);
        !           143:                                goto out;
        !           144:                        } else if((peer->service_state == cooperating) &&
        !           145:                                  !load_balance_mine(packet, peer)) {
        !           146:                                log_info("%s: load balance to peer %s",
        !           147:                                         msgbuf, peer->name);
        !           148:                                goto out;
        !           149:                        }
        !           150:                }
        !           151: #endif
        !           152: 
        !           153:                ack_lease (packet, lease, 0, 0, msgbuf, 0, hp);
        !           154:                goto out;
        !           155:        }
        !           156: 
        !           157:        /* Run the executable statements to compute the client and server
        !           158:           options. */
        !           159:        option_state_allocate (&options, MDL);
        !           160: 
        !           161:        /* Execute the subnet statements. */
        !           162:        execute_statements_in_scope ((struct binding_value **)0,
        !           163:                                     packet, lease, (struct client_state *)0,
        !           164:                                     packet -> options, options,
        !           165:                                     &lease -> scope, lease -> subnet -> group,
        !           166:                                     (struct group *)0);
        !           167: 
        !           168:        /* Execute statements from class scopes. */
        !           169:        for (i = packet -> class_count; i > 0; i--) {
        !           170:                execute_statements_in_scope
        !           171:                        ((struct binding_value **)0,
        !           172:                         packet, lease, (struct client_state *)0,
        !           173:                         packet -> options, options,
        !           174:                         &lease -> scope, packet -> classes [i - 1] -> group,
        !           175:                         lease -> subnet -> group);
        !           176:        }
        !           177: 
        !           178:        /* Execute the host statements. */
        !           179:        execute_statements_in_scope ((struct binding_value **)0,
        !           180:                                     packet, lease, (struct client_state *)0,
        !           181:                                     packet -> options, options,
        !           182:                                     &lease -> scope,
        !           183:                                     hp -> group, lease -> subnet -> group);
        !           184:        
        !           185:        /* Drop the request if it's not allowed for this client. */
        !           186:        if ((oc = lookup_option (&server_universe, options, SV_ALLOW_BOOTP)) &&
        !           187:            !evaluate_boolean_option_cache (&ignorep, packet, lease,
        !           188:                                            (struct client_state *)0,
        !           189:                                            packet -> options, options,
        !           190:                                            &lease -> scope, oc, MDL)) {
        !           191:                if (!ignorep)
        !           192:                        log_info ("%s: bootp disallowed", msgbuf);
        !           193:                goto out;
        !           194:        } 
        !           195: 
        !           196:        if ((oc = lookup_option (&server_universe,
        !           197:                                 options, SV_ALLOW_BOOTING)) &&
        !           198:            !evaluate_boolean_option_cache (&ignorep, packet, lease,
        !           199:                                            (struct client_state *)0,
        !           200:                                            packet -> options, options,
        !           201:                                            &lease -> scope, oc, MDL)) {
        !           202:                if (!ignorep)
        !           203:                        log_info ("%s: booting disallowed", msgbuf);
        !           204:                goto out;
        !           205:        }
        !           206: 
        !           207:        /* Set up the outgoing packet... */
        !           208:        memset (&outgoing, 0, sizeof outgoing);
        !           209:        memset (&raw, 0, sizeof raw);
        !           210:        outgoing.raw = &raw;
        !           211: 
        !           212:        /* If we didn't get a known vendor magic number on the way in,
        !           213:           just copy the input options to the output. */
        !           214:        if (!packet -> options_valid &&
        !           215:            !(evaluate_boolean_option_cache
        !           216:              (&ignorep, packet, lease, (struct client_state *)0,
        !           217:               packet -> options, options, &lease -> scope,
        !           218:               lookup_option (&server_universe, options,
        !           219:                              SV_ALWAYS_REPLY_RFC1048), MDL))) {
        !           220:                memcpy (outgoing.raw -> options,
        !           221:                        packet -> raw -> options, DHCP_MAX_OPTION_LEN);
        !           222:                outgoing.packet_length = BOOTP_MIN_LEN;
        !           223:        } else {
        !           224: 
        !           225:                /* Use the subnet mask from the subnet declaration if no other
        !           226:                   mask has been provided. */
        !           227: 
        !           228:                oc = (struct option_cache *)0;
        !           229:                i = DHO_SUBNET_MASK;
        !           230:                if (!lookup_option (&dhcp_universe, options, i)) {
        !           231:                        if (option_cache_allocate (&oc, MDL)) {
        !           232:                                if (make_const_data
        !           233:                                    (&oc -> expression,
        !           234:                                     lease -> subnet -> netmask.iabuf,
        !           235:                                     lease -> subnet -> netmask.len,
        !           236:                                     0, 0, MDL)) {
        !           237:                                        option_code_hash_lookup(&oc->option,
        !           238:                                                        dhcp_universe.code_hash,
        !           239:                                                                &i, 0, MDL);
        !           240:                                        save_option (&dhcp_universe,
        !           241:                                                     options, oc);
        !           242:                                }
        !           243:                                option_cache_dereference (&oc, MDL);
        !           244:                        }
        !           245:                }
        !           246: 
        !           247:                /* Pack the options into the buffer.  Unlike DHCP, we
        !           248:                   can't pack options into the filename and server
        !           249:                   name buffers. */
        !           250: 
        !           251:                outgoing.packet_length =
        !           252:                        cons_options (packet, outgoing.raw, lease,
        !           253:                                      (struct client_state *)0, 0,
        !           254:                                      packet -> options, options,
        !           255:                                      &lease -> scope,
        !           256:                                      0, 0, 1, (struct data_string *)0,
        !           257:                                      (const char *)0);
        !           258:                if (outgoing.packet_length < BOOTP_MIN_LEN)
        !           259:                        outgoing.packet_length = BOOTP_MIN_LEN;
        !           260:        }
        !           261: 
        !           262:        /* Take the fields that we care about... */
        !           263:        raw.op = BOOTREPLY;
        !           264:        raw.htype = packet -> raw -> htype;
        !           265:        raw.hlen = packet -> raw -> hlen;
        !           266:        memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
        !           267:        raw.hops = packet -> raw -> hops;
        !           268:        raw.xid = packet -> raw -> xid;
        !           269:        raw.secs = packet -> raw -> secs;
        !           270:        raw.flags = packet -> raw -> flags;
        !           271:        raw.ciaddr = packet -> raw -> ciaddr;
        !           272: 
        !           273:        /* yiaddr is an ipv4 address, it must be 4 octets. */
        !           274:        memcpy (&raw.yiaddr, lease->ip_addr.iabuf, 4);
        !           275: 
        !           276:        /* If we're always supposed to broadcast to this client, set
        !           277:           the broadcast bit in the bootp flags field. */
        !           278:        if ((oc = lookup_option (&server_universe,
        !           279:                                options, SV_ALWAYS_BROADCAST)) &&
        !           280:            evaluate_boolean_option_cache (&ignorep, packet, lease,
        !           281:                                           (struct client_state *)0,
        !           282:                                           packet -> options, options,
        !           283:                                           &lease -> scope, oc, MDL))
        !           284:                raw.flags |= htons (BOOTP_BROADCAST);
        !           285: 
        !           286:        /* Figure out the address of the next server. */
        !           287:        memset (&d1, 0, sizeof d1);
        !           288:        oc = lookup_option (&server_universe, options, SV_NEXT_SERVER);
        !           289:        if (oc &&
        !           290:            evaluate_option_cache (&d1, packet, lease,
        !           291:                                   (struct client_state *)0,
        !           292:                                   packet -> options, options,
        !           293:                                   &lease -> scope, oc, MDL)) {
        !           294:                /* If there was more than one answer, take the first. */
        !           295:                if (d1.len >= 4 && d1.data)
        !           296:                        memcpy (&raw.siaddr, d1.data, 4);
        !           297:                data_string_forget (&d1, MDL);
        !           298:        } else {
        !           299:                if ((lease->subnet->shared_network->interface != NULL) &&
        !           300:                    lease->subnet->shared_network->interface->address_count)
        !           301:                    raw.siaddr =
        !           302:                        lease->subnet->shared_network->interface->addresses[0];
        !           303:                else if (packet->interface->address_count)
        !           304:                        raw.siaddr = packet->interface->addresses[0];
        !           305:        }
        !           306: 
        !           307:        raw.giaddr = packet -> raw -> giaddr;
        !           308: 
        !           309:        /* Figure out the filename. */
        !           310:        oc = lookup_option (&server_universe, options, SV_FILENAME);
        !           311:        if (oc &&
        !           312:            evaluate_option_cache (&d1, packet, lease,
        !           313:                                   (struct client_state *)0,
        !           314:                                   packet -> options, options,
        !           315:                                   &lease -> scope, oc, MDL)) {
        !           316:                memcpy (raw.file, d1.data,
        !           317:                        d1.len > sizeof raw.file ? sizeof raw.file : d1.len);
        !           318:                if (sizeof raw.file > d1.len)
        !           319:                        memset (&raw.file [d1.len],
        !           320:                                0, (sizeof raw.file) - d1.len);
        !           321:                data_string_forget (&d1, MDL);
        !           322:        } else
        !           323:                memcpy (raw.file, packet -> raw -> file, sizeof raw.file);
        !           324: 
        !           325:        /* Choose a server name as above. */
        !           326:        oc = lookup_option (&server_universe, options, SV_SERVER_NAME);
        !           327:        if (oc &&
        !           328:            evaluate_option_cache (&d1, packet, lease,
        !           329:                                   (struct client_state *)0,
        !           330:                                   packet -> options, options,
        !           331:                                   &lease -> scope, oc, MDL)) {
        !           332:                memcpy (raw.sname, d1.data,
        !           333:                        d1.len > sizeof raw.sname ? sizeof raw.sname : d1.len);
        !           334:                if (sizeof raw.sname > d1.len)
        !           335:                        memset (&raw.sname [d1.len],
        !           336:                                0, (sizeof raw.sname) - d1.len);
        !           337:                data_string_forget (&d1, MDL);
        !           338:        }
        !           339: 
        !           340:        /* Execute the commit statements, if there are any. */
        !           341:        execute_statements ((struct binding_value **)0,
        !           342:                            packet, lease, (struct client_state *)0,
        !           343:                            packet -> options,
        !           344:                            options, &lease -> scope, lease -> on_commit);
        !           345: 
        !           346:        /* We're done with the option state. */
        !           347:        option_state_dereference (&options, MDL);
        !           348: 
        !           349:        /* Set up the hardware destination address... */
        !           350:        hto.hbuf [0] = packet -> raw -> htype;
        !           351:        hto.hlen = packet -> raw -> hlen + 1;
        !           352:        memcpy (&hto.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen);
        !           353: 
        !           354:        if (packet->interface->address_count) {
        !           355:                from = packet->interface->addresses[0];
        !           356:        } else {
        !           357:                log_error("%s: Interface %s appears to have no IPv4 "
        !           358:                          "addresses, and so dhcpd cannot select a source "
        !           359:                          "address.", msgbuf, packet->interface->name);
        !           360:                goto out;
        !           361:        }
        !           362: 
        !           363:        /* Report what we're doing... */
        !           364:        log_info ("%s", msgbuf);
        !           365:        log_info ("BOOTREPLY for %s to %s (%s) via %s",
        !           366:              piaddr (lease->ip_addr), hp -> name,
        !           367:              print_hw_addr (packet -> raw -> htype,
        !           368:                             packet -> raw -> hlen,
        !           369:                             packet -> raw -> chaddr),
        !           370:              packet -> raw -> giaddr.s_addr
        !           371:              ? inet_ntoa (packet -> raw -> giaddr)
        !           372:              : packet -> interface -> name);
        !           373: 
        !           374:        /* Set up the parts of the address that are in common. */
        !           375:        to.sin_family = AF_INET;
        !           376: #ifdef HAVE_SA_LEN
        !           377:        to.sin_len = sizeof to;
        !           378: #endif
        !           379:        memset (to.sin_zero, 0, sizeof to.sin_zero);
        !           380: 
        !           381:        /* If this was gatewayed, send it back to the gateway... */
        !           382:        if (raw.giaddr.s_addr) {
        !           383:                to.sin_addr = raw.giaddr;
        !           384:                to.sin_port = local_port;
        !           385: 
        !           386:                if (fallback_interface) {
        !           387:                        result = send_packet (fallback_interface,
        !           388:                                              (struct packet *)0,
        !           389:                                              &raw, outgoing.packet_length,
        !           390:                                              from, &to, &hto);
        !           391:                        goto out;
        !           392:                }
        !           393: 
        !           394:        /* If it comes from a client that already knows its address
        !           395:           and is not requesting a broadcast response, and we can
        !           396:           unicast to a client without using the ARP protocol, sent it
        !           397:           directly to that client. */
        !           398:        } else if (!(raw.flags & htons (BOOTP_BROADCAST)) &&
        !           399:                   can_unicast_without_arp (packet -> interface)) {
        !           400:                to.sin_addr = raw.yiaddr;
        !           401:                to.sin_port = remote_port;
        !           402: 
        !           403:        /* Otherwise, broadcast it on the local network. */
        !           404:        } else {
        !           405:                to.sin_addr = limited_broadcast;
        !           406:                to.sin_port = remote_port; /* XXX */
        !           407:        }
        !           408: 
        !           409:        errno = 0;
        !           410:        result = send_packet (packet -> interface,
        !           411:                              packet, &raw, outgoing.packet_length,
        !           412:                              from, &to, &hto);
        !           413:       out:
        !           414:        if (options)
        !           415:                option_state_dereference (&options, MDL);
        !           416:        if (lease)
        !           417:                lease_dereference (&lease, MDL);
        !           418:        if (hp)
        !           419:                host_dereference (&hp, MDL);
        !           420:        if (host)
        !           421:                host_dereference (&host, MDL);
        !           422: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>