File: | src/usr.sbin/dhcpd/dhcp.c |
Warning: | line 699, column 2 Value stored to 'result' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: dhcp.c,v 1.57 2017/07/11 10:28:24 reyk Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1995, 1996, 1997, 1998, 1999 |
5 | * The Internet Software Consortium. All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * |
11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the |
15 | * documentation and/or other materials provided with the distribution. |
16 | * 3. Neither the name of The Internet Software Consortium nor the names |
17 | * of its contributors may be used to endorse or promote products derived |
18 | * from this software without specific prior written permission. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND |
21 | * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, |
22 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
23 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
24 | * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR |
25 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
26 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
27 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
28 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
29 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
31 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 | * SUCH DAMAGE. |
33 | * |
34 | * This software has been written for the Internet Software Consortium |
35 | * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie |
36 | * Enterprises. To learn more about the Internet Software Consortium, |
37 | * see ``http://www.vix.com/isc''. To learn more about Vixie |
38 | * Enterprises, see ``http://www.vix.com''. |
39 | */ |
40 | |
41 | #include <sys/types.h> |
42 | #include <sys/socket.h> |
43 | |
44 | #include <arpa/inet.h> |
45 | |
46 | #include <net/if.h> |
47 | |
48 | #include <netinet/in.h> |
49 | |
50 | #include <errno(*__errno()).h> |
51 | #include <stdio.h> |
52 | #include <stdlib.h> |
53 | #include <string.h> |
54 | |
55 | #include "dhcp.h" |
56 | #include "tree.h" |
57 | #include "dhcpd.h" |
58 | #include "log.h" |
59 | #include "sync.h" |
60 | |
61 | int outstanding_pings; |
62 | |
63 | static char dhcp_message[256]; |
64 | |
65 | void |
66 | dhcp(struct packet *packet, int is_udpsock) |
67 | { |
68 | if (!locate_network(packet) && packet->packet_type != DHCPREQUEST3) |
69 | return; |
70 | |
71 | if (is_udpsock && packet->packet_type != DHCPINFORM8) { |
72 | log_info("Unable to handle a DHCP message type=%d on UDP " |
73 | "socket", packet->packet_type); |
74 | return; |
75 | } |
76 | |
77 | switch (packet->packet_type) { |
78 | case DHCPDISCOVER1: |
79 | dhcpdiscover(packet); |
80 | break; |
81 | |
82 | case DHCPREQUEST3: |
83 | dhcprequest(packet); |
84 | break; |
85 | |
86 | case DHCPRELEASE7: |
87 | dhcprelease(packet); |
88 | break; |
89 | |
90 | case DHCPDECLINE4: |
91 | dhcpdecline(packet); |
92 | break; |
93 | |
94 | case DHCPINFORM8: |
95 | dhcpinform(packet); |
96 | break; |
97 | |
98 | default: |
99 | break; |
100 | } |
101 | } |
102 | |
103 | void |
104 | dhcpdiscover(struct packet *packet) |
105 | { |
106 | struct lease *lease = find_lease(packet, packet->shared_network, 0); |
107 | struct host_decl *hp; |
108 | |
109 | log_info("DHCPDISCOVER from %s via %s", |
110 | print_hw_addr(packet->raw->htype, packet->raw->hlen, |
111 | packet->raw->chaddr), |
112 | packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) : |
113 | packet->interface->name); |
114 | |
115 | /* Sourceless packets don't make sense here. */ |
116 | if (!packet->shared_network) { |
117 | log_info("Packet from unknown subnet: %s", |
118 | inet_ntoa(packet->raw->giaddr)); |
119 | return; |
120 | } |
121 | |
122 | /* If we didn't find a lease, try to allocate one... */ |
123 | if (!lease) { |
124 | lease = packet->shared_network->last_lease; |
125 | |
126 | /* |
127 | * If there are no leases in that subnet that have |
128 | * expired, we have nothing to offer this client. |
129 | */ |
130 | if (!lease || lease->ends > cur_time) { |
131 | log_info("no free leases on subnet %s", |
132 | packet->shared_network->name); |
133 | return; |
134 | } |
135 | |
136 | /* |
137 | * If we find an abandoned lease, take it, but print a |
138 | * warning message, so that if it continues to lose, |
139 | * the administrator will eventually investigate. |
140 | */ |
141 | if ((lease->flags & ABANDONED_LEASE16)) { |
142 | struct lease *lp; |
143 | |
144 | /* See if we can find an unabandoned lease first. */ |
145 | for (lp = lease; lp; lp = lp->prev) { |
146 | if (lp->ends > cur_time) |
147 | break; |
148 | if (!(lp->flags & ABANDONED_LEASE16)) { |
149 | lease = lp; |
150 | break; |
151 | } |
152 | } |
153 | |
154 | /* |
155 | * If we can't find an unabandoned lease, |
156 | * reclaim the abandoned lease. |
157 | */ |
158 | if ((lease->flags & ABANDONED_LEASE16)) { |
159 | log_warnx("Reclaiming abandoned IP address %s.", |
160 | piaddr(lease->ip_addr)); |
161 | lease->flags &= ~ABANDONED_LEASE16; |
162 | |
163 | pfmsg('L', lease); /* unabandon address */ |
164 | } |
165 | } |
166 | |
167 | /* Try to find a host_decl that matches the client |
168 | identifier or hardware address on the packet, and |
169 | has no fixed IP address. If there is one, hang |
170 | it off the lease so that its option definitions |
171 | can be used. */ |
172 | if (((packet->options[DHO_DHCP_CLIENT_IDENTIFIER61].len != 0) && |
173 | ((hp = find_hosts_by_uid( |
174 | packet->options[DHO_DHCP_CLIENT_IDENTIFIER61].data, |
175 | packet->options[DHO_DHCP_CLIENT_IDENTIFIER61].len)) != |
176 | NULL((void *)0))) || |
177 | ((hp = find_hosts_by_haddr(packet->raw->htype, |
178 | packet->raw->chaddr, packet->raw->hlen)) != NULL((void *)0))) { |
179 | for (; hp; hp = hp->n_ipaddr) { |
180 | if (!hp->fixed_addr) { |
181 | lease->host = hp; |
182 | break; |
183 | } |
184 | } |
185 | } else |
186 | lease->host = NULL((void *)0); |
187 | } |
188 | |
189 | /* If this subnet won't boot unknown clients, ignore the |
190 | request. */ |
191 | if (!lease->host && |
192 | !lease->subnet->group->boot_unknown_clients) { |
193 | log_info("Ignoring unknown client %s", |
194 | print_hw_addr(packet->raw->htype, packet->raw->hlen, |
195 | packet->raw->chaddr)); |
196 | } else if (lease->host && !lease->host->group->allow_booting) { |
197 | log_info("Declining to boot client %s", |
198 | lease->host->name ? lease->host->name : |
199 | print_hw_addr(packet->raw->htype, packet->raw->hlen, |
200 | packet->raw->chaddr)); |
201 | } else |
202 | ack_lease(packet, lease, DHCPOFFER2, cur_time + 120); |
203 | } |
204 | |
205 | void |
206 | dhcprequest(struct packet *packet) |
207 | { |
208 | struct lease *lease; |
209 | struct iaddr cip; |
210 | struct subnet *subnet; |
211 | int ours = 0; |
212 | |
213 | cip.len = 4; |
214 | if (packet->options[DHO_DHCP_REQUESTED_ADDRESS50].len == 4) |
215 | memcpy(cip.iabuf, |
216 | packet->options[DHO_DHCP_REQUESTED_ADDRESS50].data, 4); |
217 | else |
218 | memcpy(cip.iabuf, &packet->raw->ciaddr.s_addr, 4); |
219 | subnet = find_subnet(cip); |
220 | |
221 | /* Find the lease that matches the address requested by the client. */ |
222 | |
223 | if (subnet) |
224 | lease = find_lease(packet, subnet->shared_network, &ours); |
225 | else |
226 | lease = NULL((void *)0); |
227 | |
228 | log_info("DHCPREQUEST for %s from %s via %s", piaddr(cip), |
229 | print_hw_addr(packet->raw->htype, packet->raw->hlen, |
230 | packet->raw->chaddr), |
231 | packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) : |
232 | packet->interface->name); |
233 | |
234 | /* If a client on a given network REQUESTs a lease on an |
235 | * address on a different network, NAK it. If the Requested |
236 | * Address option was used, the protocol says that it must |
237 | * have been broadcast, so we can trust the source network |
238 | * information. |
239 | * |
240 | * If ciaddr was specified and Requested Address was not, then |
241 | * we really only know for sure what network a packet came from |
242 | * if it came through a BOOTP gateway - if it came through an |
243 | * IP router, we'll just have to assume that it's cool. |
244 | * |
245 | * If we don't think we know where the packet came from, it |
246 | * came through a gateway from an unknown network, so it's not |
247 | * from a RENEWING client. If we recognize the network it |
248 | * *thinks* it's on, we can NAK it even though we don't |
249 | * recognize the network it's *actually* on; otherwise we just |
250 | * have to ignore it. |
251 | * |
252 | * We don't currently try to take advantage of access to the |
253 | * raw packet, because it's not available on all platforms. |
254 | * So a packet that was unicast to us through a router from a |
255 | * RENEWING client is going to look exactly like a packet that |
256 | * was broadcast to us from an INIT-REBOOT client. |
257 | * |
258 | * Since we can't tell the difference between these two kinds |
259 | * of packets, if the packet appears to have come in off the |
260 | * local wire, we have to treat it as if it's a RENEWING |
261 | * client. This means that we can't NAK a RENEWING client on |
262 | * the local wire that has a bogus address. The good news is |
263 | * that we won't ACK it either, so it should revert to INIT |
264 | * state and send us a DHCPDISCOVER, which we *can* work with. |
265 | * |
266 | * Because we can't detect that a RENEWING client is on the |
267 | * wrong wire, it's going to sit there trying to renew until |
268 | * it gets to the REBIND state, when we *can* NAK it because |
269 | * the packet will get to us through a BOOTP gateway. We |
270 | * shouldn't actually see DHCPREQUEST packets from RENEWING |
271 | * clients on the wrong wire anyway, since their idea of their |
272 | * local router will be wrong. In any case, the protocol |
273 | * doesn't really allow us to NAK a DHCPREQUEST from a |
274 | * RENEWING client, so we can punt on this issue. |
275 | */ |
276 | if (!packet->shared_network || |
277 | (packet->raw->ciaddr.s_addr && packet->raw->giaddr.s_addr) || |
278 | (packet->options[DHO_DHCP_REQUESTED_ADDRESS50].len == 4 && |
279 | !packet->raw->ciaddr.s_addr)) { |
280 | |
281 | /* |
282 | * If we don't know where it came from but we do know |
283 | * where it claims to have come from, it didn't come |
284 | * from there. Fry it. |
285 | */ |
286 | if (!packet->shared_network) { |
287 | if (subnet && |
288 | subnet->shared_network->group->authoritative) { |
289 | nak_lease(packet, &cip); |
290 | return; |
291 | } |
292 | /* Otherwise, ignore it. */ |
293 | return; |
294 | } |
295 | |
296 | /* |
297 | * If we do know where it came from and it asked for an |
298 | * address that is not on that shared network, nak it. |
299 | */ |
300 | subnet = find_grouped_subnet(packet->shared_network, cip); |
301 | if (!subnet) { |
302 | if (packet->shared_network->group->authoritative) |
303 | nak_lease(packet, &cip); |
304 | return; |
305 | } |
306 | } |
307 | |
308 | /* |
309 | * If we found a lease for the client but it's not the one the |
310 | * client asked for, don't send it - some other server probably |
311 | * made the cut. |
312 | */ |
313 | if (lease && !addr_eq(lease->ip_addr, cip)) { |
314 | /* |
315 | * If we found the address the client asked for, but |
316 | * it wasn't what got picked, the lease belongs to us, |
317 | * so we should NAK it. |
318 | */ |
319 | if (ours) |
320 | nak_lease(packet, &cip); |
321 | return; |
322 | } |
323 | |
324 | /* |
325 | * If the address the client asked for is ours, but it wasn't |
326 | * available for the client, NAK it. |
327 | */ |
328 | if (!lease && ours) { |
329 | nak_lease(packet, &cip); |
330 | return; |
331 | } |
332 | |
333 | /* If we're not allowed to serve this client anymore, don't. */ |
334 | if (lease && !lease->host && |
335 | !lease->subnet->group->boot_unknown_clients) { |
336 | log_info("Ignoring unknown client %s", |
337 | print_hw_addr(packet->raw->htype, packet->raw->hlen, |
338 | packet->raw->chaddr)); |
339 | return; |
340 | } else if (lease && lease->host && !lease->host->group->allow_booting) |
341 | { |
342 | log_info("Declining to renew client %s", |
343 | lease->host->name ? lease->host->name : |
344 | print_hw_addr(packet->raw->htype, packet->raw->hlen, |
345 | packet->raw->chaddr)); |
346 | return; |
347 | } |
348 | |
349 | /* |
350 | * If we own the lease that the client is asking for, |
351 | * and it's already been assigned to the client, ack it. |
352 | */ |
353 | if (lease && |
354 | ((lease->uid_len && lease->uid_len == |
355 | packet->options[DHO_DHCP_CLIENT_IDENTIFIER61].len && |
356 | !memcmp(packet->options[DHO_DHCP_CLIENT_IDENTIFIER61].data, |
357 | lease->uid, lease->uid_len)) || |
358 | (lease->hardware_addr.hlen == packet->raw->hlen && |
359 | lease->hardware_addr.htype == packet->raw->htype && |
360 | !memcmp(lease->hardware_addr.haddr, packet->raw->chaddr, |
361 | packet->raw->hlen)))) { |
362 | ack_lease(packet, lease, DHCPACK5, 0); |
363 | sync_lease(lease); |
364 | return; |
365 | } |
366 | |
367 | /* |
368 | * At this point, the client has requested a lease, and it's |
369 | * available, but it wasn't assigned to the client, which |
370 | * means that the client probably hasn't gone through the |
371 | * DHCPDISCOVER part of the protocol. We are within our |
372 | * rights to send a DHCPNAK. We can also send a DHCPACK. |
373 | * The thing we probably should not do is to remain silent. |
374 | * For now, we'll just assign the lease to the client anyway. |
375 | */ |
376 | if (lease) { |
377 | ack_lease(packet, lease, DHCPACK5, 0); |
378 | sync_lease(lease); |
379 | } |
380 | } |
381 | |
382 | void |
383 | dhcprelease(struct packet *packet) |
384 | { |
385 | char ciaddrbuf[INET_ADDRSTRLEN16]; |
386 | struct lease *lease; |
387 | struct iaddr cip; |
388 | int i; |
389 | |
390 | /* |
391 | * DHCPRELEASE must not specify address in requested-address |
392 | * option, but old protocol specs weren't explicit about this, |
393 | * so let it go. |
394 | */ |
395 | if (packet->options[DHO_DHCP_REQUESTED_ADDRESS50].len) { |
396 | log_info("DHCPRELEASE from %s specified requested-address.", |
397 | print_hw_addr(packet->raw->htype, packet->raw->hlen, |
398 | packet->raw->chaddr)); |
399 | } |
400 | |
401 | i = DHO_DHCP_CLIENT_IDENTIFIER61; |
402 | if (packet->options[i].len) { |
403 | lease = find_lease_by_uid(packet->options[i].data, |
404 | packet->options[i].len); |
405 | |
406 | /* |
407 | * See if we can find a lease that matches the |
408 | * IP address the client is claiming. |
409 | */ |
410 | for (; lease; lease = lease->n_uid) { |
411 | if (!memcmp(&packet->raw->ciaddr, |
412 | lease->ip_addr.iabuf, 4)) { |
413 | break; |
414 | } |
415 | } |
416 | } else { |
417 | /* |
418 | * The client is supposed to pass a valid client-identifier, |
419 | * but the spec on this has changed historically, so try the |
420 | * IP address in ciaddr if the client-identifier fails. |
421 | */ |
422 | cip.len = 4; |
423 | memcpy(cip.iabuf, &packet->raw->ciaddr, 4); |
424 | lease = find_lease_by_ip_addr(cip); |
425 | } |
426 | |
427 | /* Can't do >1 inet_ntoa() in a printf()! */ |
428 | strlcpy(ciaddrbuf, inet_ntoa(packet->raw->ciaddr), sizeof(ciaddrbuf)); |
429 | |
430 | log_info("DHCPRELEASE of %s from %s via %s (%sfound)", |
431 | ciaddrbuf, |
432 | print_hw_addr(packet->raw->htype, packet->raw->hlen, |
433 | packet->raw->chaddr), |
434 | packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) : |
435 | packet->interface->name, |
436 | lease ? "" : "not "); |
437 | |
438 | /* If we're already acking this lease, don't do it again. */ |
439 | if (lease && lease->state) { |
440 | log_info("DHCPRELEASE already acking lease %s", |
441 | piaddr(lease->ip_addr)); |
442 | return; |
443 | } |
444 | |
445 | /* If we found a lease, release it. */ |
446 | if (lease && lease->ends > cur_time) { |
447 | /* |
448 | * First, we ping this lease to see if it's still |
449 | * there. if it is, we don't release it. This avoids |
450 | * the problem of spoofed releases being used to liberate |
451 | * addresses from the server. |
452 | */ |
453 | if (!lease->releasing) { |
454 | log_info("DHCPRELEASE of %s from %s via %s (found)", |
455 | ciaddrbuf, |
456 | print_hw_addr(packet->raw->htype, |
457 | packet->raw->hlen, packet->raw->chaddr), |
458 | packet->raw->giaddr.s_addr ? |
459 | inet_ntoa(packet->raw->giaddr) : |
460 | packet->interface->name); |
461 | |
462 | lease->releasing = 1; |
463 | add_timeout(cur_time + 1, lease_ping_timeout, lease); |
464 | icmp_echorequest(&(lease->ip_addr)); |
465 | ++outstanding_pings; |
466 | } else { |
467 | log_info("DHCPRELEASE of %s from %s via %s ignored " |
468 | "(release already pending)", |
469 | ciaddrbuf, |
470 | print_hw_addr(packet->raw->htype, |
471 | packet->raw->hlen, packet->raw->chaddr), |
472 | packet->raw->giaddr.s_addr ? |
473 | inet_ntoa(packet->raw->giaddr) : |
474 | packet->interface->name); |
475 | } |
476 | } else { |
477 | log_info("DHCPRELEASE of %s from %s via %s for nonexistent " |
478 | "lease", ciaddrbuf, print_hw_addr(packet->raw->htype, |
479 | packet->raw->hlen, packet->raw->chaddr), |
480 | packet->raw->giaddr.s_addr ? |
481 | inet_ntoa(packet->raw->giaddr) : packet->interface->name); |
482 | } |
483 | } |
484 | |
485 | void |
486 | dhcpdecline(struct packet *packet) |
487 | { |
488 | struct lease *lease; |
489 | struct iaddr cip; |
490 | |
491 | /* DHCPDECLINE must specify address. */ |
492 | if (packet->options[DHO_DHCP_REQUESTED_ADDRESS50].len != 4) |
493 | return; |
494 | |
495 | cip.len = 4; |
496 | memcpy(cip.iabuf, |
497 | packet->options[DHO_DHCP_REQUESTED_ADDRESS50].data, 4); |
498 | lease = find_lease_by_ip_addr(cip); |
499 | |
500 | log_info("DHCPDECLINE on %s from %s via %s", |
501 | piaddr(cip), print_hw_addr(packet->raw->htype, |
502 | packet->raw->hlen, packet->raw->chaddr), |
503 | packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) : |
504 | packet->interface->name); |
505 | |
506 | /* If we're already acking this lease, don't do it again. */ |
507 | if (lease && lease->state) { |
508 | log_info("DHCPDECLINE already acking lease %s", |
509 | piaddr(lease->ip_addr)); |
510 | return; |
511 | } |
512 | |
513 | /* If we found a lease, mark it as unusable and complain. */ |
514 | if (lease) |
515 | abandon_lease(lease, "declined."); |
516 | } |
517 | |
518 | void |
519 | dhcpinform(struct packet *packet) |
520 | { |
521 | struct lease lease; |
522 | struct iaddr cip; |
523 | struct subnet *subnet; |
524 | |
525 | /* |
526 | * ciaddr should be set to client's IP address but |
527 | * not all clients are standards compliant. |
528 | */ |
529 | cip.len = 4; |
530 | if (packet->raw->ciaddr.s_addr && !packet->raw->giaddr.s_addr) { |
531 | if (memcmp(&packet->raw->ciaddr.s_addr, |
532 | packet->client_addr.iabuf, 4) != 0) { |
533 | log_info("DHCPINFORM from %s but ciaddr %s is not " |
534 | "consistent with actual address", |
535 | piaddr(packet->client_addr), |
536 | inet_ntoa(packet->raw->ciaddr)); |
537 | return; |
538 | } |
539 | memcpy(cip.iabuf, &packet->raw->ciaddr.s_addr, 4); |
540 | } else |
541 | memcpy(cip.iabuf, &packet->client_addr.iabuf, 4); |
542 | |
543 | log_info("DHCPINFORM from %s", piaddr(cip)); |
544 | |
545 | /* Find the lease that matches the address requested by the client. */ |
546 | subnet = find_subnet(cip); |
547 | if (!subnet) |
548 | return; |
549 | |
550 | /* Sourceless packets don't make sense here. */ |
551 | if (!subnet->shared_network) { |
552 | log_info("Packet from unknown subnet: %s", |
553 | inet_ntoa(packet->raw->giaddr)); |
554 | return; |
555 | } |
556 | |
557 | /* Use a fake lease entry */ |
558 | memset(&lease, 0, sizeof(lease)); |
559 | lease.subnet = subnet; |
560 | lease.shared_network = subnet->shared_network; |
561 | |
562 | if (packet->options[DHO_DHCP_CLIENT_IDENTIFIER61].len) |
563 | lease.host = find_hosts_by_uid( |
564 | packet->options[DHO_DHCP_CLIENT_IDENTIFIER61].data, |
565 | packet->options[DHO_DHCP_CLIENT_IDENTIFIER61].len); |
566 | |
567 | lease.starts = lease.timestamp = lease.ends = MIN_TIME0; |
568 | lease.flags = INFORM_NOLEASE32; |
569 | ack_lease(packet, &lease, DHCPACK5, 0); |
570 | if (lease.state != NULL((void *)0)) |
571 | free_lease_state(lease.state, "ack_lease"); |
572 | } |
573 | |
574 | void |
575 | nak_lease(struct packet *packet, struct iaddr *cip) |
576 | { |
577 | struct sockaddr_in to; |
578 | struct in_addr from; |
579 | ssize_t result; |
580 | int i; |
581 | struct dhcp_packet raw; |
582 | unsigned char nak = DHCPNAK6; |
583 | struct packet outgoing; |
584 | struct tree_cache *options[256]; |
585 | struct tree_cache dhcpnak_tree, dhcpmsg_tree; |
586 | struct tree_cache client_tree, server_tree; |
587 | |
588 | memset(options, 0, sizeof options); |
589 | memset(&outgoing, 0, sizeof outgoing); |
590 | memset(&raw, 0, sizeof raw); |
591 | outgoing.raw = &raw; |
592 | |
593 | /* Set DHCP_MESSAGE_TYPE to DHCPNAK */ |
594 | i = DHO_DHCP_MESSAGE_TYPE53; |
595 | options[i] = &dhcpnak_tree; |
596 | options[i]->value = &nak; |
597 | options[i]->len = sizeof nak; |
598 | options[i]->buf_size = sizeof nak; |
599 | options[i]->timeout = -1; |
600 | options[i]->tree = NULL((void *)0); |
601 | options[i]->flags = 0; |
602 | |
603 | /* Set DHCP_MESSAGE to whatever the message is */ |
604 | i = DHO_DHCP_MESSAGE56; |
605 | options[i] = &dhcpmsg_tree; |
606 | options[i]->value = (unsigned char *)dhcp_message; |
607 | options[i]->len = strlen(dhcp_message); |
608 | options[i]->buf_size = strlen(dhcp_message); |
609 | options[i]->timeout = -1; |
610 | options[i]->tree = NULL((void *)0); |
611 | options[i]->flags = 0; |
612 | |
613 | /* Include server identifier in the NAK. At least one |
614 | * router vendor depends on it when using dhcp relay proxy mode. |
615 | */ |
616 | i = DHO_DHCP_SERVER_IDENTIFIER54; |
617 | if (packet->options[i].len) { |
618 | options[i] = &server_tree; |
619 | options[i]->value = packet->options[i].data, |
620 | options[i]->len = packet->options[i].len; |
621 | options[i]->buf_size = packet->options[i].len; |
622 | options[i]->timeout = -1; |
623 | options[i]->tree = NULL((void *)0); |
624 | options[i]->flags = 0; |
625 | } |
626 | |
627 | /* Echo back the client-identifier as RFC 6842 mandates. */ |
628 | i = DHO_DHCP_CLIENT_IDENTIFIER61; |
629 | if (packet->options[i].len) { |
630 | options[i] = &client_tree; |
631 | options[i]->value = packet->options[i].data, |
632 | options[i]->len = packet->options[i].len; |
633 | options[i]->buf_size = packet->options[i].len; |
634 | options[i]->timeout = -1; |
635 | options[i]->tree = NULL((void *)0); |
636 | options[i]->flags = 0; |
637 | } |
638 | |
639 | /* Do not use the client's requested parameter list. */ |
640 | i = DHO_DHCP_PARAMETER_REQUEST_LIST55; |
641 | if (packet->options[i].data) { |
642 | packet->options[i].len = 0; |
643 | free(packet->options[i].data); |
644 | packet->options[i].data = NULL((void *)0); |
645 | } |
646 | |
647 | /* Set up the option buffer... */ |
648 | outgoing.packet_length = cons_options(packet, outgoing.raw, |
649 | 0, options, 0, 0, 0, NULL((void *)0), 0); |
650 | |
651 | /* memset(&raw.ciaddr, 0, sizeof raw.ciaddr);*/ |
652 | raw.siaddr = packet->interface->primary_address; |
653 | raw.giaddr = packet->raw->giaddr; |
654 | memcpy(raw.chaddr, packet->raw->chaddr, sizeof raw.chaddr); |
655 | raw.hlen = packet->raw->hlen; |
656 | raw.htype = packet->raw->htype; |
657 | raw.xid = packet->raw->xid; |
658 | raw.secs = packet->raw->secs; |
659 | raw.flags = packet->raw->flags | htons(BOOTP_BROADCAST)(__uint16_t)(__builtin_constant_p(32768L) ? (__uint16_t)(((__uint16_t )(32768L) & 0xffU) << 8 | ((__uint16_t)(32768L) & 0xff00U) >> 8) : __swap16md(32768L)); |
660 | raw.hops = packet->raw->hops; |
661 | raw.op = BOOTREPLY2; |
662 | |
663 | /* Report what we're sending... */ |
664 | log_info("DHCPNAK on %s to %s via %s", piaddr(*cip), |
665 | print_hw_addr(packet->raw->htype, packet->raw->hlen, |
666 | packet->raw->chaddr), packet->raw->giaddr.s_addr ? |
667 | inet_ntoa(packet->raw->giaddr) : packet->interface->name); |
668 | |
669 | /* Set up the common stuff... */ |
670 | memset(&to, 0, sizeof to); |
671 | to.sin_family = AF_INET2; |
672 | to.sin_len = sizeof to; |
673 | |
674 | from = packet->interface->primary_address; |
675 | |
676 | /* Make sure that the packet is at least as big as a BOOTP packet. */ |
677 | if (outgoing.packet_length < BOOTP_MIN_LEN300) |
678 | outgoing.packet_length = BOOTP_MIN_LEN300; |
679 | |
680 | /* |
681 | * If this was gatewayed, send it back to the gateway. |
682 | * Otherwise, broadcast it on the local network. |
683 | */ |
684 | if (raw.giaddr.s_addr) { |
685 | to.sin_addr = raw.giaddr; |
686 | to.sin_port = server_port; |
687 | |
688 | result = packet->interface->send_packet(packet->interface, &raw, |
689 | outgoing.packet_length, from, &to, packet->haddr); |
690 | if (result == -1) |
691 | log_warn("send_fallback"); |
692 | return; |
693 | } else { |
694 | to.sin_addr.s_addr = htonl(INADDR_BROADCAST)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0xffffffff))) ? (__uint32_t)(((__uint32_t)(((u_int32_t)(0xffffffff))) & 0xff ) << 24 | ((__uint32_t)(((u_int32_t)(0xffffffff))) & 0xff00) << 8 | ((__uint32_t)(((u_int32_t)(0xffffffff)) ) & 0xff0000) >> 8 | ((__uint32_t)(((u_int32_t)(0xffffffff ))) & 0xff000000) >> 24) : __swap32md(((u_int32_t)( 0xffffffff)))); |
695 | to.sin_port = client_port; |
696 | } |
697 | |
698 | errno(*__errno()) = 0; |
699 | result = packet->interface->send_packet(packet->interface, &raw, |
Value stored to 'result' is never read | |
700 | outgoing.packet_length, from, &to, NULL((void *)0)); |
701 | } |
702 | |
703 | void |
704 | ack_lease(struct packet *packet, struct lease *lease, unsigned int offer, |
705 | time_t when) |
706 | { |
707 | struct lease lt; |
708 | struct lease_state *state; |
709 | time_t lease_time, offered_lease_time, max_lease_time, default_lease_time; |
710 | struct class *vendor_class, *user_class; |
711 | int ulafdr, echo_client_id, i; |
712 | |
713 | /* If we're already acking this lease, don't do it again. */ |
714 | if (lease->state) { |
715 | if ((lease->flags & STATIC_LEASE1) || |
716 | cur_time - lease->timestamp < 60) { |
717 | log_info("already acking lease %s", |
718 | piaddr(lease->ip_addr)); |
719 | return; |
720 | } |
721 | free_lease_state(lease->state, "ACK timed out"); |
722 | lease->state = NULL((void *)0); |
723 | } |
724 | |
725 | i = DHO_DHCP_CLASS_IDENTIFIER60; |
726 | if (packet->options[i].len) { |
727 | vendor_class = find_class(0, packet->options[i].data, |
728 | packet->options[i].len); |
729 | } else |
730 | vendor_class = NULL((void *)0); |
731 | |
732 | i = DHO_DHCP_USER_CLASS_ID77; |
733 | if (packet->options[i].len) { |
734 | user_class = find_class(1, packet->options[i].data, |
735 | packet->options[i].len); |
736 | } else |
737 | user_class = NULL((void *)0); |
738 | |
739 | /* |
740 | * If there is not a specific host entry, and either the |
741 | * vendor class or user class (if they exist) deny booting, |
742 | * then bug out. |
743 | */ |
744 | if (!lease->host) { |
745 | if (vendor_class && !vendor_class->group->allow_booting) { |
746 | log_debug("Booting denied by vendor class"); |
747 | return; |
748 | } |
749 | |
750 | if (user_class && !user_class->group->allow_booting) { |
751 | log_debug("Booting denied by user class"); |
752 | return; |
753 | } |
754 | } |
755 | |
756 | /* Allocate a lease state structure... */ |
757 | state = new_lease_state("ack_lease"); |
758 | if (!state) |
759 | fatalx("unable to allocate lease state!"); |
760 | memset(state, 0, sizeof *state); |
761 | state->got_requested_address = packet->got_requested_address; |
762 | state->shared_network = packet->interface->shared_network; |
763 | |
764 | /* Remember if we got a server identifier option. */ |
765 | i = DHO_DHCP_SERVER_IDENTIFIER54; |
766 | if (packet->options[i].len) |
767 | state->got_server_identifier = 1; |
768 | |
769 | /* Replace the old lease hostname with the new one, if it's changed. */ |
770 | i = DHO_HOST_NAME12; |
771 | if (packet->options[i].len && lease->client_hostname && |
772 | (strlen(lease->client_hostname) == packet->options[i].len) && |
773 | !memcmp(lease->client_hostname, packet->options[i].data, |
774 | packet->options[i].len)) { |
775 | } else if (packet->options[i].len) { |
776 | free(lease->client_hostname); |
777 | lease->client_hostname = malloc( packet->options[i].len + 1); |
778 | if (!lease->client_hostname) |
779 | fatalx("no memory for client hostname.\n"); |
780 | memcpy(lease->client_hostname, packet->options[i].data, |
781 | packet->options[i].len); |
782 | lease->client_hostname[packet->options[i].len] = 0; |
783 | } else if (lease->client_hostname) { |
784 | free(lease->client_hostname); |
785 | lease->client_hostname = 0; |
786 | } |
787 | |
788 | /* Replace the lease client identifier with a new one. */ |
789 | i = DHO_DHCP_CLIENT_IDENTIFIER61; |
790 | if (packet->options[i].len && lease->client_identifier && |
791 | lease->client_identifier_len == packet->options[i].len && |
792 | !memcmp(lease->client_identifier, packet->options[i].data, |
793 | packet->options[i].len)) { |
794 | /* Same client identifier. */ |
795 | } else if (packet->options[i].len) { |
796 | free(lease->client_identifier); |
797 | lease->client_identifier = malloc(packet->options[i].len); |
798 | if (!lease->client_identifier) |
799 | fatalx("no memory for client identifier.\n"); |
800 | lease->client_identifier_len = packet->options[i].len; |
801 | memcpy(lease->client_identifier, packet->options[i].data, |
802 | packet->options[i].len); |
803 | } else if (lease->client_identifier) { |
804 | free(lease->client_identifier); |
805 | lease->client_identifier = NULL((void *)0); |
806 | lease->client_identifier_len = 0; |
807 | } |
808 | |
809 | /* |
810 | * Choose a filename; first from the host_decl, if any, then from |
811 | * the user class, then from the vendor class. |
812 | */ |
813 | if (lease->host && lease->host->group->filename) |
814 | strlcpy(state->filename, lease->host->group->filename, |
815 | sizeof state->filename); |
816 | else if (user_class && user_class->group->filename) |
817 | strlcpy(state->filename, user_class->group->filename, |
818 | sizeof state->filename); |
819 | else if (vendor_class && vendor_class->group->filename) |
820 | strlcpy(state->filename, vendor_class->group->filename, |
821 | sizeof state->filename); |
822 | else if (packet->raw->file[0]) |
823 | strlcpy(state->filename, packet->raw->file, |
824 | sizeof state->filename); |
825 | else if (lease->subnet->group->filename) |
826 | strlcpy(state->filename, lease->subnet->group->filename, |
827 | sizeof state->filename); |
828 | else |
829 | strlcpy(state->filename, "", sizeof state->filename); |
830 | |
831 | /* Choose a server name as above. */ |
832 | if (lease->host && lease->host->group->server_name) |
833 | state->server_name = lease->host->group->server_name; |
834 | else if (user_class && user_class->group->server_name) |
835 | state->server_name = user_class->group->server_name; |
836 | else if (vendor_class && vendor_class->group->server_name) |
837 | state->server_name = vendor_class->group->server_name; |
838 | else if (lease->subnet->group->server_name) |
839 | state->server_name = lease->subnet->group->server_name; |
840 | else state->server_name = NULL((void *)0); |
841 | |
842 | /* |
843 | * At this point, we have a lease that we can offer the client. |
844 | * Now we construct a lease structure that contains what we want, |
845 | * and call supersede_lease to do the right thing with it. |
846 | */ |
847 | memset(<, 0, sizeof lt); |
848 | |
849 | /* |
850 | * Use the ip address of the lease that we finally found in |
851 | * the database. |
852 | */ |
853 | lt.ip_addr = lease->ip_addr; |
854 | |
855 | /* Start now. */ |
856 | lt.starts = cur_time; |
857 | |
858 | /* Figure out maximum lease time. */ |
859 | if (lease->host && lease->host->group->max_lease_time) |
860 | max_lease_time = lease->host->group->max_lease_time; |
861 | else |
862 | max_lease_time = lease->subnet->group->max_lease_time; |
863 | |
864 | /* Figure out default lease time. */ |
865 | if (lease->host && lease->host->group->default_lease_time) |
866 | default_lease_time = lease->host->group->default_lease_time; |
867 | else |
868 | default_lease_time = lease->subnet->group->default_lease_time; |
869 | |
870 | /* |
871 | * Figure out how long a lease to assign. If this is a |
872 | * dynamic BOOTP lease, its duration must be infinite. |
873 | */ |
874 | if (offer) { |
875 | i = DHO_DHCP_LEASE_TIME51; |
876 | if (packet->options[i].len == 4) { |
877 | lease_time = getULong( packet->options[i].data); |
878 | |
879 | /* |
880 | * Don't let the client ask for a longer lease than |
881 | * is supported for this subnet or host. |
882 | * |
883 | * time_t is signed, so really large numbers come |
884 | * back as negative. Don't allow lease_time of 0, |
885 | * either. |
886 | */ |
887 | if (lease_time < 1 || lease_time > max_lease_time) |
888 | lease_time = max_lease_time; |
889 | } else |
890 | lease_time = default_lease_time; |
891 | |
892 | state->offered_expiry = cur_time + lease_time; |
893 | if (when) |
894 | lt.ends = when; |
895 | else |
896 | lt.ends = state->offered_expiry; |
897 | } else { |
898 | if (lease->host && |
899 | lease->host->group->bootp_lease_length) |
900 | lt.ends = (cur_time + |
901 | lease->host->group->bootp_lease_length); |
902 | else if (lease->subnet->group->bootp_lease_length) |
903 | lt.ends = (cur_time + |
904 | lease->subnet->group->bootp_lease_length); |
905 | else if (lease->host && |
906 | lease->host->group->bootp_lease_cutoff) |
907 | lt.ends = lease->host->group->bootp_lease_cutoff; |
908 | else |
909 | lt.ends = lease->subnet->group->bootp_lease_cutoff; |
910 | state->offered_expiry = lt.ends; |
911 | lt.flags = BOOTP_LEASE2; |
912 | } |
913 | |
914 | /* Record the uid, if given... */ |
915 | i = DHO_DHCP_CLIENT_IDENTIFIER61; |
916 | if (packet->options[i].len) { |
917 | if (packet->options[i].len <= sizeof lt.uid_buf) { |
918 | memcpy(lt.uid_buf, packet->options[i].data, |
919 | packet->options[i].len); |
920 | lt.uid = lt.uid_buf; |
921 | lt.uid_max = sizeof lt.uid_buf; |
922 | lt.uid_len = packet->options[i].len; |
923 | } else { |
924 | lt.uid_max = lt.uid_len = packet->options[i].len; |
925 | lt.uid = malloc(lt.uid_max); |
926 | if (!lt.uid) |
927 | fatalx("can't allocate memory for large uid."); |
928 | memcpy(lt.uid, packet->options[i].data, lt.uid_len); |
929 | } |
930 | } |
931 | |
932 | lt.host = lease->host; |
933 | lt.subnet = lease->subnet; |
934 | lt.shared_network = lease->shared_network; |
935 | |
936 | /* Don't call supersede_lease on a mocked-up lease. */ |
937 | if (lease->flags & (STATIC_LEASE1 | INFORM_NOLEASE32)) { |
938 | /* Copy the hardware address into the static lease |
939 | structure. */ |
940 | lease->hardware_addr.hlen = packet->raw->hlen; |
941 | lease->hardware_addr.htype = packet->raw->htype; |
942 | memcpy(lease->hardware_addr.haddr, packet->raw->chaddr, |
943 | sizeof packet->raw->chaddr); /* XXX */ |
944 | } else { |
945 | /* Record the hardware address, if given... */ |
946 | lt.hardware_addr.hlen = packet->raw->hlen; |
947 | lt.hardware_addr.htype = packet->raw->htype; |
948 | memcpy(lt.hardware_addr.haddr, packet->raw->chaddr, |
949 | sizeof packet->raw->chaddr); |
950 | |
951 | /* Install the new information about this lease in the |
952 | database. If this is a DHCPACK or a dynamic BOOTREPLY |
953 | and we can't write the lease, don't ACK it (or BOOTREPLY |
954 | it) either. */ |
955 | |
956 | if (!(supersede_lease(lease, <, !offer || |
957 | offer == DHCPACK5) || (offer && offer != DHCPACK5))) { |
958 | free_lease_state(state, "ack_lease: !supersede_lease"); |
959 | return; |
960 | } |
961 | } |
962 | |
963 | /* Remember the interface on which the packet arrived. */ |
964 | state->ip = packet->interface; |
965 | |
966 | /* Set a flag if this client is a lame Microsoft client that NUL |
967 | terminates string options and expects us to do likewise. */ |
968 | i = DHO_HOST_NAME12; |
969 | if (packet->options[i].len && |
970 | packet->options[i].data[packet->options[i].len - 1] == '\0') |
971 | lease->flags |= MS_NULL_TERMINATION8; |
972 | else |
973 | lease->flags &= ~MS_NULL_TERMINATION8; |
974 | |
975 | /* Remember the giaddr, xid, secs, flags and hops. */ |
976 | state->giaddr = packet->raw->giaddr; |
977 | state->ciaddr = packet->raw->ciaddr; |
978 | state->xid = packet->raw->xid; |
979 | state->secs = packet->raw->secs; |
980 | state->bootp_flags = packet->raw->flags; |
981 | state->hops = packet->raw->hops; |
982 | state->offer = offer; |
983 | memcpy(&state->haddr, packet->haddr, sizeof state->haddr); |
984 | |
985 | /* Figure out what options to send to the client: */ |
986 | |
987 | /* Start out with the subnet options... */ |
988 | memcpy(state->options, lease->subnet->group->options, |
989 | sizeof state->options); |
990 | |
991 | /* Vendor and user classes are only supported for DHCP clients. */ |
992 | if (state->offer) { |
993 | /* If we have a vendor class, install those options, |
994 | superseding any subnet options. */ |
995 | if (vendor_class) { |
996 | for (i = 0; i < 256; i++) |
997 | if (vendor_class->group->options[i]) |
998 | state->options[i] = |
999 | vendor_class->group->options[i]; |
1000 | } |
1001 | |
1002 | /* If we have a user class, install those options, |
1003 | superseding any subnet and vendor class options. */ |
1004 | if (user_class) { |
1005 | for (i = 0; i < 256; i++) |
1006 | if (user_class->group->options[i]) |
1007 | state->options[i] = |
1008 | user_class->group->options[i]; |
1009 | } |
1010 | |
1011 | } |
1012 | |
1013 | /* If we have a host_decl structure, install the associated |
1014 | options, superseding anything that's in the way. */ |
1015 | if (lease->host) { |
1016 | for (i = 0; i < 256; i++) |
1017 | if (lease->host->group->options[i]) |
1018 | state->options[i] = |
1019 | lease->host->group->options[i]; |
1020 | } |
1021 | |
1022 | /* Get the Maximum Message Size option from the packet, if one |
1023 | was sent. */ |
1024 | i = DHO_DHCP_MAX_MESSAGE_SIZE57; |
1025 | if (packet->options[i].data && |
1026 | packet->options[i].len == sizeof(u_int16_t)) |
1027 | state->max_message_size = getUShort(packet->options[i].data); |
1028 | /* Otherwise, if a maximum message size was specified, use that. */ |
1029 | else if (state->options[i] && state->options[i]->value) |
1030 | state->max_message_size = getUShort(state->options[i]->value); |
1031 | |
1032 | /* Save the parameter request list if there is one. */ |
1033 | i = DHO_DHCP_PARAMETER_REQUEST_LIST55; |
1034 | if (packet->options[i].data) { |
1035 | state->prl = calloc(1, packet->options[i].len); |
1036 | if (!state->prl) |
1037 | log_warnx("no memory for parameter request list"); |
1038 | else { |
1039 | memcpy(state->prl, packet->options[i].data, |
1040 | packet->options[i].len); |
1041 | state->prl_len = packet->options[i].len; |
1042 | } |
1043 | } |
1044 | |
1045 | /* If we didn't get a hostname from an option somewhere, see if |
1046 | we can get one from the lease. */ |
1047 | i = DHO_HOST_NAME12; |
1048 | if (!state->options[i] && lease->hostname) { |
1049 | state->options[i] = new_tree_cache("hostname"); |
1050 | state->options[i]->flags = TC_TEMPORARY2; |
1051 | state->options[i]->value = (unsigned char *)lease->hostname; |
1052 | state->options[i]->len = strlen(lease->hostname); |
1053 | state->options[i]->buf_size = state->options[i]->len; |
1054 | state->options[i]->timeout = -1; |
1055 | state->options[i]->tree = NULL((void *)0); |
1056 | } |
1057 | |
1058 | /* |
1059 | * Now, if appropriate, put in DHCP-specific options that |
1060 | * override those. |
1061 | */ |
1062 | if (state->offer) { |
1063 | i = DHO_DHCP_MESSAGE_TYPE53; |
1064 | state->options[i] = new_tree_cache("message-type"); |
1065 | state->options[i]->flags = TC_TEMPORARY2; |
1066 | state->options[i]->value = &state->offer; |
1067 | state->options[i]->len = sizeof state->offer; |
1068 | state->options[i]->buf_size = sizeof state->offer; |
1069 | state->options[i]->timeout = -1; |
1070 | state->options[i]->tree = NULL((void *)0); |
1071 | |
1072 | i = DHO_DHCP_SERVER_IDENTIFIER54; |
1073 | if (!state->options[i]) { |
1074 | use_primary: |
1075 | state->options[i] = new_tree_cache("server-id"); |
1076 | state->options[i]->value = |
1077 | (unsigned char *)&state->ip->primary_address; |
1078 | state->options[i]->len = |
1079 | sizeof state->ip->primary_address; |
1080 | state->options[i]->buf_size = state->options[i]->len; |
1081 | state->options[i]->timeout = -1; |
1082 | state->options[i]->tree = NULL((void *)0); |
1083 | state->from.len = sizeof state->ip->primary_address; |
1084 | memcpy(state->from.iabuf, &state->ip->primary_address, |
1085 | state->from.len); |
1086 | } else { |
1087 | /* Find the value of the server identifier... */ |
1088 | if (!tree_evaluate(state->options[i])) |
1089 | goto use_primary; |
1090 | if (!state->options[i]->value || |
1091 | (state->options[i]->len > |
1092 | sizeof state->from.iabuf)) |
1093 | goto use_primary; |
1094 | |
1095 | state->from.len = state->options[i]->len; |
1096 | memcpy(state->from.iabuf, state->options[i]->value, |
1097 | state->from.len); |
1098 | } |
1099 | /* |
1100 | * Do not ACK a REQUEST intended for another server. |
1101 | */ |
1102 | if (packet->options[i].len == 4) { |
1103 | if (state->options[i]->len != 4 || |
1104 | memcmp(packet->options[i].data, |
1105 | state->options[i]->value, 4) != 0) { |
1106 | free_lease_state(state, "ack_lease: " |
1107 | "server identifier"); |
1108 | return; |
1109 | } |
1110 | } |
1111 | |
1112 | /* If we used the vendor class the client specified, we |
1113 | have to return it. */ |
1114 | if (vendor_class) { |
1115 | i = DHO_DHCP_CLASS_IDENTIFIER60; |
1116 | state->options[i] = new_tree_cache("class-identifier"); |
1117 | state->options[i]->flags = TC_TEMPORARY2; |
1118 | state->options[i]->value = |
1119 | (unsigned char *)vendor_class->name; |
1120 | state->options[i]->len = strlen(vendor_class->name); |
1121 | state->options[i]->buf_size = state->options[i]->len; |
1122 | state->options[i]->timeout = -1; |
1123 | state->options[i]->tree = NULL((void *)0); |
1124 | } |
1125 | |
1126 | /* If we used the user class the client specified, we |
1127 | have to return it. */ |
1128 | if (user_class) { |
1129 | i = DHO_DHCP_USER_CLASS_ID77; |
1130 | state->options[i] = new_tree_cache("user-class"); |
1131 | state->options[i]->flags = TC_TEMPORARY2; |
1132 | state->options[i]->value = |
1133 | (unsigned char *)user_class->name; |
1134 | state->options[i]->len = strlen(user_class->name); |
1135 | state->options[i]->buf_size = state->options[i]->len; |
1136 | state->options[i]->timeout = -1; |
1137 | state->options[i]->tree = NULL((void *)0); |
1138 | } |
1139 | } |
1140 | |
1141 | /* for DHCPINFORM, don't include lease time parameters */ |
1142 | if (state->offer && (lease->flags & INFORM_NOLEASE32) == 0) { |
1143 | |
1144 | /* Sanity check the lease time. */ |
1145 | if ((state->offered_expiry - cur_time) < 15) |
1146 | offered_lease_time = default_lease_time; |
1147 | else if (state->offered_expiry - cur_time > max_lease_time) |
1148 | offered_lease_time = max_lease_time; |
1149 | else |
1150 | offered_lease_time = |
1151 | state->offered_expiry - cur_time; |
1152 | |
1153 | putULong((unsigned char *)&state->expiry, offered_lease_time); |
1154 | i = DHO_DHCP_LEASE_TIME51; |
1155 | state->options[i] = new_tree_cache("lease-expiry"); |
1156 | state->options[i]->flags = TC_TEMPORARY2; |
1157 | state->options[i]->value = (unsigned char *)&state->expiry; |
1158 | state->options[i]->len = sizeof state->expiry; |
1159 | state->options[i]->buf_size = sizeof state->expiry; |
1160 | state->options[i]->timeout = -1; |
1161 | state->options[i]->tree = NULL((void *)0); |
1162 | |
1163 | /* Renewal time is lease time * 0.5. */ |
1164 | offered_lease_time /= 2; |
1165 | putULong((unsigned char *)&state->renewal, offered_lease_time); |
1166 | i = DHO_DHCP_RENEWAL_TIME58; |
1167 | state->options[i] = new_tree_cache("renewal-time"); |
1168 | state->options[i]->flags = TC_TEMPORARY2; |
1169 | state->options[i]->value = |
1170 | (unsigned char *)&state->renewal; |
1171 | state->options[i]->len = sizeof state->renewal; |
1172 | state->options[i]->buf_size = sizeof state->renewal; |
1173 | state->options[i]->timeout = -1; |
1174 | state->options[i]->tree = NULL((void *)0); |
1175 | |
1176 | |
1177 | /* Rebinding time is lease time * 0.875. */ |
1178 | offered_lease_time += (offered_lease_time / 2 + |
1179 | offered_lease_time / 4); |
1180 | putULong((unsigned char *)&state->rebind, offered_lease_time); |
1181 | i = DHO_DHCP_REBINDING_TIME59; |
1182 | state->options[i] = new_tree_cache("rebind-time"); |
1183 | state->options[i]->flags = TC_TEMPORARY2; |
1184 | state->options[i]->value = (unsigned char *)&state->rebind; |
1185 | state->options[i]->len = sizeof state->rebind; |
1186 | state->options[i]->buf_size = sizeof state->rebind; |
1187 | state->options[i]->timeout = -1; |
1188 | state->options[i]->tree = NULL((void *)0); |
1189 | } |
1190 | |
1191 | /* Use the subnet mask from the subnet declaration if no other |
1192 | mask has been provided. */ |
1193 | i = DHO_SUBNET_MASK1; |
1194 | if (!state->options[i]) { |
1195 | state->options[i] = new_tree_cache("subnet-mask"); |
1196 | state->options[i]->flags = TC_TEMPORARY2; |
1197 | state->options[i]->value = lease->subnet->netmask.iabuf; |
1198 | state->options[i]->len = lease->subnet->netmask.len; |
1199 | state->options[i]->buf_size = lease->subnet->netmask.len; |
1200 | state->options[i]->timeout = -1; |
1201 | state->options[i]->tree = NULL((void *)0); |
1202 | } |
1203 | |
1204 | /* If so directed, use the leased IP address as the router address. |
1205 | This supposedly makes Win95 machines ARP for all IP addresses, |
1206 | so if the local router does proxy arp, you win. */ |
1207 | |
1208 | ulafdr = 0; |
1209 | if (lease->host) { |
1210 | if (lease->host->group->use_lease_addr_for_default_route) |
1211 | ulafdr = 1; |
1212 | } else if (user_class) { |
1213 | if (user_class->group->use_lease_addr_for_default_route) |
1214 | ulafdr = 1; |
1215 | } else if (vendor_class) { |
1216 | if (vendor_class->group->use_lease_addr_for_default_route) |
1217 | ulafdr = 1; |
1218 | } else if (lease->subnet->group->use_lease_addr_for_default_route) |
1219 | ulafdr = 1; |
1220 | else |
1221 | ulafdr = 0; |
1222 | |
1223 | i = DHO_ROUTERS3; |
1224 | if (ulafdr && !state->options[i]) { |
1225 | state->options[i] = new_tree_cache("routers"); |
1226 | state->options[i]->flags = TC_TEMPORARY2; |
1227 | state->options[i]->value = lease->ip_addr.iabuf; |
1228 | state->options[i]->len = lease->ip_addr.len; |
1229 | state->options[i]->buf_size = lease->ip_addr.len; |
1230 | state->options[i]->timeout = -1; |
1231 | state->options[i]->tree = NULL((void *)0); |
1232 | } |
1233 | |
1234 | /* |
1235 | * RFC 3046: MUST NOT echo relay agent information if the server |
1236 | * does not understand/use the data. We don't. |
1237 | */ |
1238 | i = DHO_RELAY_AGENT_INFORMATION82; |
1239 | memset(&state->options[i], 0, sizeof(state->options[i])); |
1240 | |
1241 | /* Echo back the client-identifier as RFC 6842 mandates. */ |
1242 | if (lease->host) |
1243 | echo_client_id = lease->host->group->echo_client_id; |
1244 | else if (user_class) |
1245 | echo_client_id = user_class->group->echo_client_id; |
1246 | else if (vendor_class) |
1247 | echo_client_id = vendor_class->group->echo_client_id; |
1248 | else |
1249 | echo_client_id = lease->subnet->group->echo_client_id; |
1250 | i = DHO_DHCP_CLIENT_IDENTIFIER61; |
1251 | if (lease->client_identifier && echo_client_id) { |
1252 | state->options[i] = new_tree_cache("dhcp-client-identifier"); |
1253 | state->options[i]->flags = TC_TEMPORARY2; |
1254 | state->options[i]->value = lease->client_identifier; |
1255 | state->options[i]->len = lease->client_identifier_len; |
1256 | state->options[i]->buf_size = lease->client_identifier_len; |
1257 | state->options[i]->timeout = -1; |
1258 | state->options[i]->tree = NULL((void *)0); |
1259 | } else |
1260 | memset(&state->options[i], 0, sizeof(state->options[i])); |
1261 | |
1262 | lease->state = state; |
1263 | |
1264 | /* If this is a DHCPOFFER, ping the lease address before actually |
1265 | sending the offer. */ |
1266 | if (offer == DHCPOFFER2 && !(lease->flags & STATIC_LEASE1) && |
1267 | cur_time - lease->timestamp > 60) { |
1268 | lease->timestamp = cur_time; |
1269 | icmp_echorequest(&lease->ip_addr); |
1270 | add_timeout(cur_time + 1, lease_ping_timeout, lease); |
1271 | ++outstanding_pings; |
1272 | } else { |
1273 | lease->timestamp = cur_time; |
1274 | dhcp_reply(lease); |
1275 | } |
1276 | } |
1277 | |
1278 | void |
1279 | dhcp_reply(struct lease *lease) |
1280 | { |
1281 | char ciaddrbuf[INET_ADDRSTRLEN16]; |
1282 | int bufs = 0, packet_length, i; |
1283 | struct dhcp_packet raw; |
1284 | struct sockaddr_in to; |
1285 | struct in_addr from; |
1286 | struct lease_state *state = lease->state; |
1287 | int nulltp, bootpp; |
1288 | u_int8_t *prl; |
1289 | int prl_len; |
1290 | |
1291 | if (!state) |
1292 | fatalx("dhcp_reply was supplied lease with no state!"); |
1293 | |
1294 | /* Compose a response for the client... */ |
1295 | memset(&raw, 0, sizeof raw); |
1296 | |
1297 | /* Copy in the filename if given; otherwise, flag the filename |
1298 | buffer as available for options. */ |
1299 | if (state->filename[0]) |
1300 | strlcpy(raw.file, state->filename, sizeof raw.file); |
1301 | else |
1302 | bufs |= 1; |
1303 | |
1304 | /* Copy in the server name if given; otherwise, flag the |
1305 | server_name buffer as available for options. */ |
1306 | if (state->server_name) |
1307 | strlcpy(raw.sname, state->server_name, sizeof raw.sname); |
1308 | else |
1309 | bufs |= 2; /* XXX */ |
1310 | |
1311 | memcpy(raw.chaddr, lease->hardware_addr.haddr, sizeof raw.chaddr); |
1312 | raw.hlen = lease->hardware_addr.hlen; |
1313 | raw.htype = lease->hardware_addr.htype; |
1314 | |
1315 | /* See if this is a Microsoft client that NUL-terminates its |
1316 | strings and expects us to do likewise... */ |
1317 | if (lease->flags & MS_NULL_TERMINATION8) |
1318 | nulltp = 1; |
1319 | else |
1320 | nulltp = 0; |
1321 | |
1322 | /* See if this is a bootp client... */ |
1323 | if (state->offer) |
1324 | bootpp = 0; |
1325 | else |
1326 | bootpp = 1; |
1327 | |
1328 | if (state->options[DHO_DHCP_PARAMETER_REQUEST_LIST55] && |
1329 | state->options[DHO_DHCP_PARAMETER_REQUEST_LIST55]->value) { |
1330 | prl = state->options[DHO_DHCP_PARAMETER_REQUEST_LIST55]->value; |
1331 | prl_len = state->options[DHO_DHCP_PARAMETER_REQUEST_LIST55]->len; |
1332 | } else if (state->prl) { |
1333 | prl = state->prl; |
1334 | prl_len = state->prl_len; |
1335 | } else { |
1336 | prl = NULL((void *)0); |
1337 | prl_len = 0; |
1338 | } |
1339 | |
1340 | /* Insert such options as will fit into the buffer. */ |
1341 | packet_length = cons_options(NULL((void *)0), &raw, state->max_message_size, |
1342 | state->options, bufs, nulltp, bootpp, prl, prl_len); |
1343 | |
1344 | /* Having done the cons_options(), we can release the tree_cache |
1345 | entries. */ |
1346 | for (i = 0; i < 256; i++) { |
1347 | if (state->options[i] && |
1348 | state->options[i]->flags & TC_TEMPORARY2) |
1349 | free_tree_cache(state->options[i]); |
1350 | } |
1351 | |
1352 | memcpy(&raw.ciaddr, &state->ciaddr, sizeof raw.ciaddr); |
1353 | if ((lease->flags & INFORM_NOLEASE32) == 0) |
1354 | memcpy(&raw.yiaddr, lease->ip_addr.iabuf, 4); |
1355 | |
1356 | /* Figure out the address of the next server. */ |
1357 | if (lease->host && lease->host->group->next_server.len) |
1358 | memcpy(&raw.siaddr, lease->host->group->next_server.iabuf, 4); |
1359 | else if (lease->subnet->group->next_server.len) |
1360 | memcpy(&raw.siaddr, lease->subnet->group->next_server.iabuf, |
1361 | 4); |
1362 | else if (lease->subnet->interface_address.len) |
1363 | memcpy(&raw.siaddr, lease->subnet->interface_address.iabuf, 4); |
1364 | else |
1365 | raw.siaddr = state->ip->primary_address; |
1366 | |
1367 | raw.giaddr = state->giaddr; |
1368 | |
1369 | raw.xid = state->xid; |
1370 | raw.secs = state->secs; |
1371 | raw.flags = state->bootp_flags; |
1372 | raw.hops = state->hops; |
1373 | raw.op = BOOTREPLY2; |
1374 | |
1375 | /* Can't do >1 inet_ntoa() in a printf()! */ |
1376 | strlcpy(ciaddrbuf, inet_ntoa(state->ciaddr), sizeof(ciaddrbuf)); |
1377 | |
1378 | /* Say what we're doing... */ |
1379 | if ((state->offer == DHCPACK5) && (lease->flags & INFORM_NOLEASE32)) |
1380 | log_info("DHCPACK to %s (%s) via %s", |
1381 | ciaddrbuf, |
1382 | print_hw_addr(lease->hardware_addr.htype, |
1383 | lease->hardware_addr.hlen, lease->hardware_addr.haddr), |
1384 | state->giaddr.s_addr ? inet_ntoa(state->giaddr) : |
1385 | state->ip->name); |
1386 | else |
1387 | log_info("%s on %s to %s via %s", |
1388 | (state->offer ? (state->offer == DHCPACK5 ? "DHCPACK" : |
1389 | "DHCPOFFER") : "BOOTREPLY"), |
1390 | piaddr(lease->ip_addr), |
1391 | print_hw_addr(lease->hardware_addr.htype, |
1392 | lease->hardware_addr.hlen, lease->hardware_addr.haddr), |
1393 | state->giaddr.s_addr ? inet_ntoa(state->giaddr) : |
1394 | state->ip->name); |
1395 | |
1396 | memset(&to, 0, sizeof to); |
1397 | to.sin_family = AF_INET2; |
1398 | #ifdef HAVE_SA_LEN |
1399 | to.sin_len = sizeof to; |
1400 | #endif |
1401 | |
1402 | /* Make sure outgoing packets are at least as big |
1403 | as a BOOTP packet. */ |
1404 | if (packet_length < BOOTP_MIN_LEN300) |
1405 | packet_length = BOOTP_MIN_LEN300; |
1406 | |
1407 | /* If this was gatewayed, send it back to the gateway... */ |
1408 | if (raw.giaddr.s_addr) { |
1409 | to.sin_addr = raw.giaddr; |
1410 | to.sin_port = server_port; |
1411 | |
1412 | memcpy(&from, state->from.iabuf, sizeof from); |
1413 | |
1414 | (void) state->ip->send_packet(state->ip, &raw, |
1415 | packet_length, from, &to, &state->haddr); |
1416 | |
1417 | free_lease_state(state, "dhcp_reply gateway"); |
1418 | lease->state = NULL((void *)0); |
1419 | return; |
1420 | |
1421 | /* If the client is RENEWING, unicast to the client using the |
1422 | regular IP stack. Some clients, particularly those that |
1423 | follow RFC1541, are buggy, and send both ciaddr and |
1424 | server-identifier. We deal with this situation by assuming |
1425 | that if we got both dhcp-server-identifier and ciaddr, and |
1426 | giaddr was not set, then the client is on the local |
1427 | network, and we can therefore unicast or broadcast to it |
1428 | successfully. A client in REQUESTING state on another |
1429 | network that's making this mistake will have set giaddr, |
1430 | and will therefore get a relayed response from the above |
1431 | code. */ |
1432 | } else if (raw.ciaddr.s_addr && |
1433 | !((state->got_server_identifier || |
1434 | (raw.flags & htons(BOOTP_BROADCAST)(__uint16_t)(__builtin_constant_p(32768L) ? (__uint16_t)(((__uint16_t )(32768L) & 0xffU) << 8 | ((__uint16_t)(32768L) & 0xff00U) >> 8) : __swap16md(32768L)))) && |
1435 | /* XXX This won't work if giaddr isn't zero, but it is: */ |
1436 | (state->shared_network == lease->shared_network)) && |
1437 | state->offer == DHCPACK5) { |
1438 | to.sin_addr = raw.ciaddr; |
1439 | to.sin_port = client_port; |
1440 | |
1441 | /* If it comes from a client that already knows its address |
1442 | and is not requesting a broadcast response, and we can |
1443 | unicast to a client without using the ARP protocol, sent it |
1444 | directly to that client. */ |
1445 | } else if (!(raw.flags & htons(BOOTP_BROADCAST)(__uint16_t)(__builtin_constant_p(32768L) ? (__uint16_t)(((__uint16_t )(32768L) & 0xffU) << 8 | ((__uint16_t)(32768L) & 0xff00U) >> 8) : __swap16md(32768L)))) { |
1446 | to.sin_addr = raw.yiaddr; |
1447 | to.sin_port = client_port; |
1448 | |
1449 | /* Otherwise, broadcast it on the local network. */ |
1450 | } else { |
1451 | to.sin_addr.s_addr = htonl(INADDR_BROADCAST)(__uint32_t)(__builtin_constant_p(((u_int32_t)(0xffffffff))) ? (__uint32_t)(((__uint32_t)(((u_int32_t)(0xffffffff))) & 0xff ) << 24 | ((__uint32_t)(((u_int32_t)(0xffffffff))) & 0xff00) << 8 | ((__uint32_t)(((u_int32_t)(0xffffffff)) ) & 0xff0000) >> 8 | ((__uint32_t)(((u_int32_t)(0xffffffff ))) & 0xff000000) >> 24) : __swap32md(((u_int32_t)( 0xffffffff)))); |
1452 | to.sin_port = client_port; |
1453 | memset(&state->haddr, 0xff, sizeof state->haddr); |
1454 | } |
1455 | |
1456 | memcpy(&from, state->from.iabuf, sizeof from); |
1457 | |
1458 | (void) state->ip->send_packet(state->ip, &raw, packet_length, |
1459 | from, &to, &state->haddr); |
1460 | |
1461 | free_lease_state(state, "dhcp_reply"); |
1462 | lease->state = NULL((void *)0); |
1463 | } |
1464 | |
1465 | struct lease * |
1466 | find_lease(struct packet *packet, struct shared_network *share, |
1467 | int *ours) |
1468 | { |
1469 | struct lease *uid_lease, *ip_lease, *hw_lease; |
1470 | struct lease *lease = NULL((void *)0); |
1471 | struct iaddr cip; |
1472 | struct host_decl *hp, *host = NULL((void *)0); |
1473 | struct lease *fixed_lease; |
1474 | |
1475 | /* Figure out what IP address the client is requesting, if any. */ |
1476 | if (packet->options[DHO_DHCP_REQUESTED_ADDRESS50].len == 4) { |
1477 | packet->got_requested_address = 1; |
1478 | cip.len = 4; |
1479 | memcpy(cip.iabuf, |
1480 | packet->options[DHO_DHCP_REQUESTED_ADDRESS50].data, |
1481 | cip.len); |
1482 | } else if (packet->raw->ciaddr.s_addr) { |
1483 | cip.len = 4; |
1484 | memcpy(cip.iabuf, &packet->raw->ciaddr, 4); |
1485 | } else |
1486 | cip.len = 0; |
1487 | |
1488 | /* Try to find a host or lease that's been assigned to the |
1489 | specified unique client identifier. */ |
1490 | if (packet->options[DHO_DHCP_CLIENT_IDENTIFIER61].len) { |
1491 | /* First, try to find a fixed host entry for the specified |
1492 | client identifier... */ |
1493 | hp = find_hosts_by_uid( |
1494 | packet->options[DHO_DHCP_CLIENT_IDENTIFIER61].data, |
1495 | packet->options[DHO_DHCP_CLIENT_IDENTIFIER61].len); |
1496 | if (hp) { |
1497 | host = hp; |
1498 | fixed_lease = mockup_lease(packet, share, hp); |
1499 | uid_lease = NULL((void *)0); |
1500 | } else { |
1501 | uid_lease = find_lease_by_uid( |
1502 | packet->options[DHO_DHCP_CLIENT_IDENTIFIER61].data, |
1503 | packet->options[DHO_DHCP_CLIENT_IDENTIFIER61].len); |
1504 | /* Find the lease matching this uid that's on the |
1505 | network the packet came from (if any). */ |
1506 | for (; uid_lease; uid_lease = uid_lease->n_uid) |
1507 | if (uid_lease->shared_network == share) |
1508 | break; |
1509 | fixed_lease = NULL((void *)0); |
1510 | if (uid_lease && (uid_lease->flags & ABANDONED_LEASE16)) |
1511 | uid_lease = NULL((void *)0); |
1512 | } |
1513 | } else { |
1514 | uid_lease = NULL((void *)0); |
1515 | fixed_lease = NULL((void *)0); |
1516 | } |
1517 | |
1518 | /* If we didn't find a fixed lease using the uid, try doing |
1519 | it with the hardware address... */ |
1520 | if (!fixed_lease) { |
1521 | hp = find_hosts_by_haddr(packet->raw->htype, |
1522 | packet->raw->chaddr, packet->raw->hlen); |
1523 | if (hp) { |
1524 | host = hp; /* Save it for later. */ |
1525 | fixed_lease = mockup_lease(packet, share, hp); |
1526 | } |
1527 | } |
1528 | |
1529 | /* If fixed_lease is present but does not match the requested |
1530 | IP address, and this is a DHCPREQUEST, then we can't return |
1531 | any other lease, so we might as well return now. */ |
1532 | if (packet->packet_type == DHCPREQUEST3 && fixed_lease && |
1533 | (fixed_lease->ip_addr.len != cip.len || |
1534 | memcmp(fixed_lease->ip_addr.iabuf, cip.iabuf, cip.len))) { |
1535 | if (ours) |
1536 | *ours = 1; |
1537 | strlcpy(dhcp_message, "requested address is incorrect", |
1538 | sizeof(dhcp_message)); |
1539 | return NULL((void *)0); |
1540 | } |
1541 | |
1542 | /* Try to find a lease that's been attached to the client's |
1543 | hardware address... */ |
1544 | hw_lease = find_lease_by_hw_addr(packet->raw->chaddr, |
1545 | packet->raw->hlen); |
1546 | /* Find the lease that's on the network the packet came from |
1547 | (if any). */ |
1548 | for (; hw_lease; hw_lease = hw_lease->n_hw) { |
1549 | if (hw_lease->shared_network == share) { |
1550 | if ((hw_lease->flags & ABANDONED_LEASE16)) |
1551 | continue; |
1552 | if (packet->packet_type) |
1553 | break; |
1554 | if (hw_lease->flags & |
1555 | (BOOTP_LEASE2 | DYNAMIC_BOOTP_OK4)) |
1556 | break; |
1557 | } |
1558 | } |
1559 | |
1560 | /* Try to find a lease that's been allocated to the client's |
1561 | IP address. */ |
1562 | if (cip.len) |
1563 | ip_lease = find_lease_by_ip_addr(cip); |
1564 | else |
1565 | ip_lease = NULL((void *)0); |
1566 | |
1567 | /* If ip_lease is valid at this point, set ours to one, so that |
1568 | even if we choose a different lease, we know that the address |
1569 | the client was requesting was ours, and thus we can NAK it. */ |
1570 | if (ip_lease && ours) |
1571 | *ours = 1; |
1572 | |
1573 | /* If the requested IP address isn't on the network the packet |
1574 | came from, don't use it. Allow abandoned leases to be matched |
1575 | here - if the client is requesting it, there's a decent chance |
1576 | that it's because the lease database got trashed and a client |
1577 | that thought it had this lease answered an ARP or PING, causing the |
1578 | lease to be abandoned. If so, this request probably came from |
1579 | that client. */ |
1580 | if (ip_lease && (ip_lease->shared_network != share)) { |
1581 | ip_lease = NULL((void *)0); |
1582 | strlcpy(dhcp_message, "requested address on bad subnet", |
1583 | sizeof(dhcp_message)); |
1584 | } |
1585 | |
1586 | /* Toss ip_lease if it hasn't yet expired and isn't owned by the |
1587 | client. */ |
1588 | if (ip_lease && ip_lease->ends >= cur_time && ip_lease != uid_lease) { |
1589 | int i = DHO_DHCP_CLIENT_IDENTIFIER61; |
1590 | |
1591 | /* Make sure that ip_lease actually belongs to the client, |
1592 | and toss it if not. */ |
1593 | if ((ip_lease->uid_len && packet->options[i].data && |
1594 | ip_lease->uid_len == packet->options[i].len && |
1595 | !memcmp(packet->options[i].data, ip_lease->uid, |
1596 | ip_lease->uid_len)) || |
1597 | (!ip_lease->uid_len && |
1598 | ip_lease->hardware_addr.htype == packet->raw->htype && |
1599 | ip_lease->hardware_addr.hlen == packet->raw->hlen && |
1600 | !memcmp(ip_lease->hardware_addr.haddr, packet->raw->chaddr, |
1601 | ip_lease->hardware_addr.hlen))) { |
1602 | if (uid_lease) { |
1603 | if (uid_lease->ends > cur_time) { |
1604 | log_warnx("client %s has duplicate " |
1605 | "leases on %s", |
1606 | print_hw_addr(packet->raw->htype, |
1607 | packet->raw->hlen, |
1608 | packet->raw->chaddr), |
1609 | ip_lease->shared_network->name); |
1610 | |
1611 | if (uid_lease && |
1612 | !packet->raw->ciaddr.s_addr) |
1613 | release_lease(uid_lease); |
1614 | } |
1615 | uid_lease = ip_lease; |
1616 | } |
1617 | } else { |
1618 | strlcpy(dhcp_message, "requested address is not " |
1619 | "available", sizeof(dhcp_message)); |
1620 | ip_lease = NULL((void *)0); |
1621 | } |
1622 | |
1623 | /* If we get to here and fixed_lease is not null, that means |
1624 | that there are both a dynamic lease and a fixed-address |
1625 | declaration for the same IP address. */ |
1626 | if (packet->packet_type == DHCPREQUEST3 && fixed_lease) { |
1627 | fixed_lease = NULL((void *)0); |
1628 | db_conflict: |
1629 | log_warnx("Both dynamic and static leases present for " |
1630 | "%s.", piaddr(cip)); |
1631 | log_warnx("Either remove host declaration %s or " |
1632 | "remove %s", (fixed_lease && fixed_lease->host ? |
1633 | (fixed_lease->host->name ? |
1634 | fixed_lease->host->name : piaddr(cip)) : |
1635 | piaddr(cip)), piaddr(cip)); |
1636 | log_warnx("from the dynamic address pool for %s", |
1637 | share->name); |
1638 | if (fixed_lease) |
1639 | ip_lease = NULL((void *)0); |
1640 | strlcpy(dhcp_message, "database conflict - call for " |
1641 | "help!", sizeof(dhcp_message)); |
1642 | } |
1643 | } |
1644 | |
1645 | /* If we get to here with both fixed_lease and ip_lease not |
1646 | null, then we have a configuration file bug. */ |
1647 | if (packet->packet_type == DHCPREQUEST3 && fixed_lease && ip_lease) |
1648 | goto db_conflict; |
1649 | |
1650 | /* Toss hw_lease if it hasn't yet expired and the uid doesn't |
1651 | match, except that if the hardware address matches and the |
1652 | client is now doing dynamic BOOTP (and thus hasn't provided |
1653 | a uid) we let the client get away with it. */ |
1654 | if (hw_lease && hw_lease->ends >= cur_time && hw_lease->uid && |
1655 | packet->options[DHO_DHCP_CLIENT_IDENTIFIER61].len && |
1656 | hw_lease != uid_lease) |
1657 | hw_lease = NULL((void *)0); |
1658 | |
1659 | /* Toss extra pointers to the same lease... */ |
1660 | if (hw_lease == uid_lease) |
1661 | hw_lease = NULL((void *)0); |
1662 | if (ip_lease == hw_lease) |
1663 | hw_lease = NULL((void *)0); |
1664 | if (ip_lease == uid_lease) |
1665 | uid_lease = NULL((void *)0); |
1666 | |
1667 | /* If we've already eliminated the lease, it wasn't there to |
1668 | begin with. If we have come up with a matching lease, |
1669 | set the message to bad network in case we have to throw it out. */ |
1670 | if (!ip_lease) { |
1671 | strlcpy(dhcp_message, "requested address not available", |
1672 | sizeof(dhcp_message)); |
1673 | } |
1674 | |
1675 | /* Now eliminate leases that are on the wrong network... */ |
1676 | if (ip_lease && share != ip_lease->shared_network) { |
1677 | if (packet->packet_type == DHCPREQUEST3) |
1678 | release_lease(ip_lease); |
1679 | ip_lease = NULL((void *)0); |
1680 | } |
1681 | if (uid_lease && share != uid_lease->shared_network) { |
1682 | if (packet->packet_type == DHCPREQUEST3) |
1683 | release_lease(uid_lease); |
1684 | uid_lease = NULL((void *)0); |
1685 | } |
1686 | if (hw_lease && share != hw_lease->shared_network) { |
1687 | if (packet->packet_type == DHCPREQUEST3) |
1688 | release_lease(hw_lease); |
1689 | hw_lease = NULL((void *)0); |
1690 | } |
1691 | |
1692 | /* If this is a DHCPREQUEST, make sure the lease we're going to return |
1693 | matches the requested IP address. If it doesn't, don't return a |
1694 | lease at all. */ |
1695 | if (packet->packet_type == DHCPREQUEST3 && !ip_lease && !fixed_lease) |
1696 | return NULL((void *)0); |
1697 | |
1698 | /* At this point, if fixed_lease is nonzero, we can assign it to |
1699 | this client. */ |
1700 | if (fixed_lease) |
1701 | lease = fixed_lease; |
1702 | |
1703 | /* If we got a lease that matched the ip address and don't have |
1704 | a better offer, use that; otherwise, release it. */ |
1705 | if (ip_lease) { |
1706 | if (lease) { |
1707 | if (packet->packet_type == DHCPREQUEST3) |
1708 | release_lease(ip_lease); |
1709 | } else { |
1710 | lease = ip_lease; |
1711 | lease->host = NULL((void *)0); |
1712 | } |
1713 | } |
1714 | |
1715 | /* If we got a lease that matched the client identifier, we may want |
1716 | to use it, but if we already have a lease we like, we must free |
1717 | the lease that matched the client identifier. */ |
1718 | if (uid_lease) { |
1719 | if (lease) { |
1720 | if (packet->packet_type == DHCPREQUEST3) |
1721 | release_lease(uid_lease); |
1722 | } else { |
1723 | lease = uid_lease; |
1724 | lease->host = NULL((void *)0); |
1725 | } |
1726 | } |
1727 | |
1728 | /* The lease that matched the hardware address is treated likewise. */ |
1729 | if (hw_lease) { |
1730 | if (lease) { |
1731 | if (packet->packet_type == DHCPREQUEST3) |
1732 | release_lease(hw_lease); |
1733 | } else { |
1734 | lease = hw_lease; |
1735 | lease->host = NULL((void *)0); |
1736 | } |
1737 | } |
1738 | |
1739 | /* If we found a host_decl but no matching address, try to |
1740 | find a host_decl that has no address, and if there is one, |
1741 | hang it off the lease so that we can use the supplied |
1742 | options. */ |
1743 | if (lease && host && !lease->host) { |
1744 | for (; host; host = host->n_ipaddr) { |
1745 | if (!host->fixed_addr) { |
1746 | lease->host = host; |
1747 | break; |
1748 | } |
1749 | } |
1750 | } |
1751 | |
1752 | /* If we find an abandoned lease, take it, but print a |
1753 | warning message, so that if it continues to lose, |
1754 | the administrator will eventually investigate. */ |
1755 | if (lease && (lease->flags & ABANDONED_LEASE16)) { |
1756 | if (packet->packet_type == DHCPREQUEST3) { |
1757 | log_warnx("Reclaiming REQUESTed abandoned IP address " |
1758 | "%s.", piaddr(lease->ip_addr)); |
1759 | lease->flags &= ~ABANDONED_LEASE16; |
1760 | } else |
1761 | lease = NULL((void *)0); |
1762 | } |
1763 | return lease; |
1764 | } |
1765 | |
1766 | /* |
1767 | * Search the provided host_decl structure list for an address that's on |
1768 | * the specified shared network. If one is found, mock up and return a |
1769 | * lease structure for it; otherwise return the null pointer. |
1770 | */ |
1771 | struct lease * |
1772 | mockup_lease(struct packet *packet, struct shared_network *share, |
1773 | struct host_decl *hp) |
1774 | { |
1775 | static struct lease mock; |
1776 | |
1777 | mock.subnet = find_host_for_network(&hp, &mock.ip_addr, share); |
1778 | if (!mock.subnet) |
1779 | return (NULL((void *)0)); |
1780 | mock.next = mock.prev = NULL((void *)0); |
1781 | mock.shared_network = mock.subnet->shared_network; |
1782 | mock.host = hp; |
1783 | |
1784 | if (hp->group->options[DHO_DHCP_CLIENT_IDENTIFIER61]) { |
1785 | mock.uid = |
1786 | hp->group->options[DHO_DHCP_CLIENT_IDENTIFIER61]->value; |
1787 | mock.uid_len = |
1788 | hp->group->options[DHO_DHCP_CLIENT_IDENTIFIER61]->len; |
1789 | } else { |
1790 | mock.uid = NULL((void *)0); |
1791 | mock.uid_len = 0; |
1792 | } |
1793 | |
1794 | mock.hardware_addr = hp->interface; |
1795 | mock.starts = mock.timestamp = mock.ends = MIN_TIME0; |
1796 | mock.flags = STATIC_LEASE1; |
1797 | return &mock; |
1798 | } |