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