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