ISC DHCP 4.4.3-P1
A reference DHCPv4 and DHCPv6 implementation
 
Loading...
Searching...
No Matches
dhcpleasequery.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2006-2017 by Internet Systems Consortium, Inc. ("ISC")
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "dhcpd.h"
18
19/*
20 * TODO: RFC4388 specifies that the server SHOULD return the same
21 * options it would for a DHCREQUEST message, if no Parameter
22 * Request List option (option 55) is passed. We do not do that.
23 *
24 * TODO: RFC4388 specifies the creation of a "non-sensitive options"
25 * configuration list, and that these SHOULD be returned. We
26 * have no such list.
27 *
28 * TODO: RFC4388 says the server SHOULD use RFC3118, "Authentication
29 * for DHCP Messages".
30 *
31 * TODO: RFC4388 specifies that you SHOULD insure that you cannot be
32 * DoS'ed by DHCPLEASEQUERY message.
33 */
34
35/*
36 * If you query by hardware address or by client ID, then you may have
37 * more than one IP address for your query argument. We need to do two
38 * things:
39 *
40 * 1. Find the most recent lease.
41 * 2. Find all additional IP addresses for the query argument.
42 *
43 * We do this by looking through all of the leases associated with a
44 * given hardware address or client ID. We use the cltt (client last
45 * transaction time) of the lease, which only has a resolution of one
46 * second, so we might not actually give the very latest IP.
47 */
48
49static struct lease*
50next_hw(const struct lease *lease) {
51 /* INSIST(lease != NULL); */
52 return lease->n_hw;
53}
54
55static struct lease*
56next_uid(const struct lease *lease) {
57 /* INSIST(lease != NULL); */
58 return lease->n_uid;
59}
60
61void
62get_newest_lease(struct lease **retval,
63 struct lease *lease,
64 struct lease *(*next)(const struct lease *)) {
65
66 struct lease *p;
67 struct lease *newest;
68
69 /* INSIST(newest != NULL); */
70 /* INSIST(next != NULL); */
71
72 *retval = NULL;
73
74 if (lease == NULL) {
75 return;
76 }
77
78 newest = lease;
79 for (p=next(lease); p != NULL; p=next(p)) {
80 if (newest->binding_state == FTS_ACTIVE) {
81 if ((p->binding_state == FTS_ACTIVE) &&
82 (p->cltt > newest->cltt)) {
83 newest = p;
84 }
85 } else {
86 if (p->ends > newest->ends) {
87 newest = p;
88 }
89 }
90 }
91
92 lease_reference(retval, newest, MDL);
93}
94
95static int
96get_associated_ips(const struct lease *lease,
97 struct lease *(*next)(const struct lease *),
98 const struct lease *newest,
99 u_int32_t *associated_ips,
100 unsigned int associated_ips_size) {
101
102 const struct lease *p;
103 int cnt;
104
105 /* INSIST(next != NULL); */
106 /* INSIST(associated_ips != NULL); */
107
108 if (lease == NULL) {
109 return 0;
110 }
111
112 cnt = 0;
113 for (p=lease; p != NULL; p=next(p)) {
114 if ((p->binding_state == FTS_ACTIVE) && (p != newest)) {
115 if (cnt < associated_ips_size) {
116 memcpy(&associated_ips[cnt],
117 p->ip_addr.iabuf,
118 sizeof(associated_ips[cnt]));
119 }
120 cnt++;
121 }
122 }
123 return cnt;
124}
125
126
127void
128dhcpleasequery(struct packet *packet, int ms_nulltp) {
129 char msgbuf[256];
130 char dbg_info[128];
131 struct iaddr cip;
132 struct iaddr gip;
133 struct data_string uid;
134 struct hardware h;
135 struct lease *tmp_lease;
136 struct lease *lease;
137 int want_associated_ip;
138 int assoc_ip_cnt;
139 u_int32_t assoc_ips[40]; /* XXXSK: arbitrary maximum number of IPs */
140 const int nassoc_ips = sizeof(assoc_ips) / sizeof(assoc_ips[0]);
141
142 unsigned char dhcpMsgType;
143 const char *dhcp_msg_type_name;
144 struct subnet *subnet;
145 struct group *relay_group;
146 struct option_state *options;
147 struct option_cache *oc;
148 int allow_leasequery;
149 int ignorep;
150 u_int32_t lease_duration;
151 u_int32_t time_renewal;
152 u_int32_t time_rebinding;
153 u_int32_t time_expiry;
154 u_int32_t client_last_transaction_time;
155#if defined(RELAY_PORT)
156 u_int16_t relay_port = 0;
157#endif
158 struct sockaddr_in to;
159 struct in_addr siaddr;
160 struct data_string prl;
161 struct data_string *prl_ptr;
162
163 int i;
164 struct interface_info *interface;
165
166 /* INSIST(packet != NULL); */
167
168 /*
169 * Prepare log information.
170 */
171 snprintf(msgbuf, sizeof(msgbuf),
172 "DHCPLEASEQUERY from %s", inet_ntoa(packet->raw->giaddr));
173
174 /*
175 * We can't reply if there is no giaddr field.
176 */
177 /*
178 * Note: this makes DHCPv4-over-DHCPv6 always fail but it should not
179 * really be a problem because it is not a specified use case
180 * (or even one that makes sense).
181 */
182 if (!packet->raw->giaddr.s_addr) {
183 log_info("%s: missing giaddr, ciaddr is %s, no reply sent",
184 msgbuf, inet_ntoa(packet->raw->ciaddr));
185 return;
186 }
187
188 /*
189 * Initially we use the 'giaddr' subnet options scope to determine if
190 * the giaddr-identified relay agent is permitted to perform a
191 * leasequery. The subnet is not required, and may be omitted, in
192 * which case we are essentially interrogating the root options class
193 * to find a globally permit.
194 */
195 gip.len = sizeof(packet->raw->giaddr);
196 memcpy(gip.iabuf, &packet->raw->giaddr, sizeof(packet->raw->giaddr));
197
198 subnet = NULL;
199 find_subnet(&subnet, gip, MDL);
200 if (subnet != NULL)
201 relay_group = subnet->group;
202 else
203 relay_group = root_group;
204
205 subnet_dereference(&subnet, MDL);
206
207 options = NULL;
208 if (!option_state_allocate(&options, MDL)) {
209 log_error("No memory for option state.");
210 log_info("%s: out of memory, no reply sent", msgbuf);
211 return;
212 }
213
215 options, &global_scope, relay_group,
216 NULL, NULL);
217
218 for (i=packet->class_count-1; i>=0; i--) {
219 execute_statements_in_scope(NULL, packet, NULL, NULL,
220 packet->options, options,
222 packet->classes[i]->group,
223 relay_group, NULL);
224 }
225
226 /*
227 * Because LEASEQUERY has some privacy concerns, default to deny.
228 */
229 allow_leasequery = 0;
230
231 /*
232 * See if we are authorized to do LEASEQUERY.
233 */
235 if (oc != NULL) {
236 allow_leasequery = evaluate_boolean_option_cache(&ignorep,
237 packet, NULL, NULL, packet->options,
238 options, &global_scope, oc, MDL);
239 }
240
241 if (!allow_leasequery) {
242 log_info("%s: LEASEQUERY not allowed, query ignored", msgbuf);
243 option_state_dereference(&options, MDL);
244 return;
245 }
246
247
248 /*
249 * Copy out the client IP address.
250 */
251 cip.len = sizeof(packet->raw->ciaddr);
252 memcpy(cip.iabuf, &packet->raw->ciaddr, sizeof(packet->raw->ciaddr));
253
254 /*
255 * If the client IP address is valid (not all zero), then we
256 * are looking for information about that IP address.
257 */
258 assoc_ip_cnt = 0;
259 lease = tmp_lease = NULL;
260 if (memcmp(cip.iabuf, "\0\0\0", 4)) {
261
262 want_associated_ip = 0;
263
264 snprintf(dbg_info, sizeof(dbg_info), "IP %s", piaddr(cip));
266
267
268 } else {
269
270 want_associated_ip = 1;
271
272 /*
273 * If the client IP address is all zero, then we will
274 * either look up by the client identifier (if we have
275 * one), or by the MAC address.
276 */
277
278 memset(&uid, 0, sizeof(uid));
279 i = get_option(&uid,
281 packet,
282 NULL,
283 NULL,
285 NULL,
286 packet->options,
289 MDL);
290 if (!i)
291 i = get_option(&uid,
293 packet,
294 NULL,
295 NULL,
297 NULL,
301 MDL);
302 if (i) {
303 snprintf(dbg_info,
304 sizeof(dbg_info),
305 "client-id %s",
306 print_hex_1(uid.len, uid.data, 60));
307
308 find_lease_by_uid(&tmp_lease, uid.data, uid.len, MDL);
309 data_string_forget(&uid, MDL);
310 get_newest_lease(&lease, tmp_lease, next_uid);
311 assoc_ip_cnt = get_associated_ips(tmp_lease,
312 next_uid,
313 lease,
314 assoc_ips,
315 nassoc_ips);
316
317 } else {
318
319 if (packet->raw->hlen+1 > sizeof(h.hbuf)) {
320 log_info("%s: hardware length too long, "
321 "no reply sent", msgbuf);
322 option_state_dereference(&options, MDL);
323 return;
324 }
325
326 h.hlen = packet->raw->hlen + 1;
327 h.hbuf[0] = packet->raw->htype;
328 memcpy(&h.hbuf[1],
329 packet->raw->chaddr,
330 packet->raw->hlen);
331
332 snprintf(dbg_info,
333 sizeof(dbg_info),
334 "MAC address %s",
335 print_hw_addr(h.hbuf[0],
336 h.hlen - 1,
337 &h.hbuf[1]));
338
339 find_lease_by_hw_addr(&tmp_lease, h.hbuf, h.hlen, MDL);
340 get_newest_lease(&lease, tmp_lease, next_hw);
341 assoc_ip_cnt = get_associated_ips(tmp_lease,
342 next_hw,
343 lease,
344 assoc_ips,
345 nassoc_ips);
346
347 }
348
349 lease_dereference(&tmp_lease, MDL);
350
351 if (lease != NULL) {
352 memcpy(&packet->raw->ciaddr,
354 sizeof(packet->raw->ciaddr));
355 }
356
357 /*
358 * Log if we have too many IP addresses associated
359 * with this client.
360 */
361 if (want_associated_ip && (assoc_ip_cnt > nassoc_ips)) {
362 log_info("%d IP addresses associated with %s, "
363 "only %d sent in reply.",
364 assoc_ip_cnt, dbg_info, nassoc_ips);
365 }
366 }
367
368 /*
369 * We now know the query target too, so can report this in
370 * our log message.
371 */
372 snprintf(msgbuf, sizeof(msgbuf),
373 "DHCPLEASEQUERY from %s for %s",
374 inet_ntoa(packet->raw->giaddr), dbg_info);
375
376 /*
377 * Figure our our return type.
378 */
379 if (lease == NULL) {
380 dhcpMsgType = DHCPLEASEUNKNOWN;
381 dhcp_msg_type_name = "DHCPLEASEUNKNOWN";
382 } else {
384 dhcpMsgType = DHCPLEASEACTIVE;
385 dhcp_msg_type_name = "DHCPLEASEACTIVE";
386 } else {
387 dhcpMsgType = DHCPLEASEUNASSIGNED;
388 dhcp_msg_type_name = "DHCPLEASEUNASSIGNED";
389 }
390 }
391
392 /*
393 * Set options that only make sense if we have an active lease.
394 */
395
396 if (dhcpMsgType == DHCPLEASEACTIVE)
397 {
398 /*
399 * RFC 4388 uses the PRL to request options for the agent to
400 * receive that are "about" the client. It is confusing
401 * because in some cases it wants to know what was sent to
402 * the client (lease times, adjusted), and in others it wants
403 * to know information the client sent. You're supposed to
404 * know this on a case-by-case basis.
405 *
406 * "Name servers", "domain name", and the like from the relay
407 * agent's scope seems less than useful. Our options are to
408 * restart the option cache from the lease's best point of view
409 * (execute statements from the lease pool's group), or to
410 * simply restart the option cache from empty.
411 *
412 * I think restarting the option cache from empty best
413 * approaches RFC 4388's intent; specific options are included.
414 */
415 option_state_dereference(&options, MDL);
416
417 if (!option_state_allocate(&options, MDL)) {
418 log_error("%s: out of memory, no reply sent", msgbuf);
419 lease_dereference(&lease, MDL);
420 return;
421 }
422
423 /*
424 * Set the hardware address fields.
425 */
426
429 memcpy(packet->raw->chaddr,
431 sizeof(packet->raw->chaddr));
432
433 /*
434 * Set client identifier option.
435 */
436 if (lease->uid_len > 0) {
437 if (!add_option(options,
439 lease->uid,
440 lease->uid_len)) {
441 option_state_dereference(&options, MDL);
442 lease_dereference(&lease, MDL);
443 log_info("%s: out of memory, no reply sent",
444 msgbuf);
445 return;
446 }
447 }
448
449
450 /*
451 * Calculate T1 and T2, the times when the client
452 * tries to extend its lease on its networking
453 * address.
454 * These seem to be hard-coded in ISC DHCP, to 0.5 and
455 * 0.875 of the lease time.
456 */
457
458 lease_duration = lease->ends - lease->starts;
459 time_renewal = lease->starts +
460 (lease_duration / 2);
461 time_rebinding = lease->starts +
462 (lease_duration / 2) +
463 (lease_duration / 4) +
464 (lease_duration / 8);
465
466 if (time_renewal > cur_time) {
467 time_renewal = htonl(time_renewal - cur_time);
468
469 if (!add_option(options,
471 &time_renewal,
472 sizeof(time_renewal))) {
473 option_state_dereference(&options, MDL);
474 lease_dereference(&lease, MDL);
475 log_info("%s: out of memory, no reply sent",
476 msgbuf);
477 return;
478 }
479 }
480
481 if (time_rebinding > cur_time) {
482 time_rebinding = htonl(time_rebinding - cur_time);
483
484 if (!add_option(options,
486 &time_rebinding,
487 sizeof(time_rebinding))) {
488 option_state_dereference(&options, MDL);
489 lease_dereference(&lease, MDL);
490 log_info("%s: out of memory, no reply sent",
491 msgbuf);
492 return;
493 }
494 }
495
496 if (lease->ends > cur_time) {
497 time_expiry = htonl(lease->ends - cur_time);
498
499 if (!add_option(options,
501 &time_expiry,
502 sizeof(time_expiry))) {
503 option_state_dereference(&options, MDL);
504 lease_dereference(&lease, MDL);
505 log_info("%s: out of memory, no reply sent",
506 msgbuf);
507 return;
508 }
509 }
510
511 /* Supply the Vendor-Class-Identifier. */
512 if (lease->scope != NULL) {
513 struct data_string vendor_class;
514
515 memset(&vendor_class, 0, sizeof(vendor_class));
516
517 if (find_bound_string(&vendor_class, lease->scope,
518 "vendor-class-identifier")) {
519 if (!add_option(options,
521 (void *)vendor_class.data,
522 vendor_class.len)) {
524 MDL);
525 lease_dereference(&lease, MDL);
526 log_error("%s: error adding vendor "
527 "class identifier, no reply "
528 "sent", msgbuf);
529 data_string_forget(&vendor_class, MDL);
530 return;
531 }
532 data_string_forget(&vendor_class, MDL);
533 }
534 }
535
536 /*
537 * Set the relay agent info.
538 *
539 * Note that because agent info is appended without regard
540 * to the PRL in cons_options(), this will be sent as the
541 * last option in the packet whether it is listed on PRL or
542 * not.
543 */
544
545 if (lease->agent_options != NULL) {
546 int idx = agent_universe.index;
547 struct option_chain_head **tmp1 =
548 (struct option_chain_head **)
549 &(options->universes[idx]);
550 struct option_chain_head *tmp2 =
551 (struct option_chain_head *)
553
554 option_chain_head_reference(tmp1, tmp2, MDL);
555 }
556
557 /*
558 * Set the client last transaction time.
559 * We check to make sure we have a timestamp. For
560 * lease files that were saved before running a
561 * timestamp-aware version of the server, this may
562 * not be set.
563 */
564
565 if (lease->cltt != MIN_TIME) {
566 if (cur_time > lease->cltt) {
567 client_last_transaction_time =
568 htonl(cur_time - lease->cltt);
569 } else {
570 client_last_transaction_time = htonl(0);
571 }
572 if (!add_option(options,
574 &client_last_transaction_time,
575 sizeof(client_last_transaction_time))) {
576 option_state_dereference(&options, MDL);
577 lease_dereference(&lease, MDL);
578 log_info("%s: out of memory, no reply sent",
579 msgbuf);
580 return;
581 }
582 }
583
584 /*
585 * Set associated IPs, if requested and there are some.
586 */
587 if (want_associated_ip && (assoc_ip_cnt > 0)) {
588 if (!add_option(options,
590 assoc_ips,
591 assoc_ip_cnt * sizeof(assoc_ips[0]))) {
592 option_state_dereference(&options, MDL);
593 lease_dereference(&lease, MDL);
594 log_info("%s: out of memory, no reply sent",
595 msgbuf);
596 return;
597 }
598 }
599 }
600
601 /*
602 * Set the message type.
603 */
604
606
607 /*
608 * Set DHCP message type.
609 */
610 if (!add_option(options,
612 &dhcpMsgType,
613 sizeof(dhcpMsgType))) {
614 option_state_dereference(&options, MDL);
615 lease_dereference(&lease, MDL);
616 log_info("%s: error adding option, no reply sent", msgbuf);
617 return;
618 }
619
620 /*
621 * Log the message we've received.
622 */
623 log_info("%s", msgbuf);
624
625 /*
626 * Figure out which address to use to send from.
627 */
628 get_server_source_address(&siaddr, options, options, packet);
629
630 /*
631 * Set up the option buffer.
632 */
633
634 memset(&prl, 0, sizeof(prl));
635 oc = lookup_option(&dhcp_universe, options,
637 if (oc != NULL) {
639 packet,
640 NULL,
641 NULL,
643 options,
645 oc,
646 MDL);
647 }
648 if (prl.len > 0) {
649 prl_ptr = &prl;
650 } else {
651 prl_ptr = NULL;
652 }
653
655 packet->raw,
656 lease,
657 NULL,
658 0,
660 options,
662 0,
663 0,
664 0,
665 prl_ptr,
666 NULL);
667
668 data_string_forget(&prl, MDL); /* SK: safe, even if empty */
669 option_state_dereference(&options, MDL);
670 lease_dereference(&lease, MDL);
671
672 to.sin_family = AF_INET;
673#ifdef HAVE_SA_LEN
674 to.sin_len = sizeof(to);
675#endif
676 memset(to.sin_zero, 0, sizeof(to.sin_zero));
677
678#if defined(RELAY_PORT)
680#endif
681
682 /*
683 * Leasequery packets are be sent to the gateway address.
684 */
685 to.sin_addr = packet->raw->giaddr;
686 if (packet->raw->giaddr.s_addr != htonl(INADDR_LOOPBACK)) {
687#if defined(RELAY_PORT)
688 to.sin_port = relay_port ? relay_port : local_port;
689#else
690 to.sin_port = local_port;
691#endif
692 } else {
693 to.sin_port = remote_port; /* XXXSK: For debugging. */
694 }
695
696 /*
697 * The fallback_interface lets us send with a real IP
698 * address. The packet interface sends from all-zeros.
699 */
700 if (fallback_interface != NULL) {
701 interface = fallback_interface;
702 } else {
703 interface = packet->interface;
704 }
705
706 /*
707 * Report what we're sending.
708 */
709 log_info("%s to %s for %s (%d associated IPs)",
710 dhcp_msg_type_name,
711 inet_ntoa(to.sin_addr), dbg_info, assoc_ip_cnt);
712
714 NULL,
715 packet->raw,
717 siaddr,
718 &to,
719 NULL);
720}
721
722#ifdef DHCPv6
723
724/*
725 * TODO: RFC5007 query-by-clientid.
726 *
727 * TODO: RFC5007 look at the pools according to the link-address.
728 *
729 * TODO: get fixed leases too.
730 *
731 * TODO: RFC5007 ORO in query-options.
732 *
733 * TODO: RFC5007 lq-relay-data.
734 *
735 * TODO: RFC5007 lq-client-link.
736 *
737 * Note: the code is still nearly compliant and usable for the target
738 * case with these missing features!
739 */
740
741/*
742 * The structure to handle a leasequery.
743 */
744struct lq6_state {
745 struct packet *packet;
746 struct data_string client_id;
747 struct data_string server_id;
748 struct data_string lq_query;
749 uint8_t query_type;
750 struct in6_addr link_addr;
751 struct option_state *query_opts;
752
753 struct option_state *reply_opts;
754 unsigned cursor;
755 union reply_buffer {
756 unsigned char data[65536];
757 struct dhcpv6_packet reply;
758 } buf;
759};
760
761/*
762 * Options that we want to send.
763 */
764static const int required_opts_lq[] = {
771 0
772};
773static const int required_opt_CLIENT_DATA[] = {
778 0
779};
780
781/*
782 * Get the lq-query option from the packet.
783 */
784static isc_result_t
785get_lq_query(struct lq6_state *lq)
786{
787 struct data_string *lq_query = &lq->lq_query;
788 struct packet *packet = lq->packet;
789 struct option_cache *oc;
790
791 /*
792 * Verify our lq_query structure is empty.
793 */
794 if ((lq_query->data != NULL) || (lq_query->len != 0)) {
795 return DHCP_R_INVALIDARG;
796 }
797
799 if (oc == NULL) {
800 return ISC_R_NOTFOUND;
801 }
802
803 if (!evaluate_option_cache(lq_query, packet, NULL, NULL,
804 packet->options, NULL,
805 &global_scope, oc, MDL)) {
806 return ISC_R_FAILURE;
807 }
808
809 return ISC_R_SUCCESS;
810}
811
812/*
813 * Message validation, RFC 5007 section 4.2.1:
814 * dhcpv6.c:valid_client_msg() - unicast + lq-query option.
815 */
816static int
817valid_query_msg(struct lq6_state *lq) {
818 struct packet *packet = lq->packet;
819 int ret_val = 0;
820 struct option_cache *oc;
821
822 /* INSIST((lq != NULL) || (packet != NULL)); */
823
824 switch (get_client_id(packet, &lq->client_id)) {
825 case ISC_R_SUCCESS:
826 break;
827 case ISC_R_NOTFOUND:
828 log_debug("Discarding %s from %s; "
829 "client identifier missing",
832 goto exit;
833 default:
834 log_error("Error processing %s from %s; "
835 "unable to evaluate Client Identifier",
838 goto exit;
839 }
840
842 if (oc != NULL) {
843 if (evaluate_option_cache(&lq->server_id, packet, NULL, NULL,
844 packet->options, NULL,
845 &global_scope, oc, MDL)) {
846 log_debug("Discarding %s from %s; "
847 "server identifier found "
848 "(CLIENTID %s, SERVERID %s)",
851 print_hex_1(lq->client_id.len,
852 lq->client_id.data, 60),
853 print_hex_2(lq->server_id.len,
854 lq->server_id.data, 60));
855 } else {
856 log_debug("Discarding %s from %s; "
857 "server identifier found "
858 "(CLIENTID %s)",
860 print_hex_1(lq->client_id.len,
861 lq->client_id.data, 60),
863 }
864 goto exit;
865 }
866
867 switch (get_lq_query(lq)) {
868 case ISC_R_SUCCESS:
869 break;
870 case ISC_R_NOTFOUND:
871 log_debug("Discarding %s from %s; lq-query missing",
874 goto exit;
875 default:
876 log_error("Error processing %s from %s; "
877 "unable to evaluate LQ-Query",
880 goto exit;
881 }
882
883 /* looks good */
884 ret_val = 1;
885
886exit:
887 if (!ret_val) {
888 data_string_forget(&lq->client_id, MDL);
889 data_string_forget(&lq->server_id, MDL);
890 data_string_forget(&lq->lq_query, MDL);
891 }
892 return ret_val;
893}
894
895/*
896 * Set an error in a status-code option (from set_status_code).
897 */
898static int
899set_error(struct lq6_state *lq, u_int16_t code, const char *message) {
900 struct data_string d;
901 int ret_val;
902
903 memset(&d, 0, sizeof(d));
904 d.len = sizeof(code) + strlen(message);
905 if (!buffer_allocate(&d.buffer, d.len, MDL)) {
906 log_fatal("set_error: no memory for status code.");
907 }
908 d.data = d.buffer->data;
909 putUShort(d.buffer->data, code);
910 memcpy(d.buffer->data + sizeof(code), message, d.len - sizeof(code));
911 if (!save_option_buffer(&dhcpv6_universe, lq->reply_opts,
912 d.buffer, (unsigned char *)d.data, d.len,
913 D6O_STATUS_CODE, 0)) {
914 log_error("set_error: error saving status code.");
915 ret_val = 0;
916 } else {
917 ret_val = 1;
918 }
920 return ret_val;
921}
922
923/*
924 * Process a by-address lease query.
925 */
926static int
927process_lq_by_address(struct lq6_state *lq) {
928 struct packet *packet = lq->packet;
929 struct option_cache *oc;
930 struct ipv6_pool *pool = NULL;
931 struct data_string data;
932 struct in6_addr addr;
933 struct iasubopt *iaaddr = NULL;
934 struct option_state *opt_state = NULL;
935 u_int32_t lifetime;
936 unsigned opt_cursor;
937 int ret_val = 0;
938
939 /*
940 * Get the IAADDR.
941 */
942 oc = lookup_option(&dhcpv6_universe, lq->query_opts, D6O_IAADDR);
943 if (oc == NULL) {
944 if (!set_error(lq, STATUS_MalformedQuery,
945 "No OPTION_IAADDR.")) {
946 log_error("process_lq_by_address: unable "
947 "to set MalformedQuery status code.");
948 return 0;
949 }
950 return 1;
951 }
952 memset(&data, 0, sizeof(data));
953 if (!evaluate_option_cache(&data, packet,
954 NULL, NULL,
955 lq->query_opts, NULL,
956 &global_scope, oc, MDL) ||
957 (data.len < IAADDR_OFFSET)) {
958 log_error("process_lq_by_address: error evaluating IAADDR.");
959 goto exit;
960 }
961 memcpy(&addr, data.data, sizeof(addr));
962 data_string_forget(&data, MDL);
963
964 /*
965 * Find the lease.
966 * Note the RFC 5007 says to use the link-address to find the link
967 * or the ia-aadr when it is :: but in any case the ia-addr has
968 * to be on the link, so we ignore the link-address here.
969 */
970 if (find_ipv6_pool(&pool, D6O_IA_NA, &addr) != ISC_R_SUCCESS) {
971 if (!set_error(lq, STATUS_NotConfigured,
972 "Address not in a pool.")) {
973 log_error("process_lq_by_address: unable "
974 "to set NotConfigured status code.");
975 goto exit;
976 }
977 ret_val = 1;
978 goto exit;
979 }
980 if (iasubopt_hash_lookup(&iaaddr, pool->leases, &addr,
981 sizeof(addr), MDL) == 0) {
982 ret_val = 1;
983 goto exit;
984 }
985 if ((iaaddr == NULL) || (iaaddr->state != FTS_ACTIVE) ||
986 (iaaddr->ia == NULL) || (iaaddr->ia->iaid_duid.len <= 4)) {
987 ret_val = 1;
988 goto exit;
989 }
990
991 /*
992 * Build the client-data option (with client-id, ia-addr and clt-time).
993 */
994 if (!option_state_allocate(&opt_state, MDL)) {
995 log_error("process_lq_by_address: "
996 "no memory for option state.");
997 goto exit;
998 }
999
1000 data_string_copy(&data, &iaaddr->ia->iaid_duid, MDL);
1001 data.data += 4;
1002 data.len -= 4;
1003 if (!save_option_buffer(&dhcpv6_universe, opt_state,
1004 NULL, (unsigned char *)data.data, data.len,
1005 D6O_CLIENTID, 0)) {
1006 log_error("process_lq_by_address: error saving client ID.");
1007 goto exit;
1008 }
1009 data_string_forget(&data, MDL);
1010
1011 data.len = IAADDR_OFFSET;
1012 if (!buffer_allocate(&data.buffer, data.len, MDL)) {
1013 log_error("process_lq_by_address: no memory for ia-addr.");
1014 goto exit;
1015 }
1016 data.data = data.buffer->data;
1017 memcpy(data.buffer->data, &iaaddr->addr, 16);
1018 lifetime = iaaddr->prefer;
1019 putULong(data.buffer->data + 16, lifetime);
1020 lifetime = iaaddr->valid;
1021 putULong(data.buffer->data + 20, lifetime);
1022 if (!save_option_buffer(&dhcpv6_universe, opt_state,
1023 NULL, (unsigned char *)data.data, data.len,
1024 D6O_IAADDR, 0)) {
1025 log_error("process_lq_by_address: error saving ia-addr.");
1026 goto exit;
1027 }
1028 data_string_forget(&data, MDL);
1029
1030 lifetime = htonl(iaaddr->ia->cltt);
1031 if (!save_option_buffer(&dhcpv6_universe, opt_state,
1032 NULL, (unsigned char *)&lifetime, 4,
1033 D6O_CLT_TIME, 0)) {
1034 log_error("process_lq_by_address: error saving clt time.");
1035 goto exit;
1036 }
1037
1038 /*
1039 * Store the client-data option.
1040 */
1041 opt_cursor = lq->cursor;
1042 putUShort(lq->buf.data + lq->cursor, (unsigned)D6O_CLIENT_DATA);
1043 lq->cursor += 2;
1044 /* Skip option length. */
1045 lq->cursor += 2;
1046
1047 lq->cursor += store_options6((char *)lq->buf.data + lq->cursor,
1048 sizeof(lq->buf) - lq->cursor,
1049 opt_state, lq->packet,
1050 required_opt_CLIENT_DATA, NULL);
1051 /* Reset the length. */
1052 putUShort(lq->buf.data + opt_cursor + 2,
1053 lq->cursor - (opt_cursor + 4));
1054
1055 /* Done. */
1056 ret_val = 1;
1057
1058 exit:
1059 if (data.data != NULL)
1060 data_string_forget(&data, MDL);
1061 if (pool != NULL)
1063 if (iaaddr != NULL)
1064 iasubopt_dereference(&iaaddr, MDL);
1065 if (opt_state != NULL)
1066 option_state_dereference(&opt_state, MDL);
1067 return ret_val;
1068}
1069
1070
1071/*
1072 * Process a lease query.
1073 */
1074void
1075dhcpv6_leasequery(struct data_string *reply_ret, struct packet *packet) {
1076 static struct lq6_state lq;
1077 struct option_cache *oc;
1078 int allow_lq;
1079
1080 /*
1081 * Initialize the lease query state.
1082 */
1083 lq.packet = NULL;
1084 memset(&lq.client_id, 0, sizeof(lq.client_id));
1085 memset(&lq.server_id, 0, sizeof(lq.server_id));
1086 memset(&lq.lq_query, 0, sizeof(lq.lq_query));
1087 lq.query_opts = NULL;
1088 lq.reply_opts = NULL;
1089 packet_reference(&lq.packet, packet, MDL);
1090
1091 /*
1092 * Validate our input.
1093 */
1094 if (!valid_query_msg(&lq)) {
1095 goto exit;
1096 }
1097
1098 /*
1099 * Prepare our reply.
1100 */
1101 if (!option_state_allocate(&lq.reply_opts, MDL)) {
1102 log_error("dhcpv6_leasequery: no memory for option state.");
1103 goto exit;
1104 }
1105 execute_statements_in_scope(NULL, lq.packet, NULL, NULL,
1106 lq.packet->options, lq.reply_opts,
1107 &global_scope, root_group, NULL, NULL);
1108
1109 lq.buf.reply.msg_type = DHCPV6_LEASEQUERY_REPLY;
1110
1111 memcpy(lq.buf.reply.transaction_id,
1112 lq.packet->dhcpv6_transaction_id,
1113 sizeof(lq.buf.reply.transaction_id));
1114
1115 /*
1116 * Because LEASEQUERY has some privacy concerns, default to deny.
1117 */
1118 allow_lq = 0;
1119
1120 /*
1121 * See if we are authorized to do LEASEQUERY.
1122 */
1123 oc = lookup_option(&server_universe, lq.reply_opts, SV_LEASEQUERY);
1124 if (oc != NULL) {
1125 allow_lq = evaluate_boolean_option_cache(NULL,
1126 lq.packet,
1127 NULL, NULL,
1128 lq.packet->options,
1129 lq.reply_opts,
1130 &global_scope,
1131 oc, MDL);
1132 }
1133
1134 if (!allow_lq) {
1135 log_info("dhcpv6_leasequery: not allowed, query ignored.");
1136 goto exit;
1137 }
1138
1139 /*
1140 * Same than transmission of REPLY message in RFC 3315:
1141 * server-id
1142 * client-id
1143 */
1144
1145 oc = lookup_option(&dhcpv6_universe, lq.reply_opts, D6O_SERVERID);
1146 if (oc == NULL) {
1147 /* If not already in options, get from query then global. */
1148 if (lq.server_id.data == NULL)
1149 copy_server_duid(&lq.server_id, MDL);
1151 lq.reply_opts,
1152 NULL,
1153 (unsigned char *)lq.server_id.data,
1154 lq.server_id.len,
1156 0)) {
1157 log_error("dhcpv6_leasequery: "
1158 "error saving server identifier.");
1159 goto exit;
1160 }
1161 }
1162
1164 lq.reply_opts,
1165 lq.client_id.buffer,
1166 (unsigned char *)lq.client_id.data,
1167 lq.client_id.len,
1169 0)) {
1170 log_error("dhcpv6_leasequery: "
1171 "error saving client identifier.");
1172 goto exit;
1173 }
1174
1175 lq.cursor = 4;
1176
1177 /*
1178 * Decode the lq-query option.
1179 */
1180
1181 if (lq.lq_query.len <= LQ_QUERY_OFFSET) {
1182 if (!set_error(&lq, STATUS_MalformedQuery,
1183 "OPTION_LQ_QUERY too short.")) {
1184 log_error("dhcpv6_leasequery: unable "
1185 "to set MalformedQuery status code.");
1186 goto exit;
1187 }
1188 goto done;
1189 }
1190
1191 lq.query_type = lq.lq_query.data [0];
1192 memcpy(&lq.link_addr, lq.lq_query.data + 1, sizeof(lq.link_addr));
1193 switch (lq.query_type) {
1194 case LQ6QT_BY_ADDRESS:
1195 break;
1196 case LQ6QT_BY_CLIENTID:
1197 if (!set_error(&lq, STATUS_UnknownQueryType,
1198 "QUERY_BY_CLIENTID not supported.")) {
1199 log_error("dhcpv6_leasequery: unable to "
1200 "set UnknownQueryType status code.");
1201 goto exit;
1202 }
1203 goto done;
1204 default:
1205 if (!set_error(&lq, STATUS_UnknownQueryType,
1206 "Unknown query-type.")) {
1207 log_error("dhcpv6_leasequery: unable to "
1208 "set UnknownQueryType status code.");
1209 goto exit;
1210 }
1211 goto done;
1212 }
1213
1214 if (!option_state_allocate(&lq.query_opts, MDL)) {
1215 log_error("dhcpv6_leasequery: no memory for option state.");
1216 goto exit;
1217 }
1218 if (!parse_option_buffer(lq.query_opts,
1219 lq.lq_query.data + LQ_QUERY_OFFSET,
1220 lq.lq_query.len - LQ_QUERY_OFFSET,
1221 &dhcpv6_universe)) {
1222 log_error("dhcpv6_leasequery: error parsing query-options.");
1223 if (!set_error(&lq, STATUS_MalformedQuery,
1224 "Bad query-options.")) {
1225 log_error("dhcpv6_leasequery: unable "
1226 "to set MalformedQuery status code.");
1227 goto exit;
1228 }
1229 goto done;
1230 }
1231
1232 /* Do it. */
1233 if (!process_lq_by_address(&lq))
1234 goto exit;
1235
1236 done:
1237 /* Store the options. */
1238 lq.cursor += store_options6((char *)lq.buf.data + lq.cursor,
1239 sizeof(lq.buf) - lq.cursor,
1240 lq.reply_opts,
1241 lq.packet,
1242 required_opts_lq,
1243 NULL);
1244
1245 /* Return our reply to the caller. */
1246 reply_ret->len = lq.cursor;
1247 reply_ret->buffer = NULL;
1248 if (!buffer_allocate(&reply_ret->buffer, lq.cursor, MDL)) {
1249 log_fatal("dhcpv6_leasequery: no memory to store Reply.");
1250 }
1251 memcpy(reply_ret->buffer->data, lq.buf.data, lq.cursor);
1252 reply_ret->data = reply_ret->buffer->data;
1253
1254 exit:
1255 /* Cleanup. */
1256 if (lq.packet != NULL)
1257 packet_dereference(&lq.packet, MDL);
1258 if (lq.client_id.data != NULL)
1259 data_string_forget(&lq.client_id, MDL);
1260 if (lq.server_id.data != NULL)
1261 data_string_forget(&lq.server_id, MDL);
1262 if (lq.lq_query.data != NULL)
1263 data_string_forget(&lq.lq_query, MDL);
1264 if (lq.query_opts != NULL)
1265 option_state_dereference(&lq.query_opts, MDL);
1266 if (lq.reply_opts != NULL)
1267 option_state_dereference(&lq.reply_opts, MDL);
1268}
1269
1270#endif /* DHCPv6 */
int buffer_allocate(struct buffer **ptr, unsigned len, const char *file, int line)
Definition alloc.c:679
void data_string_forget(struct data_string *data, const char *file, int line)
Definition alloc.c:1339
int option_chain_head_reference(struct option_chain_head **ptr, struct option_chain_head *bp, const char *file, int line)
Definition alloc.c:67
int option_state_allocate(struct option_state **ptr, const char *file, int line)
Definition alloc.c:846
int option_state_dereference(struct option_state **ptr, const char *file, int line)
Definition alloc.c:911
int packet_reference(struct packet **ptr, struct packet *bp, const char *file, int line)
Definition alloc.c:1053
int packet_dereference(struct packet **ptr, const char *file, int line)
Definition alloc.c:1081
void data_string_copy(struct data_string *dest, const struct data_string *src, const char *file, int line)
Definition alloc.c:1323
int save_option_buffer(struct universe *universe, struct option_state *options, struct buffer *bp, unsigned char *buffer, unsigned length, unsigned code, int terminatep)
Definition options.c:2545
int get_option(struct data_string *result, struct universe *universe, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct option_state *options, struct binding_scope **scope, unsigned code, const char *file, int line)
Definition options.c:2323
struct option_cache * lookup_option(struct universe *universe, struct option_state *options, unsigned code)
Definition options.c:2503
int store_options6(char *buf, int buflen, struct option_state *opt_state, struct packet *packet, const int *required_opts, struct data_string *oro)
Definition options.c:1048
int add_option(struct option_state *options, unsigned int option_num, void *data, unsigned int data_len)
Definition options.c:4480
int parse_option_buffer(struct option_state *options, const unsigned char *buffer, unsigned length, struct universe *universe)
Definition options.c:119
int cons_options(struct packet *inpacket, struct dhcp_packet *outpacket, struct lease *lease, struct client_state *client_state, int mms, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, int overload_avail, int terminate, int bootpp, struct data_string *prl, const char *vuname)
Definition options.c:538
char * print_hw_addr(int htype, const int hlen, const unsigned char *data) const
Definition print.c:171
void putUShort(unsigned char *, u_int32_t)
Definition convert.c:86
void putULong(unsigned char *, u_int32_t)
Definition convert.c:70
u_int16_t remote_port
Definition discover.c:49
u_int16_t local_port
Definition discover.c:48
int find_subnet(struct subnet **sp, struct iaddr addr, const char *file, int line)
Definition dhclient.c:1567
#define D6O_CLIENT_DATA
Definition dhcp6.h:74
#define D6O_LQ_QUERY
Definition dhcp6.h:73
#define D6O_CLIENTID
Definition dhcp6.h:30
#define D6O_IAPREFIX
Definition dhcp6.h:55
#define D6O_STATUS_CODE
Definition dhcp6.h:42
#define D6O_IAADDR
Definition dhcp6.h:34
#define D6O_CLT_TIME
Definition dhcp6.h:75
#define D6O_SERVERID
Definition dhcp6.h:31
#define D6O_LQ_RELAY_DATA
Definition dhcp6.h:76
#define LQ6QT_BY_ADDRESS
Definition dhcp6.h:264
#define D6O_LQ_CLIENT_LINK
Definition dhcp6.h:77
#define STATUS_NotConfigured
Definition dhcp6.h:133
#define IAADDR_OFFSET
Definition dhcp6.h:178
#define LQ_QUERY_OFFSET
Definition dhcp6.h:184
#define STATUS_UnknownQueryType
Definition dhcp6.h:131
#define STATUS_MalformedQuery
Definition dhcp6.h:132
#define D6O_IA_NA
Definition dhcp6.h:32
#define LQ6QT_BY_CLIENTID
Definition dhcp6.h:265
#define DHCPV6_LEASEQUERY_REPLY
Definition dhcp6.h:154
#define DHO_DHCP_PARAMETER_REQUEST_LIST
Definition dhcp.h:144
#define DHO_VENDOR_CLASS_IDENTIFIER
Definition dhcp.h:149
#define DHCPLEASEUNKNOWN
Definition dhcp.h:180
#define BOOTREPLY
Definition dhcp.h:69
#define DHO_CLIENT_LAST_TRANSACTION_TIME
Definition dhcp.h:157
#define DHO_DHCP_CLIENT_IDENTIFIER
Definition dhcp.h:150
#define DHO_ASSOCIATED_IP
Definition dhcp.h:158
#define DHO_PXE_CLIENT_ID
Definition dhcp.h:159
#define DHO_DHCP_MESSAGE_TYPE
Definition dhcp.h:142
#define DHCPLEASEUNASSIGNED
Definition dhcp.h:179
#define DHO_DHCP_RENEWAL_TIME
Definition dhcp.h:147
#define DHO_DHCP_REBINDING_TIME
Definition dhcp.h:148
#define DHCPLEASEACTIVE
Definition dhcp.h:181
#define DHO_DHCP_LEASE_TIME
Definition dhcp.h:140
u_int16_t dhcp_check_relayport(struct packet *packet)
#define SV_LEASEQUERY
Definition dhcpd.h:759
void dhcpv6_leasequery(struct data_string *, struct packet *)
isc_result_t get_client_id(struct packet *, struct data_string *)
#define MIN_TIME
Definition dhcpd.h:1632
struct universe agent_universe
Definition stables.c:165
int find_lease_by_uid(struct lease **, const unsigned char *, unsigned, const char *, int)
Definition mdb.c:2059
void copy_server_duid(struct data_string *ds, const char *file, int line)
ssize_t send_packet(struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)
#define cur_time
Definition dhcpd.h:2126
int find_lease_by_hw_addr(struct lease **, const unsigned char *, unsigned, const char *, int)
Definition mdb.c:2067
struct universe server_universe
Definition stables.c:176
struct universe dhcp_universe
#define print_hex_2(len, data, limit)
Definition dhcpd.h:2639
#define FTS_ACTIVE
Definition dhcpd.h:538
isc_result_t find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type, const struct in6_addr *addr)
Definition mdb6.c:2291
int find_lease_by_ip_addr(struct lease **, struct iaddr, const char *, int)
Definition mdb.c:2052
isc_result_t ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line)
de-reference an IPv6 pool structure.
Definition mdb6.c:777
isc_result_t iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line)
Definition mdb6.c:261
void get_server_source_address(struct in_addr *from, struct option_state *options, struct option_state *out_options, struct packet *packet)
Definition dhcp.c:5487
#define print_hex_1(len, data, limit)
Definition dhcpd.h:2638
void get_newest_lease(struct lease **retval, struct lease *lease, struct lease *(*next)(const struct lease *))
void dhcpleasequery(struct packet *packet, int ms_nulltp)
u_int16_t relay_port
Definition discover.c:50
struct interface_info * fallback_interface
Definition discover.c:44
void execute_statements_in_scope(struct binding_value **result, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *out_options, struct binding_scope **scope, struct group *group, struct group *limiting_group, struct on_star *on_star)
Definition execute.c:570
const char * piaddr(const struct iaddr addr)
Definition inet.c:579
#define ISC_R_SUCCESS
struct group * root_group
Definition memory.c:31
#define MDL
Definition omapip.h:567
int log_error(const char *,...) __attribute__((__format__(__printf__
int int int log_debug(const char *,...) __attribute__((__format__(__printf__
void log_fatal(const char *,...) __attribute__((__format__(__printf__
int int log_info(const char *,...) __attribute__((__format__(__printf__
#define DHCP_R_INVALIDARG
Definition result.h:49
unsigned char data[1]
Definition tree.h:62
struct group * group
Definition dhcpd.h:1129
struct buffer * buffer
Definition tree.h:77
const unsigned char * data
Definition tree.h:78
unsigned len
Definition tree.h:79
struct in_addr ciaddr
Definition dhcp.h:55
u_int8_t op
Definition dhcp.h:48
struct in_addr giaddr
Definition dhcp.h:58
u_int8_t htype
Definition dhcp.h:49
u_int8_t hlen
Definition dhcp.h:50
unsigned char chaddr[16]
Definition dhcp.h:59
Definition dhcpd.h:962
u_int8_t hlen
Definition dhcpd.h:492
u_int8_t hbuf[HARDWARE_ADDR_LEN+1]
Definition dhcpd.h:493
time_t cltt
Definition dhcpd.h:1687
struct data_string iaid_duid
Definition dhcpd.h:1683
Definition inet.h:31
unsigned char iabuf[16]
Definition inet.h:33
unsigned len
Definition inet.h:32
binding_state_t state
Definition dhcpd.h:1650
u_int32_t prefer
Definition dhcpd.h:1654
struct in6_addr addr
Definition dhcpd.h:1648
u_int32_t valid
Definition dhcpd.h:1655
struct ia_xx * ia
Definition dhcpd.h:1656
ipv6_pool structure
Definition dhcpd.h:1715
Definition dhcpd.h:560
TIME ends
Definition dhcpd.h:570
struct lease * n_uid
Definition dhcpd.h:567
TIME starts
Definition dhcpd.h:570
struct binding_scope * scope
Definition dhcpd.h:575
struct iaddr ip_addr
Definition dhcpd.h:569
struct hardware hardware_addr
Definition dhcpd.h:589
unsigned char * uid
Definition dhcpd.h:585
struct option_chain_head * agent_options
Definition dhcpd.h:580
struct lease * next
Definition dhcpd.h:562
binding_state_t binding_state
Definition dhcpd.h:623
struct lease * n_hw
Definition dhcpd.h:567
unsigned short uid_len
Definition dhcpd.h:586
TIME cltt
Definition dhcpd.h:640
void * universes[1]
Definition dhcpd.h:401
struct dhcp_packet * raw
Definition dhcpd.h:406
unsigned char dhcpv6_msg_type
Definition dhcpd.h:411
struct interface_info * interface
Definition dhcpd.h:433
int class_count
Definition dhcpd.h:454
struct option_state * options
Definition dhcpd.h:449
unsigned packet_length
Definition dhcpd.h:408
struct class * classes[PACKET_MAX_CLASSES]
Definition dhcpd.h:455
struct iaddr client_addr
Definition dhcpd.h:432
Definition dhcpd.h:1029
struct group * group
Definition dhcpd.h:1085
const char * dhcpv6_type_names[]
Definition tables.c:668
struct universe dhcpv6_universe
Definition tables.c:351
int evaluate_option_cache(struct data_string *result, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct option_cache *oc, const char *file, int line)
Definition tree.c:2699
int evaluate_boolean_option_cache(int *ignorep, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct option_cache *oc, const char *file, int line)
Definition tree.c:2733
struct binding_scope * global_scope
Definition tree.c:38
int find_bound_string(struct data_string *value, struct binding_scope *scope, const char *name)
Definition tree.c:4103