server/bootp.c

Go to the documentation of this file.
00001 /* bootp.c
00002 
00003    BOOTP Protocol support. */
00004 
00005 /*
00006  * Copyright (c) 2009,2012-2014 by Internet Systems Consortium, Inc. ("ISC")
00007  * Copyright (c) 2004,2005,2007 by Internet Systems Consortium, Inc. ("ISC")
00008  * Copyright (c) 1995-2003 by Internet Software Consortium
00009  *
00010  * Permission to use, copy, modify, and distribute this software for any
00011  * purpose with or without fee is hereby granted, provided that the above
00012  * copyright notice and this permission notice appear in all copies.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00015  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00016  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00017  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00018  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00019  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00020  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00021  *
00022  *   Internet Systems Consortium, Inc.
00023  *   950 Charter Street
00024  *   Redwood City, CA 94063
00025  *   <info@isc.org>
00026  *   https://www.isc.org/
00027  *
00028  */
00029 
00030 #include "dhcpd.h"
00031 #include <errno.h>
00032 
00033 #if defined (TRACING)
00034 # define send_packet trace_packet_send
00035 #endif
00036 
00037 void bootp (packet)
00038         struct packet *packet;
00039 {
00040         int result;
00041         struct host_decl *hp = (struct host_decl *)0;
00042         struct host_decl *host = (struct host_decl *)0;
00043         struct packet outgoing;
00044         struct dhcp_packet raw;
00045         struct sockaddr_in to;
00046         struct in_addr from;
00047         struct hardware hto;
00048         struct option_state *options = (struct option_state *)0;
00049         struct lease *lease = (struct lease *)0;
00050         unsigned i;
00051         struct data_string d1;
00052         struct option_cache *oc;
00053         char msgbuf [1024];
00054         int ignorep;
00055         int peer_has_leases = 0;
00056         int norelay = 0;
00057 
00058         if (packet -> raw -> op != BOOTREQUEST)
00059                 return;
00060 
00061         /* %Audit% This is log output. %2004.06.17,Safe%
00062          * If we truncate we hope the user can get a hint from the log.
00063          */
00064         snprintf (msgbuf, sizeof msgbuf, "BOOTREQUEST from %s via %s",
00065                  print_hw_addr (packet -> raw -> htype,
00066                                 packet -> raw -> hlen,
00067                                 packet -> raw -> chaddr),
00068                  packet -> raw -> giaddr.s_addr
00069                  ? inet_ntoa (packet -> raw -> giaddr)
00070                  : packet -> interface -> name);
00071 
00072         if ((norelay = locate_network (packet)) == 0) {
00073                 log_info ("%s: network unknown", msgbuf);
00074                 return;
00075         }
00076 
00077         find_lease (&lease, packet, packet -> shared_network,
00078                     0, 0, (struct lease *)0, MDL);
00079 
00080         if (lease && lease->host)
00081                 host_reference(&hp, lease->host, MDL);
00082 
00083         if (!lease || ((lease->flags & STATIC_LEASE) == 0)) {
00084                 struct host_decl *h;
00085 
00086                 /* We didn't find an applicable fixed-address host
00087                    declaration.  Just in case we may be able to dynamically
00088                    assign an address, see if there's a host declaration
00089                    that doesn't have an ip address associated with it. */
00090 
00091                 if (!hp)
00092                         find_hosts_by_haddr(&hp, packet->raw->htype,
00093                                             packet->raw->chaddr,
00094                                             packet->raw->hlen, MDL);
00095 
00096                 for (h = hp; h; h = h -> n_ipaddr) {
00097                         if (!h -> fixed_addr) {
00098                                 host_reference(&host, h, MDL);
00099                                 break;
00100                         }
00101                 }
00102 
00103                 if (hp)
00104                         host_dereference(&hp, MDL);
00105 
00106                 if (host) {
00107                         host_reference(&hp, host, MDL);
00108                         host_dereference(&host, MDL);
00109                 }
00110 
00111                 /* Allocate a lease if we have not yet found one. */
00112                 if (!lease)
00113                         allocate_lease (&lease, packet,
00114                                         packet -> shared_network -> pools,
00115                                         &peer_has_leases);
00116 
00117                 if (lease == NULL) {
00118                         log_info("%s: BOOTP from dynamic client and no "
00119                                  "dynamic leases", msgbuf);
00120                         goto out;
00121                 }
00122 
00123 #if defined(FAILOVER_PROTOCOL)
00124                 if ((lease->pool != NULL) &&
00125                     (lease->pool->failover_peer != NULL)) {
00126                         dhcp_failover_state_t *peer;
00127 
00128                         peer = lease->pool->failover_peer;
00129 
00130                         /* If we are in a failover state that bars us from
00131                          * answering, do not do so.
00132                          * If we are in a cooperative state, load balance
00133                          * (all) responses.
00134                          */
00135                         if ((peer->service_state == not_responding) ||
00136                             (peer->service_state == service_startup)) {
00137                                 log_info("%s: not responding%s",
00138                                          msgbuf, peer->nrr);
00139                                 goto out;
00140                         } else if((peer->service_state == cooperating) &&
00141                                   !load_balance_mine(packet, peer)) {
00142                                 log_info("%s: load balance to peer %s",
00143                                          msgbuf, peer->name);
00144                                 goto out;
00145                         }
00146                 }
00147 #endif
00148 
00149                 ack_lease (packet, lease, 0, 0, msgbuf, 0, hp);
00150                 goto out;
00151         }
00152 
00153         /* Run the executable statements to compute the client and server
00154            options. */
00155         option_state_allocate (&options, MDL);
00156 
00157         /* Execute the subnet statements. */
00158         execute_statements_in_scope (NULL, packet, lease, NULL,
00159                                      packet->options, options,
00160                                      &lease->scope, lease->subnet->group,
00161                                      NULL, NULL);
00162 
00163         /* Execute statements from class scopes. */
00164         for (i = packet -> class_count; i > 0; i--) {
00165                 execute_statements_in_scope(NULL, packet, lease, NULL,
00166                                             packet->options, options,
00167                                             &lease->scope,
00168                                             packet->classes[i - 1]->group,
00169                                             lease->subnet->group, NULL);
00170         }
00171 
00172         /* Execute the host statements. */
00173         if (hp != NULL) {
00174                 execute_statements_in_scope (NULL, packet, lease, NULL,
00175                                              packet->options, options,
00176                                              &lease->scope, hp->group,
00177                                              lease->subnet->group, NULL);
00178         }
00179         
00180         /* Drop the request if it's not allowed for this client. */
00181         if ((oc = lookup_option (&server_universe, options, SV_ALLOW_BOOTP)) &&
00182             !evaluate_boolean_option_cache (&ignorep, packet, lease,
00183                                             (struct client_state *)0,
00184                                             packet -> options, options,
00185                                             &lease -> scope, oc, MDL)) {
00186                 if (!ignorep)
00187                         log_info ("%s: bootp disallowed", msgbuf);
00188                 goto out;
00189         } 
00190 
00191         if ((oc = lookup_option (&server_universe,
00192                                  options, SV_ALLOW_BOOTING)) &&
00193             !evaluate_boolean_option_cache (&ignorep, packet, lease,
00194                                             (struct client_state *)0,
00195                                             packet -> options, options,
00196                                             &lease -> scope, oc, MDL)) {
00197                 if (!ignorep)
00198                         log_info ("%s: booting disallowed", msgbuf);
00199                 goto out;
00200         }
00201 
00202         /* Set up the outgoing packet... */
00203         memset (&outgoing, 0, sizeof outgoing);
00204         memset (&raw, 0, sizeof raw);
00205         outgoing.raw = &raw;
00206 
00207         /* If we didn't get a known vendor magic number on the way in,
00208            just copy the input options to the output. */
00209         if (!packet -> options_valid &&
00210             !(evaluate_boolean_option_cache
00211               (&ignorep, packet, lease, (struct client_state *)0,
00212                packet -> options, options, &lease -> scope,
00213                lookup_option (&server_universe, options,
00214                               SV_ALWAYS_REPLY_RFC1048), MDL))) {
00215                 memcpy (outgoing.raw -> options,
00216                         packet -> raw -> options, DHCP_MAX_OPTION_LEN);
00217                 outgoing.packet_length = BOOTP_MIN_LEN;
00218         } else {
00219 
00220                 /* Use the subnet mask from the subnet declaration if no other
00221                    mask has been provided. */
00222 
00223                 oc = (struct option_cache *)0;
00224                 i = DHO_SUBNET_MASK;
00225                 if (!lookup_option (&dhcp_universe, options, i)) {
00226                         if (option_cache_allocate (&oc, MDL)) {
00227                                 if (make_const_data
00228                                     (&oc -> expression,
00229                                      lease -> subnet -> netmask.iabuf,
00230                                      lease -> subnet -> netmask.len,
00231                                      0, 0, MDL)) {
00232                                         option_code_hash_lookup(&oc->option,
00233                                                         dhcp_universe.code_hash,
00234                                                                 &i, 0, MDL);
00235                                         save_option (&dhcp_universe,
00236                                                      options, oc);
00237                                 }
00238                                 option_cache_dereference (&oc, MDL);
00239                         }
00240                 }
00241 
00242                 /* Pack the options into the buffer.  Unlike DHCP, we
00243                    can't pack options into the filename and server
00244                    name buffers. */
00245 
00246                 outgoing.packet_length =
00247                         cons_options (packet, outgoing.raw, lease,
00248                                       (struct client_state *)0, 0,
00249                                       packet -> options, options,
00250                                       &lease -> scope,
00251                                       0, 0, 1, (struct data_string *)0,
00252                                       (const char *)0);
00253                 if (outgoing.packet_length < BOOTP_MIN_LEN)
00254                         outgoing.packet_length = BOOTP_MIN_LEN;
00255         }
00256 
00257         /* Take the fields that we care about... */
00258         raw.op = BOOTREPLY;
00259         raw.htype = packet -> raw -> htype;
00260         raw.hlen = packet -> raw -> hlen;
00261         memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
00262         raw.hops = packet -> raw -> hops;
00263         raw.xid = packet -> raw -> xid;
00264         raw.secs = packet -> raw -> secs;
00265         raw.flags = packet -> raw -> flags;
00266         raw.ciaddr = packet -> raw -> ciaddr;
00267 
00268         /* yiaddr is an ipv4 address, it must be 4 octets. */
00269         memcpy (&raw.yiaddr, lease->ip_addr.iabuf, 4);
00270 
00271         /* If we're always supposed to broadcast to this client, set
00272            the broadcast bit in the bootp flags field. */
00273         if ((oc = lookup_option (&server_universe,
00274                                 options, SV_ALWAYS_BROADCAST)) &&
00275             evaluate_boolean_option_cache (&ignorep, packet, lease,
00276                                            (struct client_state *)0,
00277                                            packet -> options, options,
00278                                            &lease -> scope, oc, MDL))
00279                 raw.flags |= htons (BOOTP_BROADCAST);
00280 
00281         /* Figure out the address of the next server. */
00282         memset (&d1, 0, sizeof d1);
00283         oc = lookup_option (&server_universe, options, SV_NEXT_SERVER);
00284         if (oc &&
00285             evaluate_option_cache (&d1, packet, lease,
00286                                    (struct client_state *)0,
00287                                    packet -> options, options,
00288                                    &lease -> scope, oc, MDL)) {
00289                 /* If there was more than one answer, take the first. */
00290                 if (d1.len >= 4 && d1.data)
00291                         memcpy (&raw.siaddr, d1.data, 4);
00292                 data_string_forget (&d1, MDL);
00293         } else {
00294                 if ((lease->subnet->shared_network->interface != NULL) &&
00295                     lease->subnet->shared_network->interface->address_count)
00296                     raw.siaddr =
00297                         lease->subnet->shared_network->interface->addresses[0];
00298                 else if (packet->interface->address_count)
00299                         raw.siaddr = packet->interface->addresses[0];
00300         }
00301 
00302         raw.giaddr = packet -> raw -> giaddr;
00303 
00304         /* Figure out the filename. */
00305         oc = lookup_option (&server_universe, options, SV_FILENAME);
00306         if (oc &&
00307             evaluate_option_cache (&d1, packet, lease,
00308                                    (struct client_state *)0,
00309                                    packet -> options, options,
00310                                    &lease -> scope, oc, MDL)) {
00311                 memcpy (raw.file, d1.data,
00312                         d1.len > sizeof raw.file ? sizeof raw.file : d1.len);
00313                 if (sizeof raw.file > d1.len)
00314                         memset (&raw.file [d1.len],
00315                                 0, (sizeof raw.file) - d1.len);
00316                 data_string_forget (&d1, MDL);
00317         } else
00318                 memcpy (raw.file, packet -> raw -> file, sizeof raw.file);
00319 
00320         /* Choose a server name as above. */
00321         oc = lookup_option (&server_universe, options, SV_SERVER_NAME);
00322         if (oc &&
00323             evaluate_option_cache (&d1, packet, lease,
00324                                    (struct client_state *)0,
00325                                    packet -> options, options,
00326                                    &lease -> scope, oc, MDL)) {
00327                 memcpy (raw.sname, d1.data,
00328                         d1.len > sizeof raw.sname ? sizeof raw.sname : d1.len);
00329                 if (sizeof raw.sname > d1.len)
00330                         memset (&raw.sname [d1.len],
00331                                 0, (sizeof raw.sname) - d1.len);
00332                 data_string_forget (&d1, MDL);
00333         }
00334 
00335         /* Execute the commit statements, if there are any. */
00336         execute_statements (NULL, packet, lease, NULL, packet->options,
00337                             options, &lease->scope, lease->on_star.on_commit,
00338                             NULL);
00339 
00340         /* We're done with the option state. */
00341         option_state_dereference (&options, MDL);
00342 
00343         /* Set up the hardware destination address... */
00344         hto.hbuf [0] = packet -> raw -> htype;
00345         hto.hlen = packet -> raw -> hlen + 1;
00346         memcpy (&hto.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen);
00347 
00348         if (packet->interface->address_count) {
00349                 from = packet->interface->addresses[0];
00350         } else {
00351                 log_error("%s: Interface %s appears to have no IPv4 "
00352                           "addresses, and so dhcpd cannot select a source "
00353                           "address.", msgbuf, packet->interface->name);
00354                 goto out;
00355         }
00356 
00357         /* Report what we're doing... */
00358         log_info("%s", msgbuf);
00359         log_info("BOOTREPLY for %s to %s (%s) via %s",
00360                  piaddr(lease->ip_addr),
00361                  ((hp != NULL) && (hp->name != NULL)) ? hp -> name : "unknown",
00362                  print_hw_addr (packet->raw->htype,
00363                                 packet->raw->hlen,
00364                                 packet->raw->chaddr),
00365                  packet->raw->giaddr.s_addr
00366                  ? inet_ntoa (packet->raw->giaddr)
00367                  : packet->interface->name);
00368 
00369         /* Set up the parts of the address that are in common. */
00370         to.sin_family = AF_INET;
00371 #ifdef HAVE_SA_LEN
00372         to.sin_len = sizeof to;
00373 #endif
00374         memset (to.sin_zero, 0, sizeof to.sin_zero);
00375 
00376         /* If this was gatewayed, send it back to the gateway... */
00377         if (raw.giaddr.s_addr) {
00378                 to.sin_addr = raw.giaddr;
00379                 to.sin_port = local_port;
00380 
00381                 if (fallback_interface) {
00382                         result = send_packet (fallback_interface, NULL, &raw,
00383                                               outgoing.packet_length, from,
00384                                               &to, &hto);
00385                         if (result < 0) {
00386                                 log_error ("%s:%d: Failed to send %d byte long "
00387                                            "packet over %s interface.", MDL,
00388                                            outgoing.packet_length,
00389                                            fallback_interface->name);
00390                         }
00391 
00392                         goto out;
00393                 }
00394         } else if (norelay == 2) {
00395                 to.sin_addr = raw.ciaddr;
00396                 to.sin_port = remote_port;
00397                 if (fallback_interface) {
00398                         result = send_packet (fallback_interface, NULL, &raw,
00399                                               outgoing.packet_length, from,
00400                                               &to, &hto);
00401                         goto out;
00402                 }
00403 
00404         /* If it comes from a client that already knows its address
00405            and is not requesting a broadcast response, and we can
00406            unicast to a client without using the ARP protocol, sent it
00407            directly to that client. */
00408         } else if (!(raw.flags & htons (BOOTP_BROADCAST)) &&
00409                    can_unicast_without_arp (packet -> interface)) {
00410                 to.sin_addr = raw.yiaddr;
00411                 to.sin_port = remote_port;
00412 
00413         /* Otherwise, broadcast it on the local network. */
00414         } else {
00415                 to.sin_addr = limited_broadcast;
00416                 to.sin_port = remote_port; /* XXX */
00417         }
00418 
00419         errno = 0;
00420         result = send_packet(packet->interface, packet, &raw,
00421                              outgoing.packet_length, from, &to, &hto);
00422         if (result < 0) {
00423                 log_error ("%s:%d: Failed to send %d byte long packet over %s"
00424                            " interface.", MDL, outgoing.packet_length,
00425                            packet->interface->name);
00426         }
00427 
00428       out:
00429 
00430         if (options)
00431                 option_state_dereference (&options, MDL);
00432         if (lease)
00433                 lease_dereference (&lease, MDL);
00434         if (hp)
00435                 host_dereference (&hp, MDL);
00436         if (host)
00437                 host_dereference (&host, MDL);
00438 }

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1