1 /* $OpenBSD: bootp.c,v 1.18 2017/02/13 22:33:39 krw Exp $ */ 2 3 /* 4 * BOOTP Protocol support. 5 */ 6 7 /* 8 * Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of The Internet Software Consortium nor the names 21 * of its contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND 25 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 26 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 29 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 32 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 33 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 34 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 35 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * This software has been written for the Internet Software Consortium 39 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 40 * Enterprises. To learn more about the Internet Software Consortium, 41 * see ``http://www.vix.com/isc''. To learn more about Vixie 42 * Enterprises, see ``http://www.vix.com''. 43 */ 44 45 #include <sys/socket.h> 46 47 #include <arpa/inet.h> 48 49 #include <net/if.h> 50 51 #include <netinet/in.h> 52 53 #include <errno.h> 54 #include <stdio.h> 55 #include <string.h> 56 57 #include "dhcp.h" 58 #include "tree.h" 59 #include "dhcpd.h" 60 #include "log.h" 61 62 void 63 bootp(struct packet *packet) 64 { 65 struct host_decl *hp, *host = NULL; 66 struct packet outgoing; 67 struct dhcp_packet raw; 68 struct sockaddr_in to; 69 struct in_addr from; 70 struct tree_cache *options[256]; 71 struct shared_network *s; 72 struct subnet *subnet = NULL; 73 struct lease *lease; 74 struct iaddr ip_address; 75 int i; 76 77 if (packet->raw->op != BOOTREQUEST) 78 return; 79 80 log_info("BOOTREQUEST from %s via %s%s", 81 print_hw_addr(packet->raw->htype, packet->raw->hlen, 82 packet->raw->chaddr), packet->raw->giaddr.s_addr ? 83 inet_ntoa(packet->raw->giaddr) : packet->interface->name, 84 packet->options_valid ? "" : " (non-rfc1048)"); 85 86 if (!locate_network(packet)) 87 return; 88 89 hp = find_hosts_by_haddr(packet->raw->htype, packet->raw->chaddr, 90 packet->raw->hlen); 91 92 s = packet->shared_network; 93 lease = find_lease(packet, s, 0); 94 95 /* 96 * Find an IP address in the host_decl that matches the specified 97 * network. 98 */ 99 if (hp) 100 subnet = find_host_for_network(&hp, &ip_address, s); 101 102 if (!subnet) { 103 /* 104 * We didn't find an applicable host declaration. Just in case 105 * we may be able to dynamically assign an address, see if 106 * there's a host declaration that doesn't have an ip address 107 * associated with it. 108 */ 109 if (hp) 110 for (; hp; hp = hp->n_ipaddr) 111 if (!hp->fixed_addr) { 112 host = hp; 113 break; 114 } 115 116 if (host && (!host->group->allow_booting)) { 117 log_info("Ignoring excluded BOOTP client %s", 118 host->name ? host->name : 119 print_hw_addr (packet->raw->htype, 120 packet->raw->hlen, packet->raw->chaddr)); 121 return; 122 } 123 124 if (host && (!host->group->allow_bootp)) { 125 log_info("Ignoring BOOTP request from client %s", 126 host->name ? host->name : 127 print_hw_addr(packet->raw->htype, 128 packet->raw->hlen, packet->raw->chaddr)); 129 return; 130 } 131 132 /* 133 * If we've been told not to boot unknown clients, and we 134 * didn't find any host record for this client, ignore it. 135 */ 136 if (!host && !(s->group->boot_unknown_clients)) { 137 log_info("Ignoring unknown BOOTP client %s via %s", 138 print_hw_addr(packet->raw->htype, 139 packet->raw->hlen, packet->raw->chaddr), 140 packet->raw->giaddr.s_addr ? 141 inet_ntoa(packet->raw->giaddr) : 142 packet->interface->name); 143 return; 144 } 145 146 /* 147 * If we've been told not to boot with bootp on this network, 148 * ignore it. 149 */ 150 if (!host && !(s->group->allow_bootp)) { 151 log_info("Ignoring BOOTP request from client %s via " 152 "%s", print_hw_addr(packet->raw->htype, 153 packet->raw->hlen, packet->raw->chaddr), 154 packet->raw->giaddr.s_addr ? 155 inet_ntoa(packet->raw->giaddr) : 156 packet->interface->name); 157 return; 158 } 159 160 /* 161 * If the packet is from a host we don't know and there are no 162 * dynamic bootp addresses on the network it came in on, drop 163 * it on the floor. 164 */ 165 if (!(s->group->dynamic_bootp)) { 166 lose: 167 log_info("No applicable record for BOOTP host %s via " 168 "%s", print_hw_addr(packet->raw->htype, 169 packet->raw->hlen, packet->raw->chaddr), 170 packet->raw->giaddr.s_addr ? 171 inet_ntoa(packet->raw->giaddr) : 172 packet->interface->name); 173 return; 174 } 175 176 /* 177 * If a lease has already been assigned to this client and it's 178 * still okay to use dynamic bootp on that lease, reassign it. 179 */ 180 if (lease) { 181 /* 182 * If this lease can be used for dynamic bootp, do so. 183 */ 184 if ((lease->flags & DYNAMIC_BOOTP_OK)) { 185 /* 186 * If it's not a DYNAMIC_BOOTP lease, release 187 * it before reassigning it so that we don't 188 * get a lease conflict. 189 */ 190 if (!(lease->flags & BOOTP_LEASE)) 191 release_lease(lease); 192 193 lease->host = host; 194 ack_lease(packet, lease, 0, 0); 195 return; 196 } 197 198 /* 199 * If dynamic BOOTP is no longer allowed for this 200 * lease, set it free. 201 */ 202 release_lease(lease); 203 } 204 205 /* 206 * If there are dynamic bootp addresses that might be 207 * available, try to snag one. 208 */ 209 for (lease = s->last_lease; 210 lease && lease->ends <= cur_time; 211 lease = lease->prev) { 212 if ((lease->flags & DYNAMIC_BOOTP_OK)) { 213 lease->host = host; 214 ack_lease(packet, lease, 0, 0); 215 return; 216 } 217 } 218 goto lose; 219 } 220 221 /* Make sure we're allowed to boot this client. */ 222 if (hp && (!hp->group->allow_booting)) { 223 log_info("Ignoring excluded BOOTP client %s", hp->name); 224 return; 225 } 226 227 /* Make sure we're allowed to boot this client with bootp. */ 228 if (hp && (!hp->group->allow_bootp)) { 229 log_info("Ignoring BOOTP request from client %s", hp->name); 230 return; 231 } 232 233 /* Set up the outgoing packet... */ 234 memset(&outgoing, 0, sizeof outgoing); 235 memset(&raw, 0, sizeof raw); 236 outgoing.raw = &raw; 237 238 /* 239 * If we didn't get a known vendor magic number on the way in, just 240 * copy the input options to the output. 241 */ 242 if (!packet->options_valid && !subnet->group->always_reply_rfc1048 && 243 (!hp || !hp->group->always_reply_rfc1048)) { 244 memcpy(outgoing.raw->options, packet->raw->options, 245 DHCP_OPTION_LEN); 246 outgoing.packet_length = BOOTP_MIN_LEN; 247 } else { 248 struct tree_cache netmask_tree; /* -- RBF */ 249 250 /* 251 * Come up with a list of options that we want to send to this 252 * client. Start with the per-subnet options, and then override 253 * those with client-specific options. 254 */ 255 256 memcpy(options, subnet->group->options, sizeof(options)); 257 258 for (i = 0; i < 256; i++) 259 if (hp->group->options[i]) 260 options[i] = hp->group->options[i]; 261 262 /* 263 * Use the subnet mask from the subnet declaration if no other 264 * mask has been provided. 265 */ 266 if (!options[DHO_SUBNET_MASK]) { 267 options[DHO_SUBNET_MASK] = &netmask_tree; 268 netmask_tree.flags = TC_TEMPORARY; 269 netmask_tree.value = lease->subnet->netmask.iabuf; 270 netmask_tree.len = lease->subnet->netmask.len; 271 netmask_tree.buf_size = lease->subnet->netmask.len; 272 netmask_tree.timeout = -1; 273 netmask_tree.tree = NULL; 274 } 275 276 /* 277 * Pack the options into the buffer. Unlike DHCP, we can't pack 278 * options into the filename and server name buffers. 279 */ 280 281 outgoing.packet_length = cons_options(packet, outgoing.raw, 282 0, options, 0, 0, 1, NULL, 0); 283 284 if (outgoing.packet_length < BOOTP_MIN_LEN) 285 outgoing.packet_length = BOOTP_MIN_LEN; 286 } 287 288 /* Take the fields that we care about... */ 289 raw.op = BOOTREPLY; 290 raw.htype = packet->raw->htype; 291 raw.hlen = packet->raw->hlen; 292 memcpy(raw.chaddr, packet->raw->chaddr, sizeof(raw.chaddr)); 293 raw.hops = packet->raw->hops; 294 raw.xid = packet->raw->xid; 295 raw.secs = packet->raw->secs; 296 raw.flags = packet->raw->flags; 297 raw.ciaddr = packet->raw->ciaddr; 298 memcpy(&raw.yiaddr, ip_address.iabuf, sizeof(raw.yiaddr)); 299 300 /* Figure out the address of the next server. */ 301 if (hp && hp->group->next_server.len) 302 memcpy(&raw.siaddr, hp->group->next_server.iabuf, 4); 303 else if (subnet->group->next_server.len) 304 memcpy(&raw.siaddr, subnet->group->next_server.iabuf, 4); 305 else if (subnet->interface_address.len) 306 memcpy(&raw.siaddr, subnet->interface_address.iabuf, 4); 307 else 308 raw.siaddr = packet->interface->primary_address; 309 310 raw.giaddr = packet->raw->giaddr; 311 if (hp->group->server_name) 312 strncpy(raw.sname, hp->group->server_name, sizeof(raw.sname)); 313 else if (subnet->group->server_name) 314 strncpy(raw.sname, subnet->group->server_name, 315 sizeof(raw.sname)); 316 317 if (hp->group->filename) 318 strncpy(raw.file, hp->group->filename, sizeof(raw.file)); 319 else if (subnet->group->filename) 320 strncpy(raw.file, subnet->group->filename, sizeof(raw.file)); 321 else 322 memcpy(raw.file, packet->raw->file, sizeof(raw.file)); 323 324 from = packet->interface->primary_address; 325 326 /* Report what we're doing... */ 327 log_info("BOOTREPLY for %s to %s (%s) via %s", piaddr(ip_address), 328 hp->name, print_hw_addr(packet->raw->htype, packet->raw->hlen, 329 packet->raw->chaddr), packet->raw->giaddr.s_addr ? 330 inet_ntoa(packet->raw->giaddr) : packet->interface->name); 331 332 /* Set up the parts of the address that are in common. */ 333 memset(&to, 0, sizeof(to)); 334 to.sin_family = AF_INET; 335 #ifdef HAVE_SA_LEN 336 to.sin_len = sizeof(to); 337 #endif 338 339 /* If this was gatewayed, send it back to the gateway... */ 340 if (raw.giaddr.s_addr) { 341 to.sin_addr = raw.giaddr; 342 to.sin_port = server_port; 343 344 (void) packet->interface->send_packet(packet->interface, &raw, 345 outgoing.packet_length, from, &to, packet->haddr); 346 return; 347 } 348 349 /* 350 * If it comes from a client that already knows its address and is not 351 * requesting a broadcast response, and we can unicast to a client 352 * without using the ARP protocol, sent it directly to that client. 353 */ 354 else if (!(raw.flags & htons(BOOTP_BROADCAST))) { 355 to.sin_addr = raw.yiaddr; 356 to.sin_port = client_port; 357 } else { 358 /* Otherwise, broadcast it on the local network. */ 359 to.sin_addr.s_addr = INADDR_BROADCAST; 360 to.sin_port = client_port; /* XXX */ 361 } 362 363 errno = 0; 364 (void) packet->interface->send_packet(packet->interface, &raw, 365 outgoing.packet_length, from, &to, packet->haddr); 366 } 367