1 /* $NetBSD: bootp.c,v 1.1.1.3 2014/07/12 11:58:04 spz Exp $ */ 2 /* bootp.c 3 4 BOOTP Protocol support. */ 5 6 /* 7 * Copyright (c) 2009,2012-2014 by Internet Systems Consortium, Inc. ("ISC") 8 * Copyright (c) 2004,2005,2007 by Internet Systems Consortium, Inc. ("ISC") 9 * Copyright (c) 1995-2003 by Internet Software Consortium 10 * 11 * Permission to use, copy, modify, and distribute this software for any 12 * purpose with or without fee is hereby granted, provided that the above 13 * copyright notice and this permission notice appear in all copies. 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 * 950 Charter Street 25 * Redwood City, CA 94063 26 * <info@isc.org> 27 * https://www.isc.org/ 28 * 29 */ 30 31 #include <sys/cdefs.h> 32 __RCSID("$NetBSD: bootp.c,v 1.1.1.3 2014/07/12 11:58:04 spz 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 41 void 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 (struct client_state *)0, 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 (struct client_state *)0, 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 if (!packet -> options_valid && 213 !(evaluate_boolean_option_cache 214 (&ignorep, packet, lease, (struct client_state *)0, 215 packet -> options, options, &lease -> scope, 216 lookup_option (&server_universe, options, 217 SV_ALWAYS_REPLY_RFC1048), MDL))) { 218 memcpy (outgoing.raw -> options, 219 packet -> raw -> options, DHCP_MAX_OPTION_LEN); 220 outgoing.packet_length = BOOTP_MIN_LEN; 221 } else { 222 223 /* Use the subnet mask from the subnet declaration if no other 224 mask has been provided. */ 225 226 oc = (struct option_cache *)0; 227 i = DHO_SUBNET_MASK; 228 if (!lookup_option (&dhcp_universe, options, i)) { 229 if (option_cache_allocate (&oc, MDL)) { 230 if (make_const_data 231 (&oc -> expression, 232 lease -> subnet -> netmask.iabuf, 233 lease -> subnet -> netmask.len, 234 0, 0, MDL)) { 235 option_code_hash_lookup(&oc->option, 236 dhcp_universe.code_hash, 237 &i, 0, MDL); 238 save_option (&dhcp_universe, 239 options, oc); 240 } 241 option_cache_dereference (&oc, MDL); 242 } 243 } 244 245 /* Pack the options into the buffer. Unlike DHCP, we 246 can't pack options into the filename and server 247 name buffers. */ 248 249 outgoing.packet_length = 250 cons_options (packet, outgoing.raw, lease, 251 (struct client_state *)0, 0, 252 packet -> options, options, 253 &lease -> scope, 254 0, 0, 1, (struct data_string *)0, 255 (const char *)0); 256 if (outgoing.packet_length < BOOTP_MIN_LEN) 257 outgoing.packet_length = BOOTP_MIN_LEN; 258 } 259 260 /* Take the fields that we care about... */ 261 raw.op = BOOTREPLY; 262 raw.htype = packet -> raw -> htype; 263 raw.hlen = packet -> raw -> hlen; 264 memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr); 265 raw.hops = packet -> raw -> hops; 266 raw.xid = packet -> raw -> xid; 267 raw.secs = packet -> raw -> secs; 268 raw.flags = packet -> raw -> flags; 269 raw.ciaddr = packet -> raw -> ciaddr; 270 271 /* yiaddr is an ipv4 address, it must be 4 octets. */ 272 memcpy (&raw.yiaddr, lease->ip_addr.iabuf, 4); 273 274 /* If we're always supposed to broadcast to this client, set 275 the broadcast bit in the bootp flags field. */ 276 if ((oc = lookup_option (&server_universe, 277 options, SV_ALWAYS_BROADCAST)) && 278 evaluate_boolean_option_cache (&ignorep, packet, lease, 279 (struct client_state *)0, 280 packet -> options, options, 281 &lease -> scope, oc, MDL)) 282 raw.flags |= htons (BOOTP_BROADCAST); 283 284 /* Figure out the address of the next server. */ 285 memset (&d1, 0, sizeof d1); 286 oc = lookup_option (&server_universe, options, SV_NEXT_SERVER); 287 if (oc && 288 evaluate_option_cache (&d1, packet, lease, 289 (struct client_state *)0, 290 packet -> options, options, 291 &lease -> scope, oc, MDL)) { 292 /* If there was more than one answer, take the first. */ 293 if (d1.len >= 4 && d1.data) 294 memcpy (&raw.siaddr, d1.data, 4); 295 data_string_forget (&d1, MDL); 296 } else { 297 if ((lease->subnet->shared_network->interface != NULL) && 298 lease->subnet->shared_network->interface->address_count) 299 raw.siaddr = 300 lease->subnet->shared_network->interface->addresses[0]; 301 else if (packet->interface->address_count) 302 raw.siaddr = packet->interface->addresses[0]; 303 } 304 305 raw.giaddr = packet -> raw -> giaddr; 306 307 /* Figure out the filename. */ 308 oc = lookup_option (&server_universe, options, SV_FILENAME); 309 if (oc && 310 evaluate_option_cache (&d1, packet, lease, 311 (struct client_state *)0, 312 packet -> options, options, 313 &lease -> scope, oc, MDL)) { 314 memcpy (raw.file, d1.data, 315 d1.len > sizeof raw.file ? sizeof raw.file : d1.len); 316 if (sizeof raw.file > d1.len) 317 memset (&raw.file [d1.len], 318 0, (sizeof raw.file) - d1.len); 319 data_string_forget (&d1, MDL); 320 } else 321 memcpy (raw.file, packet -> raw -> file, sizeof raw.file); 322 323 /* Choose a server name as above. */ 324 oc = lookup_option (&server_universe, options, SV_SERVER_NAME); 325 if (oc && 326 evaluate_option_cache (&d1, packet, lease, 327 (struct client_state *)0, 328 packet -> options, options, 329 &lease -> scope, oc, MDL)) { 330 memcpy (raw.sname, d1.data, 331 d1.len > sizeof raw.sname ? sizeof raw.sname : d1.len); 332 if (sizeof raw.sname > d1.len) 333 memset (&raw.sname [d1.len], 334 0, (sizeof raw.sname) - d1.len); 335 data_string_forget (&d1, MDL); 336 } 337 338 /* Execute the commit statements, if there are any. */ 339 execute_statements (NULL, packet, lease, NULL, packet->options, 340 options, &lease->scope, lease->on_star.on_commit, 341 NULL); 342 343 /* We're done with the option state. */ 344 option_state_dereference (&options, MDL); 345 346 /* Set up the hardware destination address... */ 347 hto.hbuf [0] = packet -> raw -> htype; 348 hto.hlen = packet -> raw -> hlen + 1; 349 memcpy (&hto.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen); 350 351 if (packet->interface->address_count) { 352 from = packet->interface->addresses[0]; 353 } else { 354 log_error("%s: Interface %s appears to have no IPv4 " 355 "addresses, and so dhcpd cannot select a source " 356 "address.", msgbuf, packet->interface->name); 357 goto out; 358 } 359 360 /* Report what we're doing... */ 361 log_info("%s", msgbuf); 362 log_info("BOOTREPLY for %s to %s (%s) via %s", 363 piaddr(lease->ip_addr), 364 ((hp != NULL) && (hp->name != NULL)) ? hp -> name : "unknown", 365 print_hw_addr (packet->raw->htype, 366 packet->raw->hlen, 367 packet->raw->chaddr), 368 packet->raw->giaddr.s_addr 369 ? inet_ntoa (packet->raw->giaddr) 370 : packet->interface->name); 371 372 /* Set up the parts of the address that are in common. */ 373 to.sin_family = AF_INET; 374 #ifdef HAVE_SA_LEN 375 to.sin_len = sizeof to; 376 #endif 377 memset (to.sin_zero, 0, sizeof to.sin_zero); 378 379 /* If this was gatewayed, send it back to the gateway... */ 380 if (raw.giaddr.s_addr) { 381 to.sin_addr = raw.giaddr; 382 to.sin_port = local_port; 383 384 if (fallback_interface) { 385 result = send_packet (fallback_interface, NULL, &raw, 386 outgoing.packet_length, from, 387 &to, &hto); 388 if (result < 0) { 389 log_error ("%s:%d: Failed to send %d byte long " 390 "packet over %s interface.", MDL, 391 outgoing.packet_length, 392 fallback_interface->name); 393 } 394 395 goto out; 396 } 397 398 /* If it comes from a client that already knows its address 399 and is not requesting a broadcast response, and we can 400 unicast to a client without using the ARP protocol, sent it 401 directly to that client. */ 402 } else if (!(raw.flags & htons (BOOTP_BROADCAST)) && 403 can_unicast_without_arp (packet -> interface)) { 404 to.sin_addr = raw.yiaddr; 405 to.sin_port = remote_port; 406 407 /* Otherwise, broadcast it on the local network. */ 408 } else { 409 to.sin_addr = limited_broadcast; 410 to.sin_port = remote_port; /* XXX */ 411 } 412 413 errno = 0; 414 result = send_packet(packet->interface, packet, &raw, 415 outgoing.packet_length, from, &to, &hto); 416 if (result < 0) { 417 log_error ("%s:%d: Failed to send %d byte long packet over %s" 418 " interface.", MDL, outgoing.packet_length, 419 packet->interface->name); 420 } 421 422 out: 423 424 if (options) 425 option_state_dereference (&options, MDL); 426 if (lease) 427 lease_dereference (&lease, MDL); 428 if (hp) 429 host_dereference (&hp, MDL); 430 if (host) 431 host_dereference (&host, MDL); 432 } 433