1 /* $OpenBSD: bootp.c,v 1.15 2014/07/11 09:42:27 yasuoka 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 "dhcpd.h" 46 47 void 48 bootp(struct packet *packet) 49 { 50 struct host_decl *hp, *host = NULL; 51 struct packet outgoing; 52 struct dhcp_packet raw; 53 struct sockaddr_in to; 54 struct in_addr from; 55 struct tree_cache *options[256]; 56 struct shared_network *s; 57 struct subnet *subnet = NULL; 58 struct lease *lease; 59 struct iaddr ip_address; 60 int i; 61 62 if (packet->raw->op != BOOTREQUEST) 63 return; 64 65 note("BOOTREQUEST from %s via %s%s", print_hw_addr(packet->raw->htype, 66 packet->raw->hlen, packet->raw->chaddr), 67 packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) : 68 packet->interface->name, 69 packet->options_valid ? "" : " (non-rfc1048)"); 70 71 if (!locate_network(packet)) 72 return; 73 74 hp = find_hosts_by_haddr(packet->raw->htype, packet->raw->chaddr, 75 packet->raw->hlen); 76 77 s = packet->shared_network; 78 lease = find_lease(packet, s, 0); 79 80 /* 81 * Find an IP address in the host_decl that matches the specified 82 * network. 83 */ 84 if (hp) 85 subnet = find_host_for_network(&hp, &ip_address, s); 86 87 if (!subnet) { 88 /* 89 * We didn't find an applicable host declaration. Just in case 90 * we may be able to dynamically assign an address, see if 91 * there's a host declaration that doesn't have an ip address 92 * associated with it. 93 */ 94 if (hp) 95 for (; hp; hp = hp->n_ipaddr) 96 if (!hp->fixed_addr) { 97 host = hp; 98 break; 99 } 100 101 if (host && (!host->group->allow_booting)) { 102 note("Ignoring excluded BOOTP client %s", host->name ? 103 host->name : print_hw_addr (packet->raw->htype, 104 packet->raw->hlen, packet->raw->chaddr)); 105 return; 106 } 107 108 if (host && (!host->group->allow_bootp)) { 109 note("Ignoring BOOTP request from client %s", 110 host->name ? host->name : 111 print_hw_addr(packet->raw->htype, 112 packet->raw->hlen, packet->raw->chaddr)); 113 return; 114 } 115 116 /* 117 * If we've been told not to boot unknown clients, and we didn't 118 * find any host record for this client, ignore it. 119 */ 120 if (!host && !(s->group->boot_unknown_clients)) { 121 note("Ignoring unknown BOOTP client %s via %s", 122 print_hw_addr(packet->raw->htype, 123 packet->raw->hlen, packet->raw->chaddr), 124 packet->raw->giaddr.s_addr ? 125 inet_ntoa(packet->raw->giaddr) : 126 packet->interface->name); 127 return; 128 } 129 130 /* 131 * If we've been told not to boot with bootp on this network, 132 * ignore it. 133 */ 134 if (!host && !(s->group->allow_bootp)) { 135 note("Ignoring BOOTP request from client %s via %s", 136 print_hw_addr(packet->raw->htype, 137 packet->raw->hlen, packet->raw->chaddr), 138 packet->raw->giaddr.s_addr ? 139 inet_ntoa(packet->raw->giaddr) : 140 packet->interface->name); 141 return; 142 } 143 144 /* 145 * If the packet is from a host we don't know and there are no 146 * dynamic bootp addresses on the network it came in on, drop 147 * it on the floor. 148 */ 149 if (!(s->group->dynamic_bootp)) { 150 lose: 151 note("No applicable record for BOOTP host %s via %s", 152 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 a lease has already been assigned to this client and it's 162 * still okay to use dynamic bootp on that lease, reassign it. 163 */ 164 if (lease) { 165 /* 166 * If this lease can be used for dynamic bootp, do so. 167 */ 168 if ((lease->flags & DYNAMIC_BOOTP_OK)) { 169 /* 170 * If it's not a DYNAMIC_BOOTP lease, release it 171 * before reassigning it so that we don't get a 172 * lease conflict. 173 */ 174 if (!(lease->flags & BOOTP_LEASE)) 175 release_lease(lease); 176 177 lease->host = host; 178 ack_lease(packet, lease, 0, 0); 179 return; 180 } 181 182 /* 183 * If dynamic BOOTP is no longer allowed for this 184 * lease, set it free. 185 */ 186 release_lease(lease); 187 } 188 189 /* 190 * If there are dynamic bootp addresses that might be 191 * available, try to snag one. 192 */ 193 for (lease = s->last_lease; 194 lease && lease->ends <= cur_time; 195 lease = lease->prev) { 196 if ((lease->flags & DYNAMIC_BOOTP_OK)) { 197 lease->host = host; 198 ack_lease(packet, lease, 0, 0); 199 return; 200 } 201 } 202 goto lose; 203 } 204 205 /* Make sure we're allowed to boot this client. */ 206 if (hp && (!hp->group->allow_booting)) { 207 note("Ignoring excluded BOOTP client %s", hp->name); 208 return; 209 } 210 211 /* Make sure we're allowed to boot this client with bootp. */ 212 if (hp && (!hp->group->allow_bootp)) { 213 note("Ignoring BOOTP request from client %s", hp->name); 214 return; 215 } 216 217 /* Set up the outgoing packet... */ 218 memset(&outgoing, 0, sizeof outgoing); 219 memset(&raw, 0, sizeof raw); 220 outgoing.raw = &raw; 221 222 /* 223 * If we didn't get a known vendor magic number on the way in, just 224 * copy the input options to the output. 225 */ 226 if (!packet->options_valid && !subnet->group->always_reply_rfc1048 && 227 (!hp || !hp->group->always_reply_rfc1048)) { 228 memcpy(outgoing.raw->options, packet->raw->options, 229 DHCP_OPTION_LEN); 230 outgoing.packet_length = BOOTP_MIN_LEN; 231 } else { 232 struct tree_cache netmask_tree; /* -- RBF */ 233 234 /* 235 * Come up with a list of options that we want to send to this 236 * client. Start with the per-subnet options, and then override 237 * those with client-specific options. 238 */ 239 240 memcpy(options, subnet->group->options, sizeof(options)); 241 242 for (i = 0; i < 256; i++) 243 if (hp->group->options[i]) 244 options[i] = hp->group->options[i]; 245 246 /* 247 * Use the subnet mask from the subnet declaration if no other 248 * mask has been provided. 249 */ 250 if (!options[DHO_SUBNET_MASK]) { 251 options[DHO_SUBNET_MASK] = &netmask_tree; 252 netmask_tree.flags = TC_TEMPORARY; 253 netmask_tree.value = lease->subnet->netmask.iabuf; 254 netmask_tree.len = lease->subnet->netmask.len; 255 netmask_tree.buf_size = lease->subnet->netmask.len; 256 netmask_tree.timeout = -1; 257 netmask_tree.tree = NULL; 258 } 259 260 /* 261 * Pack the options into the buffer. Unlike DHCP, we can't pack 262 * options into the filename and server name buffers. 263 */ 264 265 outgoing.packet_length = cons_options(packet, outgoing.raw, 266 0, options, 0, 0, 1, NULL, 0); 267 268 if (outgoing.packet_length < BOOTP_MIN_LEN) 269 outgoing.packet_length = BOOTP_MIN_LEN; 270 } 271 272 /* Take the fields that we care about... */ 273 raw.op = BOOTREPLY; 274 raw.htype = packet->raw->htype; 275 raw.hlen = packet->raw->hlen; 276 memcpy(raw.chaddr, packet->raw->chaddr, sizeof(raw.chaddr)); 277 raw.hops = packet->raw->hops; 278 raw.xid = packet->raw->xid; 279 raw.secs = packet->raw->secs; 280 raw.flags = packet->raw->flags; 281 raw.ciaddr = packet->raw->ciaddr; 282 memcpy(&raw.yiaddr, ip_address.iabuf, sizeof(raw.yiaddr)); 283 284 /* Figure out the address of the next server. */ 285 if (hp && hp->group->next_server.len) 286 memcpy(&raw.siaddr, hp->group->next_server.iabuf, 4); 287 else if (subnet->group->next_server.len) 288 memcpy(&raw.siaddr, subnet->group->next_server.iabuf, 4); 289 else if (subnet->interface_address.len) 290 memcpy(&raw.siaddr, subnet->interface_address.iabuf, 4); 291 else 292 raw.siaddr = packet->interface->primary_address; 293 294 raw.giaddr = packet->raw->giaddr; 295 if (hp->group->server_name) 296 strncpy(raw.sname, hp->group->server_name, sizeof(raw.sname)); 297 else if (subnet->group->server_name) 298 strncpy(raw.sname, subnet->group->server_name, 299 sizeof(raw.sname)); 300 301 if (hp->group->filename) 302 strncpy(raw.file, hp->group->filename, sizeof(raw.file)); 303 else if (subnet->group->filename) 304 strncpy(raw.file, subnet->group->filename, sizeof(raw.file)); 305 else 306 memcpy(raw.file, packet->raw->file, sizeof(raw.file)); 307 308 from = packet->interface->primary_address; 309 310 /* Report what we're doing... */ 311 note("BOOTREPLY for %s to %s (%s) via %s", piaddr(ip_address), 312 hp->name, print_hw_addr(packet->raw->htype, packet->raw->hlen, 313 packet->raw->chaddr), packet->raw->giaddr.s_addr ? 314 inet_ntoa(packet->raw->giaddr) : packet->interface->name); 315 316 /* Set up the parts of the address that are in common. */ 317 memset(&to, 0, sizeof(to)); 318 to.sin_family = AF_INET; 319 #ifdef HAVE_SA_LEN 320 to.sin_len = sizeof(to); 321 #endif 322 323 /* If this was gatewayed, send it back to the gateway... */ 324 if (raw.giaddr.s_addr) { 325 to.sin_addr = raw.giaddr; 326 to.sin_port = server_port; 327 328 (void) packet->interface->send_packet(packet->interface, &raw, 329 outgoing.packet_length, from, &to, packet->haddr); 330 return; 331 } 332 333 /* 334 * If it comes from a client that already knows its address and is not 335 * requesting a broadcast response, and we can unicast to a client 336 * without using the ARP protocol, sent it directly to that client. 337 */ 338 else if (!(raw.flags & htons(BOOTP_BROADCAST))) { 339 to.sin_addr = raw.yiaddr; 340 to.sin_port = client_port; 341 } else { 342 /* Otherwise, broadcast it on the local network. */ 343 to.sin_addr.s_addr = INADDR_BROADCAST; 344 to.sin_port = client_port; /* XXX */ 345 } 346 347 errno = 0; 348 (void) packet->interface->send_packet(packet->interface, &raw, 349 outgoing.packet_length, from, &to, packet->haddr); 350 } 351