00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "dhcpd.h"
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 static struct lease*
00051 next_hw(const struct lease *lease) {
00052
00053 return lease->n_hw;
00054 }
00055
00056 static struct lease*
00057 next_uid(const struct lease *lease) {
00058
00059 return lease->n_uid;
00060 }
00061
00062 void
00063 get_newest_lease(struct lease **retval,
00064 struct lease *lease,
00065 struct lease *(*next)(const struct lease *)) {
00066
00067 struct lease *p;
00068 struct lease *newest;
00069
00070
00071
00072
00073 *retval = NULL;
00074
00075 if (lease == NULL) {
00076 return;
00077 }
00078
00079 newest = lease;
00080 for (p=next(lease); p != NULL; p=next(p)) {
00081 if (newest->binding_state == FTS_ACTIVE) {
00082 if ((p->binding_state == FTS_ACTIVE) &&
00083 (p->cltt > newest->cltt)) {
00084 newest = p;
00085 }
00086 } else {
00087 if (p->ends > newest->ends) {
00088 newest = p;
00089 }
00090 }
00091 }
00092
00093 lease_reference(retval, newest, MDL);
00094 }
00095
00096 static int
00097 get_associated_ips(const struct lease *lease,
00098 struct lease *(*next)(const struct lease *),
00099 const struct lease *newest,
00100 u_int32_t *associated_ips,
00101 unsigned int associated_ips_size) {
00102
00103 const struct lease *p;
00104 int cnt;
00105
00106
00107
00108
00109 if (lease == NULL) {
00110 return 0;
00111 }
00112
00113 cnt = 0;
00114 for (p=lease; p != NULL; p=next(p)) {
00115 if ((p->binding_state == FTS_ACTIVE) && (p != newest)) {
00116 if (cnt < associated_ips_size) {
00117 memcpy(&associated_ips[cnt],
00118 p->ip_addr.iabuf,
00119 sizeof(associated_ips[cnt]));
00120 }
00121 cnt++;
00122 }
00123 }
00124 return cnt;
00125 }
00126
00127
00128 void
00129 dhcpleasequery(struct packet *packet, int ms_nulltp) {
00130 char msgbuf[256];
00131 char dbg_info[128];
00132 struct iaddr cip;
00133 struct iaddr gip;
00134 struct data_string uid;
00135 struct hardware h;
00136 struct lease *tmp_lease;
00137 struct lease *lease;
00138 int want_associated_ip;
00139 int assoc_ip_cnt;
00140 u_int32_t assoc_ips[40];
00141 const int nassoc_ips = sizeof(assoc_ips) / sizeof(assoc_ips[0]);
00142
00143 unsigned char dhcpMsgType;
00144 const char *dhcp_msg_type_name;
00145 struct subnet *subnet;
00146 struct group *relay_group;
00147 struct option_state *options;
00148 struct option_cache *oc;
00149 int allow_leasequery;
00150 int ignorep;
00151 u_int32_t lease_duration;
00152 u_int32_t time_renewal;
00153 u_int32_t time_rebinding;
00154 u_int32_t time_expiry;
00155 u_int32_t client_last_transaction_time;
00156 struct sockaddr_in to;
00157 struct in_addr siaddr;
00158 struct data_string prl;
00159 struct data_string *prl_ptr;
00160
00161 int i;
00162 struct interface_info *interface;
00163
00164
00165
00166
00167
00168
00169 snprintf(msgbuf, sizeof(msgbuf),
00170 "DHCPLEASEQUERY from %s", inet_ntoa(packet->raw->giaddr));
00171
00172
00173
00174
00175 if (!packet->raw->giaddr.s_addr) {
00176 log_info("%s: missing giaddr, ciaddr is %s, no reply sent",
00177 msgbuf, inet_ntoa(packet->raw->ciaddr));
00178 return;
00179 }
00180
00181
00182
00183
00184
00185
00186
00187
00188 gip.len = sizeof(packet->raw->giaddr);
00189 memcpy(gip.iabuf, &packet->raw->giaddr, sizeof(packet->raw->giaddr));
00190
00191 subnet = NULL;
00192 find_subnet(&subnet, gip, MDL);
00193 if (subnet != NULL)
00194 relay_group = subnet->group;
00195 else
00196 relay_group = root_group;
00197
00198 subnet_dereference(&subnet, MDL);
00199
00200 options = NULL;
00201 if (!option_state_allocate(&options, MDL)) {
00202 log_error("No memory for option state.");
00203 log_info("%s: out of memory, no reply sent", msgbuf);
00204 return;
00205 }
00206
00207 execute_statements_in_scope(NULL, packet, NULL, NULL, packet->options,
00208 options, &global_scope, relay_group,
00209 NULL, NULL);
00210
00211 for (i=packet->class_count-1; i>=0; i--) {
00212 execute_statements_in_scope(NULL, packet, NULL, NULL,
00213 packet->options, options,
00214 &global_scope,
00215 packet->classes[i]->group,
00216 relay_group, NULL);
00217 }
00218
00219
00220
00221
00222 allow_leasequery = 0;
00223
00224
00225
00226
00227 oc = lookup_option(&server_universe, options, SV_LEASEQUERY);
00228 if (oc != NULL) {
00229 allow_leasequery = evaluate_boolean_option_cache(&ignorep,
00230 packet, NULL, NULL, packet->options,
00231 options, &global_scope, oc, MDL);
00232 }
00233
00234 if (!allow_leasequery) {
00235 log_info("%s: LEASEQUERY not allowed, query ignored", msgbuf);
00236 option_state_dereference(&options, MDL);
00237 return;
00238 }
00239
00240
00241
00242
00243
00244 cip.len = sizeof(packet->raw->ciaddr);
00245 memcpy(cip.iabuf, &packet->raw->ciaddr, sizeof(packet->raw->ciaddr));
00246
00247
00248
00249
00250
00251 assoc_ip_cnt = 0;
00252 lease = tmp_lease = NULL;
00253 if (memcmp(cip.iabuf, "\0\0\0", 4)) {
00254
00255 want_associated_ip = 0;
00256
00257 snprintf(dbg_info, sizeof(dbg_info), "IP %s", piaddr(cip));
00258 find_lease_by_ip_addr(&lease, cip, MDL);
00259
00260
00261 } else {
00262
00263 want_associated_ip = 1;
00264
00265
00266
00267
00268
00269
00270
00271 memset(&uid, 0, sizeof(uid));
00272 if (get_option(&uid,
00273 &dhcp_universe,
00274 packet,
00275 NULL,
00276 NULL,
00277 packet->options,
00278 NULL,
00279 packet->options,
00280 &global_scope,
00281 DHO_DHCP_CLIENT_IDENTIFIER,
00282 MDL)) {
00283
00284 snprintf(dbg_info,
00285 sizeof(dbg_info),
00286 "client-id %s",
00287 print_hex_1(uid.len, uid.data, 60));
00288
00289 find_lease_by_uid(&tmp_lease, uid.data, uid.len, MDL);
00290 data_string_forget(&uid, MDL);
00291 get_newest_lease(&lease, tmp_lease, next_uid);
00292 assoc_ip_cnt = get_associated_ips(tmp_lease,
00293 next_uid,
00294 lease,
00295 assoc_ips,
00296 nassoc_ips);
00297
00298 } else {
00299
00300 if (packet->raw->hlen+1 > sizeof(h.hbuf)) {
00301 log_info("%s: hardware length too long, "
00302 "no reply sent", msgbuf);
00303 option_state_dereference(&options, MDL);
00304 return;
00305 }
00306
00307 h.hlen = packet->raw->hlen + 1;
00308 h.hbuf[0] = packet->raw->htype;
00309 memcpy(&h.hbuf[1],
00310 packet->raw->chaddr,
00311 packet->raw->hlen);
00312
00313 snprintf(dbg_info,
00314 sizeof(dbg_info),
00315 "MAC address %s",
00316 print_hw_addr(h.hbuf[0],
00317 h.hlen - 1,
00318 &h.hbuf[1]));
00319
00320 find_lease_by_hw_addr(&tmp_lease, h.hbuf, h.hlen, MDL);
00321 get_newest_lease(&lease, tmp_lease, next_hw);
00322 assoc_ip_cnt = get_associated_ips(tmp_lease,
00323 next_hw,
00324 lease,
00325 assoc_ips,
00326 nassoc_ips);
00327
00328 }
00329
00330 lease_dereference(&tmp_lease, MDL);
00331
00332 if (lease != NULL) {
00333 memcpy(&packet->raw->ciaddr,
00334 lease->ip_addr.iabuf,
00335 sizeof(packet->raw->ciaddr));
00336 }
00337
00338
00339
00340
00341
00342 if (want_associated_ip && (assoc_ip_cnt > nassoc_ips)) {
00343 log_info("%d IP addresses associated with %s, "
00344 "only %d sent in reply.",
00345 assoc_ip_cnt, dbg_info, nassoc_ips);
00346 }
00347 }
00348
00349
00350
00351
00352
00353 snprintf(msgbuf, sizeof(msgbuf),
00354 "DHCPLEASEQUERY from %s for %s",
00355 inet_ntoa(packet->raw->giaddr), dbg_info);
00356
00357
00358
00359
00360 if (lease == NULL) {
00361 dhcpMsgType = DHCPLEASEUNKNOWN;
00362 dhcp_msg_type_name = "DHCPLEASEUNKNOWN";
00363 } else {
00364 if (lease->binding_state == FTS_ACTIVE) {
00365 dhcpMsgType = DHCPLEASEACTIVE;
00366 dhcp_msg_type_name = "DHCPLEASEACTIVE";
00367 } else {
00368 dhcpMsgType = DHCPLEASEUNASSIGNED;
00369 dhcp_msg_type_name = "DHCPLEASEUNASSIGNED";
00370 }
00371 }
00372
00373
00374
00375
00376
00377 if (dhcpMsgType == DHCPLEASEACTIVE)
00378 {
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 option_state_dereference(&options, MDL);
00397
00398 if (!option_state_allocate(&options, MDL)) {
00399 log_error("%s: out of memory, no reply sent", msgbuf);
00400 lease_dereference(&lease, MDL);
00401 return;
00402 }
00403
00404
00405
00406
00407
00408 packet->raw->hlen = lease->hardware_addr.hlen - 1;
00409 packet->raw->htype = lease->hardware_addr.hbuf[0];
00410 memcpy(packet->raw->chaddr,
00411 &lease->hardware_addr.hbuf[1],
00412 sizeof(packet->raw->chaddr));
00413
00414
00415
00416
00417 if (lease->uid_len > 0) {
00418 if (!add_option(options,
00419 DHO_DHCP_CLIENT_IDENTIFIER,
00420 lease->uid,
00421 lease->uid_len)) {
00422 option_state_dereference(&options, MDL);
00423 lease_dereference(&lease, MDL);
00424 log_info("%s: out of memory, no reply sent",
00425 msgbuf);
00426 return;
00427 }
00428 }
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439 lease_duration = lease->ends - lease->starts;
00440 time_renewal = lease->starts +
00441 (lease_duration / 2);
00442 time_rebinding = lease->starts +
00443 (lease_duration / 2) +
00444 (lease_duration / 4) +
00445 (lease_duration / 8);
00446
00447 if (time_renewal > cur_time) {
00448 time_renewal = htonl(time_renewal - cur_time);
00449
00450 if (!add_option(options,
00451 DHO_DHCP_RENEWAL_TIME,
00452 &time_renewal,
00453 sizeof(time_renewal))) {
00454 option_state_dereference(&options, MDL);
00455 lease_dereference(&lease, MDL);
00456 log_info("%s: out of memory, no reply sent",
00457 msgbuf);
00458 return;
00459 }
00460 }
00461
00462 if (time_rebinding > cur_time) {
00463 time_rebinding = htonl(time_rebinding - cur_time);
00464
00465 if (!add_option(options,
00466 DHO_DHCP_REBINDING_TIME,
00467 &time_rebinding,
00468 sizeof(time_rebinding))) {
00469 option_state_dereference(&options, MDL);
00470 lease_dereference(&lease, MDL);
00471 log_info("%s: out of memory, no reply sent",
00472 msgbuf);
00473 return;
00474 }
00475 }
00476
00477 if (lease->ends > cur_time) {
00478 time_expiry = htonl(lease->ends - cur_time);
00479
00480 if (!add_option(options,
00481 DHO_DHCP_LEASE_TIME,
00482 &time_expiry,
00483 sizeof(time_expiry))) {
00484 option_state_dereference(&options, MDL);
00485 lease_dereference(&lease, MDL);
00486 log_info("%s: out of memory, no reply sent",
00487 msgbuf);
00488 return;
00489 }
00490 }
00491
00492
00493 if (lease->scope != NULL) {
00494 struct data_string vendor_class;
00495
00496 memset(&vendor_class, 0, sizeof(vendor_class));
00497
00498 if (find_bound_string(&vendor_class, lease->scope,
00499 "vendor-class-identifier")) {
00500 if (!add_option(options,
00501 DHO_VENDOR_CLASS_IDENTIFIER,
00502 (void *)vendor_class.data,
00503 vendor_class.len)) {
00504 option_state_dereference(&options,
00505 MDL);
00506 lease_dereference(&lease, MDL);
00507 log_error("%s: error adding vendor "
00508 "class identifier, no reply "
00509 "sent", msgbuf);
00510 data_string_forget(&vendor_class, MDL);
00511 return;
00512 }
00513 data_string_forget(&vendor_class, MDL);
00514 }
00515 }
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526 if (lease->agent_options != NULL) {
00527 int idx = agent_universe.index;
00528 struct option_chain_head **tmp1 =
00529 (struct option_chain_head **)
00530 &(options->universes[idx]);
00531 struct option_chain_head *tmp2 =
00532 (struct option_chain_head *)
00533 lease->agent_options;
00534
00535 option_chain_head_reference(tmp1, tmp2, MDL);
00536 }
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546 if (lease->cltt != MIN_TIME) {
00547 if (cur_time > lease->cltt) {
00548 client_last_transaction_time =
00549 htonl(cur_time - lease->cltt);
00550 } else {
00551 client_last_transaction_time = htonl(0);
00552 }
00553 if (!add_option(options,
00554 DHO_CLIENT_LAST_TRANSACTION_TIME,
00555 &client_last_transaction_time,
00556 sizeof(client_last_transaction_time))) {
00557 option_state_dereference(&options, MDL);
00558 lease_dereference(&lease, MDL);
00559 log_info("%s: out of memory, no reply sent",
00560 msgbuf);
00561 return;
00562 }
00563 }
00564
00565
00566
00567
00568 if (want_associated_ip && (assoc_ip_cnt > 0)) {
00569 if (!add_option(options,
00570 DHO_ASSOCIATED_IP,
00571 assoc_ips,
00572 assoc_ip_cnt * sizeof(assoc_ips[0]))) {
00573 option_state_dereference(&options, MDL);
00574 lease_dereference(&lease, MDL);
00575 log_info("%s: out of memory, no reply sent",
00576 msgbuf);
00577 return;
00578 }
00579 }
00580 }
00581
00582
00583
00584
00585
00586 packet->raw->op = BOOTREPLY;
00587
00588
00589
00590
00591 if (!add_option(options,
00592 DHO_DHCP_MESSAGE_TYPE,
00593 &dhcpMsgType,
00594 sizeof(dhcpMsgType))) {
00595 option_state_dereference(&options, MDL);
00596 lease_dereference(&lease, MDL);
00597 log_info("%s: error adding option, no reply sent", msgbuf);
00598 return;
00599 }
00600
00601
00602
00603
00604 log_info("%s", msgbuf);
00605
00606
00607
00608
00609 get_server_source_address(&siaddr, options, options, packet);
00610
00611
00612
00613
00614
00615 memset(&prl, 0, sizeof(prl));
00616 oc = lookup_option(&dhcp_universe, options,
00617 DHO_DHCP_PARAMETER_REQUEST_LIST);
00618 if (oc != NULL) {
00619 evaluate_option_cache(&prl,
00620 packet,
00621 NULL,
00622 NULL,
00623 packet->options,
00624 options,
00625 &global_scope,
00626 oc,
00627 MDL);
00628 }
00629 if (prl.len > 0) {
00630 prl_ptr = &prl;
00631 } else {
00632 prl_ptr = NULL;
00633 }
00634
00635 packet->packet_length = cons_options(packet,
00636 packet->raw,
00637 lease,
00638 NULL,
00639 0,
00640 packet->options,
00641 options,
00642 &global_scope,
00643 0,
00644 0,
00645 0,
00646 prl_ptr,
00647 NULL);
00648
00649 data_string_forget(&prl, MDL);
00650 option_state_dereference(&options, MDL);
00651 lease_dereference(&lease, MDL);
00652
00653 to.sin_family = AF_INET;
00654 #ifdef HAVE_SA_LEN
00655 to.sin_len = sizeof(to);
00656 #endif
00657 memset(to.sin_zero, 0, sizeof(to.sin_zero));
00658
00659
00660
00661
00662 to.sin_addr = packet->raw->giaddr;
00663 if (packet->raw->giaddr.s_addr != htonl(INADDR_LOOPBACK)) {
00664 to.sin_port = local_port;
00665 } else {
00666 to.sin_port = remote_port;
00667 }
00668
00669
00670
00671
00672
00673 if (fallback_interface != NULL) {
00674 interface = fallback_interface;
00675 } else {
00676 interface = packet->interface;
00677 }
00678
00679
00680
00681
00682 log_info("%s to %s for %s (%d associated IPs)",
00683 dhcp_msg_type_name,
00684 inet_ntoa(to.sin_addr), dbg_info, assoc_ip_cnt);
00685
00686 send_packet(interface,
00687 NULL,
00688 packet->raw,
00689 packet->packet_length,
00690 siaddr,
00691 &to,
00692 NULL);
00693 }
00694
00695 #ifdef DHCPv6
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717 struct lq6_state {
00718 struct packet *packet;
00719 struct data_string client_id;
00720 struct data_string server_id;
00721 struct data_string lq_query;
00722 uint8_t query_type;
00723 struct in6_addr link_addr;
00724 struct option_state *query_opts;
00725
00726 struct option_state *reply_opts;
00727 unsigned cursor;
00728 union reply_buffer {
00729 unsigned char data[65536];
00730 struct dhcpv6_packet reply;
00731 } buf;
00732 };
00733
00734
00735
00736
00737 static const int required_opts_lq[] = {
00738 D6O_CLIENTID,
00739 D6O_SERVERID,
00740 D6O_STATUS_CODE,
00741 D6O_CLIENT_DATA,
00742 D6O_LQ_RELAY_DATA,
00743 D6O_LQ_CLIENT_LINK,
00744 0
00745 };
00746 static const int required_opt_CLIENT_DATA[] = {
00747 D6O_CLIENTID,
00748 D6O_IAADDR,
00749 D6O_IAPREFIX,
00750 D6O_CLT_TIME,
00751 0
00752 };
00753
00754
00755
00756
00757 static isc_result_t
00758 get_lq_query(struct lq6_state *lq)
00759 {
00760 struct data_string *lq_query = &lq->lq_query;
00761 struct packet *packet = lq->packet;
00762 struct option_cache *oc;
00763
00764
00765
00766
00767 if ((lq_query->data != NULL) || (lq_query->len != 0)) {
00768 return DHCP_R_INVALIDARG;
00769 }
00770
00771 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_LQ_QUERY);
00772 if (oc == NULL) {
00773 return ISC_R_NOTFOUND;
00774 }
00775
00776 if (!evaluate_option_cache(lq_query, packet, NULL, NULL,
00777 packet->options, NULL,
00778 &global_scope, oc, MDL)) {
00779 return ISC_R_FAILURE;
00780 }
00781
00782 return ISC_R_SUCCESS;
00783 }
00784
00785
00786
00787
00788
00789 static int
00790 valid_query_msg(struct lq6_state *lq) {
00791 struct packet *packet = lq->packet;
00792 int ret_val = 0;
00793 struct option_cache *oc;
00794
00795
00796
00797 switch (get_client_id(packet, &lq->client_id)) {
00798 case ISC_R_SUCCESS:
00799 break;
00800 case ISC_R_NOTFOUND:
00801 log_debug("Discarding %s from %s; "
00802 "client identifier missing",
00803 dhcpv6_type_names[packet->dhcpv6_msg_type],
00804 piaddr(packet->client_addr));
00805 goto exit;
00806 default:
00807 log_error("Error processing %s from %s; "
00808 "unable to evaluate Client Identifier",
00809 dhcpv6_type_names[packet->dhcpv6_msg_type],
00810 piaddr(packet->client_addr));
00811 goto exit;
00812 }
00813
00814 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID);
00815 if (oc != NULL) {
00816 if (evaluate_option_cache(&lq->server_id, packet, NULL, NULL,
00817 packet->options, NULL,
00818 &global_scope, oc, MDL)) {
00819 log_debug("Discarding %s from %s; "
00820 "server identifier found "
00821 "(CLIENTID %s, SERVERID %s)",
00822 dhcpv6_type_names[packet->dhcpv6_msg_type],
00823 piaddr(packet->client_addr),
00824 print_hex_1(lq->client_id.len,
00825 lq->client_id.data, 60),
00826 print_hex_2(lq->server_id.len,
00827 lq->server_id.data, 60));
00828 } else {
00829 log_debug("Discarding %s from %s; "
00830 "server identifier found "
00831 "(CLIENTID %s)",
00832 dhcpv6_type_names[packet->dhcpv6_msg_type],
00833 print_hex_1(lq->client_id.len,
00834 lq->client_id.data, 60),
00835 piaddr(packet->client_addr));
00836 }
00837 goto exit;
00838 }
00839
00840 switch (get_lq_query(lq)) {
00841 case ISC_R_SUCCESS:
00842 break;
00843 case ISC_R_NOTFOUND:
00844 log_debug("Discarding %s from %s; lq-query missing",
00845 dhcpv6_type_names[packet->dhcpv6_msg_type],
00846 piaddr(packet->client_addr));
00847 goto exit;
00848 default:
00849 log_error("Error processing %s from %s; "
00850 "unable to evaluate LQ-Query",
00851 dhcpv6_type_names[packet->dhcpv6_msg_type],
00852 piaddr(packet->client_addr));
00853 goto exit;
00854 }
00855
00856
00857 ret_val = 1;
00858
00859 exit:
00860 if (!ret_val) {
00861 if (lq->client_id.len > 0) {
00862 data_string_forget(&lq->client_id, MDL);
00863 }
00864 if (lq->server_id.len > 0) {
00865 data_string_forget(&lq->server_id, MDL);
00866 }
00867 if (lq->lq_query.len > 0) {
00868 data_string_forget(&lq->lq_query, MDL);
00869 }
00870 }
00871 return ret_val;
00872 }
00873
00874
00875
00876
00877 static int
00878 set_error(struct lq6_state *lq, u_int16_t code, const char *message) {
00879 struct data_string d;
00880 int ret_val;
00881
00882 memset(&d, 0, sizeof(d));
00883 d.len = sizeof(code) + strlen(message);
00884 if (!buffer_allocate(&d.buffer, d.len, MDL)) {
00885 log_fatal("set_error: no memory for status code.");
00886 }
00887 d.data = d.buffer->data;
00888 putUShort(d.buffer->data, code);
00889 memcpy(d.buffer->data + sizeof(code), message, d.len - sizeof(code));
00890 if (!save_option_buffer(&dhcpv6_universe, lq->reply_opts,
00891 d.buffer, (unsigned char *)d.data, d.len,
00892 D6O_STATUS_CODE, 0)) {
00893 log_error("set_error: error saving status code.");
00894 ret_val = 0;
00895 } else {
00896 ret_val = 1;
00897 }
00898 data_string_forget(&d, MDL);
00899 return ret_val;
00900 }
00901
00902
00903
00904
00905 static int
00906 process_lq_by_address(struct lq6_state *lq) {
00907 struct packet *packet = lq->packet;
00908 struct option_cache *oc;
00909 struct ipv6_pool *pool = NULL;
00910 struct data_string data;
00911 struct in6_addr addr;
00912 struct iasubopt *iaaddr = NULL;
00913 struct option_state *opt_state = NULL;
00914 u_int32_t lifetime;
00915 unsigned opt_cursor;
00916 int ret_val = 0;
00917
00918
00919
00920
00921 oc = lookup_option(&dhcpv6_universe, lq->query_opts, D6O_IAADDR);
00922 if (oc == NULL) {
00923 if (!set_error(lq, STATUS_MalformedQuery,
00924 "No OPTION_IAADDR.")) {
00925 log_error("process_lq_by_address: unable "
00926 "to set MalformedQuery status code.");
00927 return 0;
00928 }
00929 return 1;
00930 }
00931 memset(&data, 0, sizeof(data));
00932 if (!evaluate_option_cache(&data, packet,
00933 NULL, NULL,
00934 lq->query_opts, NULL,
00935 &global_scope, oc, MDL) ||
00936 (data.len < IAADDR_OFFSET)) {
00937 log_error("process_lq_by_address: error evaluating IAADDR.");
00938 goto exit;
00939 }
00940 memcpy(&addr, data.data, sizeof(addr));
00941 data_string_forget(&data, MDL);
00942
00943
00944
00945
00946
00947
00948
00949 if (find_ipv6_pool(&pool, D6O_IA_NA, &addr) != ISC_R_SUCCESS) {
00950 if (!set_error(lq, STATUS_NotConfigured,
00951 "Address not in a pool.")) {
00952 log_error("process_lq_by_address: unable "
00953 "to set NotConfigured status code.");
00954 goto exit;
00955 }
00956 ret_val = 1;
00957 goto exit;
00958 }
00959 if (iasubopt_hash_lookup(&iaaddr, pool->leases, &addr,
00960 sizeof(addr), MDL) == 0) {
00961 ret_val = 1;
00962 goto exit;
00963 }
00964 if ((iaaddr == NULL) || (iaaddr->state != FTS_ACTIVE) ||
00965 (iaaddr->ia == NULL) || (iaaddr->ia->iaid_duid.len <= 4)) {
00966 ret_val = 1;
00967 goto exit;
00968 }
00969
00970
00971
00972
00973 if (!option_state_allocate(&opt_state, MDL)) {
00974 log_error("process_lq_by_address: "
00975 "no memory for option state.");
00976 goto exit;
00977 }
00978
00979 data_string_copy(&data, &iaaddr->ia->iaid_duid, MDL);
00980 data.data += 4;
00981 data.len -= 4;
00982 if (!save_option_buffer(&dhcpv6_universe, opt_state,
00983 NULL, (unsigned char *)data.data, data.len,
00984 D6O_CLIENTID, 0)) {
00985 log_error("process_lq_by_address: error saving client ID.");
00986 goto exit;
00987 }
00988 data_string_forget(&data, MDL);
00989
00990 data.len = IAADDR_OFFSET;
00991 if (!buffer_allocate(&data.buffer, data.len, MDL)) {
00992 log_error("process_lq_by_address: no memory for ia-addr.");
00993 goto exit;
00994 }
00995 data.data = data.buffer->data;
00996 memcpy(data.buffer->data, &iaaddr->addr, 16);
00997 lifetime = iaaddr->prefer;
00998 putULong(data.buffer->data + 16, lifetime);
00999 lifetime = iaaddr->valid;
01000 putULong(data.buffer->data + 20, lifetime);
01001 if (!save_option_buffer(&dhcpv6_universe, opt_state,
01002 NULL, (unsigned char *)data.data, data.len,
01003 D6O_IAADDR, 0)) {
01004 log_error("process_lq_by_address: error saving ia-addr.");
01005 goto exit;
01006 }
01007 data_string_forget(&data, MDL);
01008
01009 lifetime = htonl(iaaddr->ia->cltt);
01010 if (!save_option_buffer(&dhcpv6_universe, opt_state,
01011 NULL, (unsigned char *)&lifetime, 4,
01012 D6O_CLT_TIME, 0)) {
01013 log_error("process_lq_by_address: error saving clt time.");
01014 goto exit;
01015 }
01016
01017
01018
01019
01020 opt_cursor = lq->cursor;
01021 putUShort(lq->buf.data + lq->cursor, (unsigned)D6O_CLIENT_DATA);
01022 lq->cursor += 2;
01023
01024 lq->cursor += 2;
01025
01026 lq->cursor += store_options6((char *)lq->buf.data + lq->cursor,
01027 sizeof(lq->buf) - lq->cursor,
01028 opt_state, lq->packet,
01029 required_opt_CLIENT_DATA, NULL);
01030
01031 putUShort(lq->buf.data + opt_cursor + 2,
01032 lq->cursor - (opt_cursor + 4));
01033
01034
01035 ret_val = 1;
01036
01037 exit:
01038 if (data.data != NULL)
01039 data_string_forget(&data, MDL);
01040 if (pool != NULL)
01041 ipv6_pool_dereference(&pool, MDL);
01042 if (iaaddr != NULL)
01043 iasubopt_dereference(&iaaddr, MDL);
01044 if (opt_state != NULL)
01045 option_state_dereference(&opt_state, MDL);
01046 return ret_val;
01047 }
01048
01049
01050
01051
01052
01053 void
01054 dhcpv6_leasequery(struct data_string *reply_ret, struct packet *packet) {
01055 static struct lq6_state lq;
01056 struct option_cache *oc;
01057 int allow_lq;
01058
01059
01060
01061
01062 lq.packet = NULL;
01063 memset(&lq.client_id, 0, sizeof(lq.client_id));
01064 memset(&lq.server_id, 0, sizeof(lq.server_id));
01065 memset(&lq.lq_query, 0, sizeof(lq.lq_query));
01066 lq.query_opts = NULL;
01067 lq.reply_opts = NULL;
01068 packet_reference(&lq.packet, packet, MDL);
01069
01070
01071
01072
01073 if (!valid_query_msg(&lq)) {
01074 goto exit;
01075 }
01076
01077
01078
01079
01080 if (!option_state_allocate(&lq.reply_opts, MDL)) {
01081 log_error("dhcpv6_leasequery: no memory for option state.");
01082 goto exit;
01083 }
01084 execute_statements_in_scope(NULL, lq.packet, NULL, NULL,
01085 lq.packet->options, lq.reply_opts,
01086 &global_scope, root_group, NULL, NULL);
01087
01088 lq.buf.reply.msg_type = DHCPV6_LEASEQUERY_REPLY;
01089
01090 memcpy(lq.buf.reply.transaction_id,
01091 lq.packet->dhcpv6_transaction_id,
01092 sizeof(lq.buf.reply.transaction_id));
01093
01094
01095
01096
01097 allow_lq = 0;
01098
01099
01100
01101
01102 oc = lookup_option(&server_universe, lq.reply_opts, SV_LEASEQUERY);
01103 if (oc != NULL) {
01104 allow_lq = evaluate_boolean_option_cache(NULL,
01105 lq.packet,
01106 NULL, NULL,
01107 lq.packet->options,
01108 lq.reply_opts,
01109 &global_scope,
01110 oc, MDL);
01111 }
01112
01113 if (!allow_lq) {
01114 log_info("dhcpv6_leasequery: not allowed, query ignored.");
01115 goto exit;
01116 }
01117
01118
01119
01120
01121
01122
01123
01124 oc = lookup_option(&dhcpv6_universe, lq.reply_opts, D6O_SERVERID);
01125 if (oc == NULL) {
01126
01127 if (lq.server_id.data == NULL)
01128 copy_server_duid(&lq.server_id, MDL);
01129 if (!save_option_buffer(&dhcpv6_universe,
01130 lq.reply_opts,
01131 NULL,
01132 (unsigned char *)lq.server_id.data,
01133 lq.server_id.len,
01134 D6O_SERVERID,
01135 0)) {
01136 log_error("dhcpv6_leasequery: "
01137 "error saving server identifier.");
01138 goto exit;
01139 }
01140 }
01141
01142 if (!save_option_buffer(&dhcpv6_universe,
01143 lq.reply_opts,
01144 lq.client_id.buffer,
01145 (unsigned char *)lq.client_id.data,
01146 lq.client_id.len,
01147 D6O_CLIENTID,
01148 0)) {
01149 log_error("dhcpv6_leasequery: "
01150 "error saving client identifier.");
01151 goto exit;
01152 }
01153
01154 lq.cursor = 4;
01155
01156
01157
01158
01159
01160 if (lq.lq_query.len <= LQ_QUERY_OFFSET) {
01161 if (!set_error(&lq, STATUS_MalformedQuery,
01162 "OPTION_LQ_QUERY too short.")) {
01163 log_error("dhcpv6_leasequery: unable "
01164 "to set MalformedQuery status code.");
01165 goto exit;
01166 }
01167 goto done;
01168 }
01169
01170 lq.query_type = lq.lq_query.data [0];
01171 memcpy(&lq.link_addr, lq.lq_query.data + 1, sizeof(lq.link_addr));
01172 switch (lq.query_type) {
01173 case LQ6QT_BY_ADDRESS:
01174 break;
01175 case LQ6QT_BY_CLIENTID:
01176 if (!set_error(&lq, STATUS_UnknownQueryType,
01177 "QUERY_BY_CLIENTID not supported.")) {
01178 log_error("dhcpv6_leasequery: unable to "
01179 "set UnknownQueryType status code.");
01180 goto exit;
01181 }
01182 goto done;
01183 default:
01184 if (!set_error(&lq, STATUS_UnknownQueryType,
01185 "Unknown query-type.")) {
01186 log_error("dhcpv6_leasequery: unable to "
01187 "set UnknownQueryType status code.");
01188 goto exit;
01189 }
01190 goto done;
01191 }
01192
01193 if (!option_state_allocate(&lq.query_opts, MDL)) {
01194 log_error("dhcpv6_leasequery: no memory for option state.");
01195 goto exit;
01196 }
01197 if (!parse_option_buffer(lq.query_opts,
01198 lq.lq_query.data + LQ_QUERY_OFFSET,
01199 lq.lq_query.len - LQ_QUERY_OFFSET,
01200 &dhcpv6_universe)) {
01201 log_error("dhcpv6_leasequery: error parsing query-options.");
01202 if (!set_error(&lq, STATUS_MalformedQuery,
01203 "Bad query-options.")) {
01204 log_error("dhcpv6_leasequery: unable "
01205 "to set MalformedQuery status code.");
01206 goto exit;
01207 }
01208 goto done;
01209 }
01210
01211
01212 if (!process_lq_by_address(&lq))
01213 goto exit;
01214
01215 done:
01216
01217 lq.cursor += store_options6((char *)lq.buf.data + lq.cursor,
01218 sizeof(lq.buf) - lq.cursor,
01219 lq.reply_opts,
01220 lq.packet,
01221 required_opts_lq,
01222 NULL);
01223
01224
01225 reply_ret->len = lq.cursor;
01226 reply_ret->buffer = NULL;
01227 if (!buffer_allocate(&reply_ret->buffer, lq.cursor, MDL)) {
01228 log_fatal("dhcpv6_leasequery: no memory to store Reply.");
01229 }
01230 memcpy(reply_ret->buffer->data, lq.buf.data, lq.cursor);
01231 reply_ret->data = reply_ret->buffer->data;
01232
01233 exit:
01234
01235 if (lq.packet != NULL)
01236 packet_dereference(&lq.packet, MDL);
01237 if (lq.client_id.data != NULL)
01238 data_string_forget(&lq.client_id, MDL);
01239 if (lq.server_id.data != NULL)
01240 data_string_forget(&lq.server_id, MDL);
01241 if (lq.lq_query.data != NULL)
01242 data_string_forget(&lq.lq_query, MDL);
01243 if (lq.query_opts != NULL)
01244 option_state_dereference(&lq.query_opts, MDL);
01245 if (lq.reply_opts != NULL)
01246 option_state_dereference(&lq.reply_opts, MDL);
01247 }
01248
01249 #endif