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