ISC DHCP  4.4.1
A reference DHCPv4 and DHCPv6 implementation
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 
49 static struct lease*
50 next_hw(const struct lease *lease) {
51  /* INSIST(lease != NULL); */
52  return lease->n_hw;
53 }
54 
55 static struct lease*
56 next_uid(const struct lease *lease) {
57  /* INSIST(lease != NULL); */
58  return lease->n_uid;
59 }
60 
61 void
62 get_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 
95 static int
96 get_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 
127 void
128 dhcpleasequery(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 
214  execute_statements_in_scope(NULL, packet, NULL, NULL, packet->options,
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,
221  &global_scope,
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,
280  &dhcp_universe,
281  packet,
282  NULL,
283  NULL,
284  packet->options,
285  NULL,
286  packet->options,
287  &global_scope,
289  MDL);
290  if (!i)
291  i = get_option(&uid,
292  &dhcp_universe,
293  packet,
294  NULL,
295  NULL,
296  packet->options,
297  NULL,
298  packet->options,
299  &global_scope,
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 {
383  if (lease->binding_state == FTS_ACTIVE) {
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,
430  &lease->hardware_addr.hbuf[1],
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)) {
523  option_state_dereference(&options,
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 
605  packet->raw->op = BOOTREPLY;
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) {
638  evaluate_option_cache(&prl,
639  packet,
640  NULL,
641  NULL,
642  packet->options,
643  options,
644  &global_scope,
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,
659  packet->options,
660  options,
661  &global_scope,
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  */
744 struct 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  */
764 static const int required_opts_lq[] = {
765  D6O_CLIENTID,
766  D6O_SERVERID,
771  0
772 };
773 static const int required_opt_CLIENT_DATA[] = {
774  D6O_CLIENTID,
775  D6O_IAADDR,
776  D6O_IAPREFIX,
777  D6O_CLT_TIME,
778  0
779 };
780 
781 /*
782  * Get the lq-query option from the packet.
783  */
784 static isc_result_t
785 get_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  */
816 static int
817 valid_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 
886 exit:
887  if (!ret_val) {
888  if (lq->client_id.len > 0) {
889  data_string_forget(&lq->client_id, MDL);
890  }
891  if (lq->server_id.len > 0) {
892  data_string_forget(&lq->server_id, MDL);
893  }
894  if (lq->lq_query.len > 0) {
895  data_string_forget(&lq->lq_query, MDL);
896  }
897  }
898  return ret_val;
899 }
900 
901 /*
902  * Set an error in a status-code option (from set_status_code).
903  */
904 static int
905 set_error(struct lq6_state *lq, u_int16_t code, const char *message) {
906  struct data_string d;
907  int ret_val;
908 
909  memset(&d, 0, sizeof(d));
910  d.len = sizeof(code) + strlen(message);
911  if (!buffer_allocate(&d.buffer, d.len, MDL)) {
912  log_fatal("set_error: no memory for status code.");
913  }
914  d.data = d.buffer->data;
915  putUShort(d.buffer->data, code);
916  memcpy(d.buffer->data + sizeof(code), message, d.len - sizeof(code));
917  if (!save_option_buffer(&dhcpv6_universe, lq->reply_opts,
918  d.buffer, (unsigned char *)d.data, d.len,
919  D6O_STATUS_CODE, 0)) {
920  log_error("set_error: error saving status code.");
921  ret_val = 0;
922  } else {
923  ret_val = 1;
924  }
925  data_string_forget(&d, MDL);
926  return ret_val;
927 }
928 
929 /*
930  * Process a by-address lease query.
931  */
932 static int
933 process_lq_by_address(struct lq6_state *lq) {
934  struct packet *packet = lq->packet;
935  struct option_cache *oc;
936  struct ipv6_pool *pool = NULL;
937  struct data_string data;
938  struct in6_addr addr;
939  struct iasubopt *iaaddr = NULL;
940  struct option_state *opt_state = NULL;
941  u_int32_t lifetime;
942  unsigned opt_cursor;
943  int ret_val = 0;
944 
945  /*
946  * Get the IAADDR.
947  */
948  oc = lookup_option(&dhcpv6_universe, lq->query_opts, D6O_IAADDR);
949  if (oc == NULL) {
950  if (!set_error(lq, STATUS_MalformedQuery,
951  "No OPTION_IAADDR.")) {
952  log_error("process_lq_by_address: unable "
953  "to set MalformedQuery status code.");
954  return 0;
955  }
956  return 1;
957  }
958  memset(&data, 0, sizeof(data));
959  if (!evaluate_option_cache(&data, packet,
960  NULL, NULL,
961  lq->query_opts, NULL,
962  &global_scope, oc, MDL) ||
963  (data.len < IAADDR_OFFSET)) {
964  log_error("process_lq_by_address: error evaluating IAADDR.");
965  goto exit;
966  }
967  memcpy(&addr, data.data, sizeof(addr));
968  data_string_forget(&data, MDL);
969 
970  /*
971  * Find the lease.
972  * Note the RFC 5007 says to use the link-address to find the link
973  * or the ia-aadr when it is :: but in any case the ia-addr has
974  * to be on the link, so we ignore the link-address here.
975  */
976  if (find_ipv6_pool(&pool, D6O_IA_NA, &addr) != ISC_R_SUCCESS) {
977  if (!set_error(lq, STATUS_NotConfigured,
978  "Address not in a pool.")) {
979  log_error("process_lq_by_address: unable "
980  "to set NotConfigured status code.");
981  goto exit;
982  }
983  ret_val = 1;
984  goto exit;
985  }
986  if (iasubopt_hash_lookup(&iaaddr, pool->leases, &addr,
987  sizeof(addr), MDL) == 0) {
988  ret_val = 1;
989  goto exit;
990  }
991  if ((iaaddr == NULL) || (iaaddr->state != FTS_ACTIVE) ||
992  (iaaddr->ia == NULL) || (iaaddr->ia->iaid_duid.len <= 4)) {
993  ret_val = 1;
994  goto exit;
995  }
996 
997  /*
998  * Build the client-data option (with client-id, ia-addr and clt-time).
999  */
1000  if (!option_state_allocate(&opt_state, MDL)) {
1001  log_error("process_lq_by_address: "
1002  "no memory for option state.");
1003  goto exit;
1004  }
1005 
1006  data_string_copy(&data, &iaaddr->ia->iaid_duid, MDL);
1007  data.data += 4;
1008  data.len -= 4;
1009  if (!save_option_buffer(&dhcpv6_universe, opt_state,
1010  NULL, (unsigned char *)data.data, data.len,
1011  D6O_CLIENTID, 0)) {
1012  log_error("process_lq_by_address: error saving client ID.");
1013  goto exit;
1014  }
1015  data_string_forget(&data, MDL);
1016 
1017  data.len = IAADDR_OFFSET;
1018  if (!buffer_allocate(&data.buffer, data.len, MDL)) {
1019  log_error("process_lq_by_address: no memory for ia-addr.");
1020  goto exit;
1021  }
1022  data.data = data.buffer->data;
1023  memcpy(data.buffer->data, &iaaddr->addr, 16);
1024  lifetime = iaaddr->prefer;
1025  putULong(data.buffer->data + 16, lifetime);
1026  lifetime = iaaddr->valid;
1027  putULong(data.buffer->data + 20, lifetime);
1028  if (!save_option_buffer(&dhcpv6_universe, opt_state,
1029  NULL, (unsigned char *)data.data, data.len,
1030  D6O_IAADDR, 0)) {
1031  log_error("process_lq_by_address: error saving ia-addr.");
1032  goto exit;
1033  }
1034  data_string_forget(&data, MDL);
1035 
1036  lifetime = htonl(iaaddr->ia->cltt);
1037  if (!save_option_buffer(&dhcpv6_universe, opt_state,
1038  NULL, (unsigned char *)&lifetime, 4,
1039  D6O_CLT_TIME, 0)) {
1040  log_error("process_lq_by_address: error saving clt time.");
1041  goto exit;
1042  }
1043 
1044  /*
1045  * Store the client-data option.
1046  */
1047  opt_cursor = lq->cursor;
1048  putUShort(lq->buf.data + lq->cursor, (unsigned)D6O_CLIENT_DATA);
1049  lq->cursor += 2;
1050  /* Skip option length. */
1051  lq->cursor += 2;
1052 
1053  lq->cursor += store_options6((char *)lq->buf.data + lq->cursor,
1054  sizeof(lq->buf) - lq->cursor,
1055  opt_state, lq->packet,
1056  required_opt_CLIENT_DATA, NULL);
1057  /* Reset the length. */
1058  putUShort(lq->buf.data + opt_cursor + 2,
1059  lq->cursor - (opt_cursor + 4));
1060 
1061  /* Done. */
1062  ret_val = 1;
1063 
1064  exit:
1065  if (data.data != NULL)
1066  data_string_forget(&data, MDL);
1067  if (pool != NULL)
1069  if (iaaddr != NULL)
1070  iasubopt_dereference(&iaaddr, MDL);
1071  if (opt_state != NULL)
1072  option_state_dereference(&opt_state, MDL);
1073  return ret_val;
1074 }
1075 
1076 
1077 /*
1078  * Process a lease query.
1079  */
1080 void
1081 dhcpv6_leasequery(struct data_string *reply_ret, struct packet *packet) {
1082  static struct lq6_state lq;
1083  struct option_cache *oc;
1084  int allow_lq;
1085 
1086  /*
1087  * Initialize the lease query state.
1088  */
1089  lq.packet = NULL;
1090  memset(&lq.client_id, 0, sizeof(lq.client_id));
1091  memset(&lq.server_id, 0, sizeof(lq.server_id));
1092  memset(&lq.lq_query, 0, sizeof(lq.lq_query));
1093  lq.query_opts = NULL;
1094  lq.reply_opts = NULL;
1095  packet_reference(&lq.packet, packet, MDL);
1096 
1097  /*
1098  * Validate our input.
1099  */
1100  if (!valid_query_msg(&lq)) {
1101  goto exit;
1102  }
1103 
1104  /*
1105  * Prepare our reply.
1106  */
1107  if (!option_state_allocate(&lq.reply_opts, MDL)) {
1108  log_error("dhcpv6_leasequery: no memory for option state.");
1109  goto exit;
1110  }
1111  execute_statements_in_scope(NULL, lq.packet, NULL, NULL,
1112  lq.packet->options, lq.reply_opts,
1113  &global_scope, root_group, NULL, NULL);
1114 
1115  lq.buf.reply.msg_type = DHCPV6_LEASEQUERY_REPLY;
1116 
1117  memcpy(lq.buf.reply.transaction_id,
1118  lq.packet->dhcpv6_transaction_id,
1119  sizeof(lq.buf.reply.transaction_id));
1120 
1121  /*
1122  * Because LEASEQUERY has some privacy concerns, default to deny.
1123  */
1124  allow_lq = 0;
1125 
1126  /*
1127  * See if we are authorized to do LEASEQUERY.
1128  */
1129  oc = lookup_option(&server_universe, lq.reply_opts, SV_LEASEQUERY);
1130  if (oc != NULL) {
1131  allow_lq = evaluate_boolean_option_cache(NULL,
1132  lq.packet,
1133  NULL, NULL,
1134  lq.packet->options,
1135  lq.reply_opts,
1136  &global_scope,
1137  oc, MDL);
1138  }
1139 
1140  if (!allow_lq) {
1141  log_info("dhcpv6_leasequery: not allowed, query ignored.");
1142  goto exit;
1143  }
1144 
1145  /*
1146  * Same than transmission of REPLY message in RFC 3315:
1147  * server-id
1148  * client-id
1149  */
1150 
1151  oc = lookup_option(&dhcpv6_universe, lq.reply_opts, D6O_SERVERID);
1152  if (oc == NULL) {
1153  /* If not already in options, get from query then global. */
1154  if (lq.server_id.data == NULL)
1155  copy_server_duid(&lq.server_id, MDL);
1157  lq.reply_opts,
1158  NULL,
1159  (unsigned char *)lq.server_id.data,
1160  lq.server_id.len,
1161  D6O_SERVERID,
1162  0)) {
1163  log_error("dhcpv6_leasequery: "
1164  "error saving server identifier.");
1165  goto exit;
1166  }
1167  }
1168 
1170  lq.reply_opts,
1171  lq.client_id.buffer,
1172  (unsigned char *)lq.client_id.data,
1173  lq.client_id.len,
1174  D6O_CLIENTID,
1175  0)) {
1176  log_error("dhcpv6_leasequery: "
1177  "error saving client identifier.");
1178  goto exit;
1179  }
1180 
1181  lq.cursor = 4;
1182 
1183  /*
1184  * Decode the lq-query option.
1185  */
1186 
1187  if (lq.lq_query.len <= LQ_QUERY_OFFSET) {
1188  if (!set_error(&lq, STATUS_MalformedQuery,
1189  "OPTION_LQ_QUERY too short.")) {
1190  log_error("dhcpv6_leasequery: unable "
1191  "to set MalformedQuery status code.");
1192  goto exit;
1193  }
1194  goto done;
1195  }
1196 
1197  lq.query_type = lq.lq_query.data [0];
1198  memcpy(&lq.link_addr, lq.lq_query.data + 1, sizeof(lq.link_addr));
1199  switch (lq.query_type) {
1200  case LQ6QT_BY_ADDRESS:
1201  break;
1202  case LQ6QT_BY_CLIENTID:
1203  if (!set_error(&lq, STATUS_UnknownQueryType,
1204  "QUERY_BY_CLIENTID not supported.")) {
1205  log_error("dhcpv6_leasequery: unable to "
1206  "set UnknownQueryType status code.");
1207  goto exit;
1208  }
1209  goto done;
1210  default:
1211  if (!set_error(&lq, STATUS_UnknownQueryType,
1212  "Unknown query-type.")) {
1213  log_error("dhcpv6_leasequery: unable to "
1214  "set UnknownQueryType status code.");
1215  goto exit;
1216  }
1217  goto done;
1218  }
1219 
1220  if (!option_state_allocate(&lq.query_opts, MDL)) {
1221  log_error("dhcpv6_leasequery: no memory for option state.");
1222  goto exit;
1223  }
1224  if (!parse_option_buffer(lq.query_opts,
1225  lq.lq_query.data + LQ_QUERY_OFFSET,
1226  lq.lq_query.len - LQ_QUERY_OFFSET,
1227  &dhcpv6_universe)) {
1228  log_error("dhcpv6_leasequery: error parsing query-options.");
1229  if (!set_error(&lq, STATUS_MalformedQuery,
1230  "Bad query-options.")) {
1231  log_error("dhcpv6_leasequery: unable "
1232  "to set MalformedQuery status code.");
1233  goto exit;
1234  }
1235  goto done;
1236  }
1237 
1238  /* Do it. */
1239  if (!process_lq_by_address(&lq))
1240  goto exit;
1241 
1242  done:
1243  /* Store the options. */
1244  lq.cursor += store_options6((char *)lq.buf.data + lq.cursor,
1245  sizeof(lq.buf) - lq.cursor,
1246  lq.reply_opts,
1247  lq.packet,
1248  required_opts_lq,
1249  NULL);
1250 
1251  /* Return our reply to the caller. */
1252  reply_ret->len = lq.cursor;
1253  reply_ret->buffer = NULL;
1254  if (!buffer_allocate(&reply_ret->buffer, lq.cursor, MDL)) {
1255  log_fatal("dhcpv6_leasequery: no memory to store Reply.");
1256  }
1257  memcpy(reply_ret->buffer->data, lq.buf.data, lq.cursor);
1258  reply_ret->data = reply_ret->buffer->data;
1259 
1260  exit:
1261  /* Cleanup. */
1262  if (lq.packet != NULL)
1263  packet_dereference(&lq.packet, MDL);
1264  if (lq.client_id.data != NULL)
1265  data_string_forget(&lq.client_id, MDL);
1266  if (lq.server_id.data != NULL)
1267  data_string_forget(&lq.server_id, MDL);
1268  if (lq.lq_query.data != NULL)
1269  data_string_forget(&lq.lq_query, MDL);
1270  if (lq.query_opts != NULL)
1271  option_state_dereference(&lq.query_opts, MDL);
1272  if (lq.reply_opts != NULL)
1273  option_state_dereference(&lq.reply_opts, MDL);
1274 }
1275 
1276 #endif /* DHCPv6 */
#define BOOTREPLY
Definition: dhcp.h:69
#define D6O_CLT_TIME
Definition: dhcp6.h:75
#define D6O_LQ_CLIENT_LINK
Definition: dhcp6.h:77
#define D6O_IAADDR
Definition: dhcp6.h:34
struct binding_scope * global_scope
Definition: tree.c:38
Definition: dhcpd.h:560
unsigned len
Definition: tree.h:79
const char * piaddr(const struct iaddr addr)
Definition: inet.c:579
u_int8_t hlen
Definition: dhcpd.h:492
#define D6O_STATUS_CODE
Definition: dhcp6.h:42
unsigned char * uid
Definition: dhcpd.h:585
#define DHO_PXE_CLIENT_ID
Definition: dhcp.h:161
void dhcpv6_leasequery(struct data_string *, struct packet *)
Definition: dhcpd.h:1061
struct universe server_universe
Definition: stables.c:176
#define MDL
Definition: omapip.h:567
unsigned char iabuf[16]
Definition: inet.h:33
#define print_hex_1(len, data, limit)
Definition: dhcpd.h:2622
#define DHO_DHCP_PARAMETER_REQUEST_LIST
Definition: dhcp.h:146
u_int8_t hlen
Definition: dhcp.h:50
#define DHCP_R_INVALIDARG
Definition: result.h:48
const char * dhcpv6_type_names[]
Definition: tables.c:661
int int int log_debug(const char *,...) __attribute__((__format__(__printf__
#define IAADDR_OFFSET
Definition: dhcp6.h:178
#define DHO_DHCP_LEASE_TIME
Definition: dhcp.h:142
int find_bound_string(struct data_string *value, struct binding_scope *scope, const char *name)
Definition: tree.c:4103
struct universe dhcp_universe
#define D6O_SERVERID
Definition: dhcp6.h:31
void data_string_forget(struct data_string *data, const char *file, int line)
Definition: alloc.c:1339
struct group * root_group
Definition: memory.c:31
void dhcpleasequery(struct packet *packet, int ms_nulltp)
u_int32_t valid
Definition: dhcpd.h:1639
int log_error(const char *,...) __attribute__((__format__(__printf__
time_t cltt
Definition: dhcpd.h:1671
void copy_server_duid(struct data_string *ds, const char *file, int line)
#define DHO_DHCP_REBINDING_TIME
Definition: dhcp.h:150
unsigned len
Definition: inet.h:32
#define D6O_CLIENTID
Definition: dhcp6.h:30
#define DHO_ASSOCIATED_IP
Definition: dhcp.h:160
struct option_state * options
Definition: dhcpd.h:449
unsigned char dhcpv6_msg_type
Definition: dhcpd.h:411
void log_fatal(const char *,...) __attribute__((__format__(__printf__
int parse_option_buffer(struct option_state *options, const unsigned char *buffer, unsigned length, struct universe *universe)
Definition: options.c:117
void get_server_source_address(struct in_addr *from, struct option_state *options, struct option_state *out_options, struct packet *packet)
Definition: dhcp.c:5380
#define DHO_CLIENT_LAST_TRANSACTION_TIME
Definition: dhcp.h:159
#define LQ_QUERY_OFFSET
Definition: dhcp6.h:184
struct dhcp_packet * raw
Definition: dhcpd.h:406
struct hardware hardware_addr
Definition: dhcpd.h:589
int find_subnet(struct subnet **sp, struct iaddr addr, const char *file, int line)
Definition: dhclient.c:1547
#define D6O_IAPREFIX
Definition: dhcp6.h:55
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:563
u_int8_t htype
Definition: dhcp.h:49
struct interface_info * fallback_interface
Definition: discover.c:42
#define DHCPLEASEACTIVE
Definition: dhcp.h:182
#define STATUS_NotConfigured
Definition: dhcp6.h:133
int option_state_allocate(struct option_state **ptr, const char *file, int line)
Definition: alloc.c:846
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
unsigned char chaddr[16]
Definition: dhcp.h:59
#define MIN_TIME
Definition: dhcpd.h:1616
int packet_reference(struct packet **ptr, struct packet *bp, const char *file, int line)
Definition: alloc.c:1053
Definition: dhcpd.h:1015
binding_state_t binding_state
Definition: dhcpd.h:623
int buffer_allocate(struct buffer **ptr, unsigned len, const char *file, int line)
Definition: alloc.c:679
#define LQ6QT_BY_ADDRESS
Definition: dhcp6.h:264
struct class * classes[PACKET_MAX_CLASSES]
Definition: dhcpd.h:455
struct interface_info * interface
Definition: dhcpd.h:433
void putULong(unsigned char *, u_int32_t)
Definition: convert.c:70
u_int16_t local_port
Definition: dhclient.c:94
Definition: dhcpd.h:405
int find_lease_by_hw_addr(struct lease **, const unsigned char *, unsigned, const char *, int)
Definition: mdb.c:2045
struct data_string iaid_duid
Definition: dhcpd.h:1667
#define cur_time
Definition: dhcpd.h:2110
struct lease * n_hw
Definition: dhcpd.h:567
ssize_t send_packet(struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)
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:533
struct lease * n_uid
Definition: dhcpd.h:567
int index
Definition: tree.h:339
TIME starts
Definition: dhcpd.h:570
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:2507
int add_option(struct option_state *options, unsigned int option_num, void *data, unsigned int data_len)
Definition: options.c:4394
u_int32_t prefer
Definition: dhcpd.h:1638
int option_chain_head_reference(struct option_chain_head **ptr, struct option_chain_head *bp, const char *file, int line)
Definition: alloc.c:67
#define D6O_LQ_QUERY
Definition: dhcp6.h:73
struct option_cache * lookup_option(struct universe *universe, struct option_state *options, unsigned code)
Definition: options.c:2465
int int log_info(const char *,...) __attribute__((__format__(__printf__
binding_state_t state
Definition: dhcpd.h:1634
u_int16_t dhcp_check_relayport(struct packet *packet)
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 find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type, const struct in6_addr *addr)
Definition: mdb6.c:2289
void get_newest_lease(struct lease **retval, struct lease *lease, struct lease *(*next)(const struct lease *))
struct group * group
Definition: dhcpd.h:1071
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:2285
#define DHCPV6_LEASEQUERY_REPLY
Definition: dhcp6.h:154
TIME cltt
Definition: dhcpd.h:640
isc_result_t get_client_id(struct packet *, struct data_string *)
Definition: inet.h:31
ipv6_pool structure
Definition: dhcpd.h:1699
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:1043
unsigned short uid_len
Definition: dhcpd.h:586
struct iaddr ip_addr
Definition: dhcpd.h:569
struct in_addr giaddr
Definition: dhcp.h:58
int option_state_dereference(struct option_state **ptr, const char *file, int line)
Definition: alloc.c:911
Definition: dhcpd.h:948
#define STATUS_UnknownQueryType
Definition: dhcp6.h:131
struct universe dhcpv6_universe
Definition: tables.c:344
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
#define D6O_IA_NA
Definition: dhcp6.h:32
#define print_hex_2(len, data, limit)
Definition: dhcpd.h:2623
#define LQ6QT_BY_CLIENTID
Definition: dhcp6.h:265
int packet_dereference(struct packet **ptr, const char *file, int line)
Definition: alloc.c:1081
#define STATUS_MalformedQuery
Definition: dhcp6.h:132
#define DHCPLEASEUNASSIGNED
Definition: dhcp.h:180
isc_result_t iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line)
Definition: mdb6.c:261
unsigned char data[1]
Definition: tree.h:62
#define D6O_CLIENT_DATA
Definition: dhcp6.h:74
int find_lease_by_uid(struct lease **, const unsigned char *, unsigned, const char *, int)
Definition: mdb.c:2037
u_int8_t hbuf[HARDWARE_ADDR_LEN+1]
Definition: dhcpd.h:493
int class_count
Definition: dhcpd.h:454
struct lease * next
Definition: dhcpd.h:562
#define DHO_VENDOR_CLASS_IDENTIFIER
Definition: dhcp.h:151
struct iaddr client_addr
Definition: dhcpd.h:432
struct universe agent_universe
Definition: stables.c:165
struct ia_xx * ia
Definition: dhcpd.h:1640
u_int16_t remote_port
Definition: dhclient.c:95
#define DHO_DHCP_RENEWAL_TIME
Definition: dhcp.h:149
u_int16_t relay_port
Definition: discover.c:47
#define DHO_DHCP_CLIENT_IDENTIFIER
Definition: dhcp.h:152
void putUShort(unsigned char *, u_int32_t)
Definition: convert.c:86
#define DHCPLEASEUNKNOWN
Definition: dhcp.h:181
struct in6_addr addr
Definition: dhcpd.h:1632
void * universes[1]
Definition: dhcpd.h:401
const unsigned char * data
Definition: tree.h:78
struct in_addr ciaddr
Definition: dhcp.h:55
#define DHO_DHCP_MESSAGE_TYPE
Definition: dhcp.h:144
TIME ends
Definition: dhcpd.h:570
struct binding_scope * scope
Definition: dhcpd.h:575
void data_string_copy(struct data_string *dest, const struct data_string *src, const char *file, int line)
Definition: alloc.c:1323
unsigned packet_length
Definition: dhcpd.h:408
#define D6O_LQ_RELAY_DATA
Definition: dhcp6.h:76
int find_lease_by_ip_addr(struct lease **, struct iaddr, const char *, int)
Definition: mdb.c:2030
u_int8_t op
Definition: dhcp.h:48
#define SV_LEASEQUERY
Definition: dhcpd.h:759
struct buffer * buffer
Definition: tree.h:77
struct group * group
Definition: dhcpd.h:1115
struct option_chain_head * agent_options
Definition: dhcpd.h:580
#define FTS_ACTIVE
Definition: dhcpd.h:538