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

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

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