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