00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00019 #include "dhcpd.h"
00020 #include "trace.h"
00021
00022 #ifdef DHCPv6
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 struct reply_state {
00046
00047 struct shared_network *shared;
00048 struct host_decl *host;
00049 struct subnet *subnet;
00050 struct option_state *opt_state;
00051 struct packet *packet;
00052 struct data_string client_id;
00053
00054
00055 unsigned ia_count;
00056 unsigned pd_count;
00057 unsigned client_resources;
00058 isc_boolean_t resources_included;
00059 isc_boolean_t static_lease;
00060 unsigned static_prefixes;
00061 struct ia_xx *ia;
00062 struct ia_xx *old_ia;
00063 struct option_state *reply_ia;
00064 struct data_string fixed;
00065 struct iaddrcidrnet fixed_pref;
00066
00067
00068 struct iasubopt *lease;
00069
00070
00071
00072
00073
00074 u_int32_t renew, rebind, prefer, valid;
00075
00076
00077 u_int32_t client_valid, client_prefer;
00078
00079
00080 u_int32_t send_valid, send_prefer;
00081
00082
00083 int preflen;
00084
00085
00086 unsigned cursor;
00087
00088
00089 struct on_star on_star;
00090
00091 union reply_buffer {
00092 unsigned char data[65536];
00093 struct dhcpv6_packet reply;
00094 } buf;
00095 };
00096
00097
00098
00099
00100 static int get_encapsulated_IA_state(struct option_state **enc_opt_state,
00101 struct data_string *enc_opt_data,
00102 struct packet *packet,
00103 struct option_cache *oc,
00104 int offset);
00105 static void build_dhcpv6_reply(struct data_string *, struct packet *);
00106 static isc_result_t shared_network_from_packet6(struct shared_network **shared,
00107 struct packet *packet);
00108 static void seek_shared_host(struct host_decl **hp,
00109 struct shared_network *shared);
00110 static isc_boolean_t fixed_matches_shared(struct host_decl *host,
00111 struct shared_network *shared);
00112 static isc_result_t reply_process_ia_na(struct reply_state *reply,
00113 struct option_cache *ia);
00114 static isc_result_t reply_process_ia_ta(struct reply_state *reply,
00115 struct option_cache *ia);
00116 static isc_result_t reply_process_addr(struct reply_state *reply,
00117 struct option_cache *addr);
00118 static isc_boolean_t address_is_owned(struct reply_state *reply,
00119 struct iaddr *addr);
00120 static isc_boolean_t temporary_is_available(struct reply_state *reply,
00121 struct iaddr *addr);
00122 static isc_result_t find_client_temporaries(struct reply_state *reply);
00123 static isc_result_t reply_process_try_addr(struct reply_state *reply,
00124 struct iaddr *addr);
00125 static isc_result_t find_client_address(struct reply_state *reply);
00126 static isc_result_t reply_process_is_addressed(struct reply_state *reply,
00127 struct binding_scope **scope,
00128 struct group *group);
00129 static isc_result_t reply_process_send_addr(struct reply_state *reply,
00130 struct iaddr *addr);
00131 static struct iasubopt *lease_compare(struct iasubopt *alpha,
00132 struct iasubopt *beta);
00133 static isc_result_t reply_process_ia_pd(struct reply_state *reply,
00134 struct option_cache *ia_pd);
00135 static isc_result_t reply_process_prefix(struct reply_state *reply,
00136 struct option_cache *pref);
00137 static isc_boolean_t prefix_is_owned(struct reply_state *reply,
00138 struct iaddrcidrnet *pref);
00139 static isc_result_t find_client_prefix(struct reply_state *reply);
00140 static isc_result_t reply_process_try_prefix(struct reply_state *reply,
00141 struct iaddrcidrnet *pref);
00142 static isc_result_t reply_process_is_prefixed(struct reply_state *reply,
00143 struct binding_scope **scope,
00144 struct group *group);
00145 static isc_result_t reply_process_send_prefix(struct reply_state *reply,
00146 struct iaddrcidrnet *pref);
00147 static struct iasubopt *prefix_compare(struct reply_state *reply,
00148 struct iasubopt *alpha,
00149 struct iasubopt *beta);
00150 static int find_hosts_by_duid_chaddr(struct host_decl **host,
00151 const struct data_string *client_id);
00152
00153
00154
00155
00156 static u_int32_t
00157 duid_time(time_t when) {
00158
00159
00160
00161 while ((when - DUID_TIME_EPOCH) > 4294967295u) {
00162
00163 when -= 2147483648u;
00164 when -= 2147483648u;
00165 }
00166
00167 return when - DUID_TIME_EPOCH;
00168 }
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187 static struct data_string server_duid;
00188
00189
00190
00191
00192 isc_boolean_t
00193 server_duid_isset(void) {
00194 return (server_duid.data != NULL);
00195 }
00196
00197
00198
00199
00200 void
00201 copy_server_duid(struct data_string *ds, const char *file, int line) {
00202 data_string_copy(ds, &server_duid, file, line);
00203 }
00204
00205
00206
00207
00208
00209
00210 void
00211 set_server_duid(struct data_string *new_duid) {
00212
00213
00214
00215 if (server_duid_isset()) {
00216 data_string_forget(&server_duid, MDL);
00217 }
00218 data_string_copy(&server_duid, new_duid, MDL);
00219 }
00220
00221
00222
00223
00224
00225
00226
00227 isc_result_t
00228 set_server_duid_from_option(void) {
00229 struct option_state *opt_state;
00230 struct option_cache *oc;
00231 struct data_string option_duid;
00232 isc_result_t ret_val;
00233
00234 opt_state = NULL;
00235 if (!option_state_allocate(&opt_state, MDL)) {
00236 log_fatal("No memory for server DUID.");
00237 }
00238
00239 execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL,
00240 opt_state, &global_scope, root_group,
00241 NULL, NULL);
00242
00243 oc = lookup_option(&dhcpv6_universe, opt_state, D6O_SERVERID);
00244 if (oc == NULL) {
00245 ret_val = ISC_R_NOTFOUND;
00246 } else {
00247 memset(&option_duid, 0, sizeof(option_duid));
00248 if (!evaluate_option_cache(&option_duid, NULL, NULL, NULL,
00249 opt_state, NULL, &global_scope,
00250 oc, MDL)) {
00251 ret_val = ISC_R_UNEXPECTED;
00252 } else {
00253 set_server_duid(&option_duid);
00254 data_string_forget(&option_duid, MDL);
00255 ret_val = ISC_R_SUCCESS;
00256 }
00257 }
00258
00259 option_state_dereference(&opt_state, MDL);
00260
00261 return ret_val;
00262 }
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274 static int server_duid_type = DUID_LLT;
00275
00276
00277
00278
00279 void
00280 set_server_duid_type(int type) {
00281 server_duid_type = type;
00282 }
00283
00284
00285
00286
00287
00288 isc_result_t
00289 generate_new_server_duid(void) {
00290 struct interface_info *p;
00291 u_int32_t time_val;
00292 struct data_string generated_duid;
00293
00294
00295
00296
00297 if ((server_duid_type != DUID_LL) && (server_duid_type != DUID_LLT)) {
00298 log_error("Invalid DUID type %d specified, "
00299 "only LL and LLT types supported", server_duid_type);
00300 return DHCP_R_INVALIDARG;
00301 }
00302
00303
00304
00305
00306
00307 for (p = interfaces; p != NULL; p = p->next) {
00308 if (p->hw_address.hlen > 0) {
00309 break;
00310 }
00311 if (p->next == NULL && p->hw_address.hbuf[0] == HTYPE_RESERVED) {
00312 log_error("Can not generate DUID from interfaces which do not have hardware addresses, please configure server-duid!");
00313 }
00314 }
00315 if (p == NULL) {
00316 return ISC_R_UNEXPECTED;
00317 }
00318
00319
00320
00321
00322 memset(&generated_duid, 0, sizeof(generated_duid));
00323 if (server_duid_type == DUID_LLT) {
00324 time_val = duid_time(time(NULL));
00325 generated_duid.len = 8 + p->hw_address.hlen - 1;
00326 if (!buffer_allocate(&generated_duid.buffer,
00327 generated_duid.len, MDL)) {
00328 log_fatal("No memory for server DUID.");
00329 }
00330 generated_duid.data = generated_duid.buffer->data;
00331 putUShort(generated_duid.buffer->data, DUID_LLT);
00332 putUShort(generated_duid.buffer->data + 2,
00333 p->hw_address.hbuf[0]);
00334 putULong(generated_duid.buffer->data + 4, time_val);
00335 memcpy(generated_duid.buffer->data + 8,
00336 p->hw_address.hbuf+1, p->hw_address.hlen-1);
00337 } else if (server_duid_type == DUID_LL) {
00338 generated_duid.len = 4 + p->hw_address.hlen - 1;
00339 if (!buffer_allocate(&generated_duid.buffer,
00340 generated_duid.len, MDL)) {
00341 log_fatal("No memory for server DUID.");
00342 }
00343 generated_duid.data = generated_duid.buffer->data;
00344 putUShort(generated_duid.buffer->data, DUID_LL);
00345 putUShort(generated_duid.buffer->data + 2,
00346 p->hw_address.hbuf[0]);
00347 memcpy(generated_duid.buffer->data + 4,
00348 p->hw_address.hbuf+1, p->hw_address.hlen-1);
00349 } else {
00350 log_fatal("Unsupported server DUID type %d.", server_duid_type);
00351 }
00352
00353 set_server_duid(&generated_duid);
00354 data_string_forget(&generated_duid, MDL);
00355
00356 return ISC_R_SUCCESS;
00357 }
00358
00359
00360
00361
00362 static isc_boolean_t unicast_option_defined;
00363
00364
00365
00366
00367
00368 static isc_boolean_t unicast_option_parsed = ISC_FALSE;
00369
00370
00371
00372
00373
00374 isc_boolean_t
00375 is_unicast_option_defined(void) {
00376 struct option_state *opt_state;
00377 struct option_cache *oc;
00378
00379
00380
00381
00382 if (unicast_option_parsed == ISC_FALSE) {
00383 unicast_option_parsed = ISC_TRUE;
00384 opt_state = NULL;
00385 if (!option_state_allocate(&opt_state, MDL)) {
00386 log_fatal("No memory for option state.");
00387 }
00388
00389 execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL,
00390 opt_state, &global_scope, root_group, NULL, NULL);
00391
00392 oc = lookup_option(&dhcpv6_universe, opt_state, D6O_UNICAST);
00393 unicast_option_defined = (oc != NULL);
00394
00395 option_state_dereference(&opt_state, MDL);
00396 }
00397
00398 return (unicast_option_defined);
00399 }
00400
00401
00402
00403
00404 isc_result_t
00405 get_client_id(struct packet *packet, struct data_string *client_id) {
00406 struct option_cache *oc;
00407
00408
00409
00410
00411 if ((client_id->data != NULL) || (client_id->len != 0)) {
00412 return DHCP_R_INVALIDARG;
00413 }
00414
00415 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_CLIENTID);
00416 if (oc == NULL) {
00417 return ISC_R_NOTFOUND;
00418 }
00419
00420 if (!evaluate_option_cache(client_id, packet, NULL, NULL,
00421 packet->options, NULL,
00422 &global_scope, oc, MDL)) {
00423 return ISC_R_FAILURE;
00424 }
00425
00426 return ISC_R_SUCCESS;
00427 }
00428
00429
00430
00431
00432
00433
00434
00435
00436 int
00437 valid_client_msg(struct packet *packet, struct data_string *client_id) {
00438 int ret_val;
00439 struct option_cache *oc;
00440 struct data_string data;
00441
00442 ret_val = 0;
00443 memset(client_id, 0, sizeof(*client_id));
00444 memset(&data, 0, sizeof(data));
00445
00446 switch (get_client_id(packet, client_id)) {
00447 case ISC_R_SUCCESS:
00448 break;
00449 case ISC_R_NOTFOUND:
00450 log_debug("Discarding %s from %s; "
00451 "client identifier missing",
00452 dhcpv6_type_names[packet->dhcpv6_msg_type],
00453 piaddr(packet->client_addr));
00454 goto exit;
00455 default:
00456 log_error("Error processing %s from %s; "
00457 "unable to evaluate Client Identifier",
00458 dhcpv6_type_names[packet->dhcpv6_msg_type],
00459 piaddr(packet->client_addr));
00460 goto exit;
00461 }
00462
00463
00464
00465
00466 if (packet->unicast) {
00467 log_debug("Discarding %s from %s; packet sent unicast "
00468 "(CLIENTID %s)",
00469 dhcpv6_type_names[packet->dhcpv6_msg_type],
00470 piaddr(packet->client_addr),
00471 print_hex_1(client_id->len, client_id->data, 60));
00472 goto exit;
00473 }
00474
00475
00476 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID);
00477 if (oc != NULL) {
00478 if (evaluate_option_cache(&data, packet, NULL, NULL,
00479 packet->options, NULL,
00480 &global_scope, oc, MDL)) {
00481 log_debug("Discarding %s from %s; "
00482 "server identifier found "
00483 "(CLIENTID %s, SERVERID %s)",
00484 dhcpv6_type_names[packet->dhcpv6_msg_type],
00485 piaddr(packet->client_addr),
00486 print_hex_1(client_id->len,
00487 client_id->data, 60),
00488 print_hex_2(data.len,
00489 data.data, 60));
00490 } else {
00491 log_debug("Discarding %s from %s; "
00492 "server identifier found "
00493 "(CLIENTID %s)",
00494 dhcpv6_type_names[packet->dhcpv6_msg_type],
00495 print_hex_1(client_id->len,
00496 client_id->data, 60),
00497 piaddr(packet->client_addr));
00498 }
00499 goto exit;
00500 }
00501
00502
00503 ret_val = 1;
00504
00505 exit:
00506 if (data.len > 0) {
00507 data_string_forget(&data, MDL);
00508 }
00509 if (!ret_val) {
00510 if (client_id->len > 0) {
00511 data_string_forget(client_id, MDL);
00512 }
00513 }
00514 return ret_val;
00515 }
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529 int
00530 valid_client_resp(struct packet *packet,
00531 struct data_string *client_id,
00532 struct data_string *server_id)
00533 {
00534 int ret_val;
00535 struct option_cache *oc;
00536
00537
00538
00539 ret_val = 0;
00540 memset(client_id, 0, sizeof(*client_id));
00541 memset(server_id, 0, sizeof(*server_id));
00542
00543 switch (get_client_id(packet, client_id)) {
00544 case ISC_R_SUCCESS:
00545 break;
00546 case ISC_R_NOTFOUND:
00547 log_debug("Discarding %s from %s; "
00548 "client identifier missing",
00549 dhcpv6_type_names[packet->dhcpv6_msg_type],
00550 piaddr(packet->client_addr));
00551 goto exit;
00552 default:
00553 log_error("Error processing %s from %s; "
00554 "unable to evaluate Client Identifier",
00555 dhcpv6_type_names[packet->dhcpv6_msg_type],
00556 piaddr(packet->client_addr));
00557 goto exit;
00558 }
00559
00560 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID);
00561 if (oc == NULL) {
00562 log_debug("Discarding %s from %s: "
00563 "server identifier missing (CLIENTID %s)",
00564 dhcpv6_type_names[packet->dhcpv6_msg_type],
00565 piaddr(packet->client_addr),
00566 print_hex_1(client_id->len, client_id->data, 60));
00567 goto exit;
00568 }
00569 if (!evaluate_option_cache(server_id, packet, NULL, NULL,
00570 packet->options, NULL,
00571 &global_scope, oc, MDL)) {
00572 log_error("Error processing %s from %s; "
00573 "unable to evaluate Server Identifier (CLIENTID %s)",
00574 dhcpv6_type_names[packet->dhcpv6_msg_type],
00575 piaddr(packet->client_addr),
00576 print_hex_1(client_id->len, client_id->data, 60));
00577 goto exit;
00578 }
00579 if ((server_duid.len != server_id->len) ||
00580 (memcmp(server_duid.data, server_id->data, server_duid.len) != 0)) {
00581 log_debug("Discarding %s from %s; "
00582 "not our server identifier "
00583 "(CLIENTID %s, SERVERID %s, server DUID %s)",
00584 dhcpv6_type_names[packet->dhcpv6_msg_type],
00585 piaddr(packet->client_addr),
00586 print_hex_1(client_id->len, client_id->data, 60),
00587 print_hex_2(server_id->len, server_id->data, 60),
00588 print_hex_3(server_duid.len, server_duid.data, 60));
00589 goto exit;
00590 }
00591
00592
00593 ret_val = 1;
00594
00595 exit:
00596 if (!ret_val) {
00597 if (server_id->len > 0) {
00598 data_string_forget(server_id, MDL);
00599 }
00600 if (client_id->len > 0) {
00601 data_string_forget(client_id, MDL);
00602 }
00603 }
00604 return ret_val;
00605 }
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618 int
00619 valid_client_info_req(struct packet *packet, struct data_string *server_id) {
00620 int ret_val;
00621 struct option_cache *oc;
00622 struct data_string client_id;
00623 char client_id_str[80];
00624
00625
00626 ret_val = 0;
00627 memset(server_id, 0, sizeof(*server_id));
00628 memset(&client_id, 0, sizeof(client_id));
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638 if (get_client_id(packet, &client_id) == ISC_R_SUCCESS) {
00639 snprintf(client_id_str, sizeof(client_id_str), " (CLIENTID %s)",
00640 print_hex_1(client_id.len, client_id.data, 60));
00641 data_string_forget(&client_id, MDL);
00642 } else {
00643 client_id_str[0] = '\0';
00644 }
00645
00646
00647
00648
00649 if (packet->unicast) {
00650 log_debug("Discarding %s from %s; packet sent unicast%s",
00651 dhcpv6_type_names[packet->dhcpv6_msg_type],
00652 piaddr(packet->client_addr), client_id_str);
00653 goto exit;
00654 }
00655
00656 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA);
00657 if (oc != NULL) {
00658 log_debug("Discarding %s from %s; "
00659 "IA_NA option present%s",
00660 dhcpv6_type_names[packet->dhcpv6_msg_type],
00661 piaddr(packet->client_addr), client_id_str);
00662 goto exit;
00663 }
00664 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_TA);
00665 if (oc != NULL) {
00666 log_debug("Discarding %s from %s; "
00667 "IA_TA option present%s",
00668 dhcpv6_type_names[packet->dhcpv6_msg_type],
00669 piaddr(packet->client_addr), client_id_str);
00670 goto exit;
00671 }
00672 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_PD);
00673 if (oc != NULL) {
00674 log_debug("Discarding %s from %s; "
00675 "IA_PD option present%s",
00676 dhcpv6_type_names[packet->dhcpv6_msg_type],
00677 piaddr(packet->client_addr), client_id_str);
00678 goto exit;
00679 }
00680
00681 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID);
00682 if (oc != NULL) {
00683 if (!evaluate_option_cache(server_id, packet, NULL, NULL,
00684 packet->options, NULL,
00685 &global_scope, oc, MDL)) {
00686 log_error("Error processing %s from %s; "
00687 "unable to evaluate Server Identifier%s",
00688 dhcpv6_type_names[packet->dhcpv6_msg_type],
00689 piaddr(packet->client_addr), client_id_str);
00690 goto exit;
00691 }
00692 if ((server_duid.len != server_id->len) ||
00693 (memcmp(server_duid.data, server_id->data,
00694 server_duid.len) != 0)) {
00695 log_debug("Discarding %s from %s; "
00696 "not our server identifier "
00697 "(SERVERID %s, server DUID %s)%s",
00698 dhcpv6_type_names[packet->dhcpv6_msg_type],
00699 piaddr(packet->client_addr),
00700 print_hex_1(server_id->len,
00701 server_id->data, 60),
00702 print_hex_2(server_duid.len,
00703 server_duid.data, 60),
00704 client_id_str);
00705 goto exit;
00706 }
00707 }
00708
00709
00710 ret_val = 1;
00711
00712 exit:
00713 if (!ret_val) {
00714 if (server_id->len > 0) {
00715 data_string_forget(server_id, MDL);
00716 }
00717 }
00718 return ret_val;
00719 }
00720
00721
00722
00723
00724
00725 static const int required_opts[] = {
00726 D6O_CLIENTID,
00727 D6O_SERVERID,
00728 D6O_STATUS_CODE,
00729 D6O_PREFERENCE,
00730 0
00731 };
00732 static const int required_opts_NAA[] = {
00733 D6O_CLIENTID,
00734 D6O_SERVERID,
00735 D6O_STATUS_CODE,
00736 0
00737 };
00738 static const int required_opts_solicit[] = {
00739 D6O_CLIENTID,
00740 D6O_SERVERID,
00741 D6O_IA_NA,
00742 D6O_IA_TA,
00743 D6O_IA_PD,
00744 D6O_RAPID_COMMIT,
00745 D6O_STATUS_CODE,
00746 D6O_RECONF_ACCEPT,
00747 D6O_PREFERENCE,
00748 0
00749 };
00750 static const int required_opts_agent[] = {
00751 D6O_INTERFACE_ID,
00752 D6O_RELAY_MSG,
00753 0
00754 };
00755 static const int required_opts_IA[] = {
00756 D6O_IAADDR,
00757 D6O_STATUS_CODE,
00758 0
00759 };
00760 static const int required_opts_IA_PD[] = {
00761 D6O_IAPREFIX,
00762 D6O_STATUS_CODE,
00763 0
00764 };
00765 static const int required_opts_STATUS_CODE[] = {
00766 D6O_STATUS_CODE,
00767 0
00768 };
00769
00770
00771
00772
00773
00774
00775
00776 static int
00777 get_encapsulated_IA_state(struct option_state **enc_opt_state,
00778 struct data_string *enc_opt_data,
00779 struct packet *packet,
00780 struct option_cache *oc,
00781 int offset)
00782 {
00783
00784
00785
00786 memset(enc_opt_data, 0, sizeof(*enc_opt_data));
00787 if (!evaluate_option_cache(enc_opt_data, packet,
00788 NULL, NULL, packet->options, NULL,
00789 &global_scope, oc, MDL)) {
00790 log_error("get_encapsulated_IA_state: "
00791 "error evaluating raw option.");
00792 return 0;
00793 }
00794 if (enc_opt_data->len < offset) {
00795 log_error("get_encapsulated_IA_state: raw option too small.");
00796 data_string_forget(enc_opt_data, MDL);
00797 return 0;
00798 }
00799
00800
00801
00802
00803
00804 *enc_opt_state = NULL;
00805 if (!option_state_allocate(enc_opt_state, MDL)) {
00806 log_error("get_encapsulated_IA_state: no memory for options.");
00807 data_string_forget(enc_opt_data, MDL);
00808 return 0;
00809 }
00810 if (!parse_option_buffer(*enc_opt_state,
00811 enc_opt_data->data + offset,
00812 enc_opt_data->len - offset,
00813 &dhcpv6_universe)) {
00814 log_error("get_encapsulated_IA_state: error parsing options.");
00815 option_state_dereference(enc_opt_state, MDL);
00816 data_string_forget(enc_opt_data, MDL);
00817 return 0;
00818 }
00819
00820 return 1;
00821 }
00822
00823 static int
00824 set_status_code(u_int16_t status_code, const char *status_message,
00825 struct option_state *opt_state)
00826 {
00827 struct data_string d;
00828 int ret_val;
00829
00830 memset(&d, 0, sizeof(d));
00831 d.len = sizeof(status_code) + strlen(status_message);
00832 if (!buffer_allocate(&d.buffer, d.len, MDL)) {
00833 log_fatal("set_status_code: no memory for status code.");
00834 }
00835 d.data = d.buffer->data;
00836 putUShort(d.buffer->data, status_code);
00837 memcpy(d.buffer->data + sizeof(status_code),
00838 status_message, d.len - sizeof(status_code));
00839 if (!save_option_buffer(&dhcpv6_universe, opt_state,
00840 d.buffer, (unsigned char *)d.data, d.len,
00841 D6O_STATUS_CODE, 0)) {
00842 log_error("set_status_code: error saving status code.");
00843 ret_val = 0;
00844 } else {
00845 ret_val = 1;
00846 }
00847 data_string_forget(&d, MDL);
00848 return ret_val;
00849 }
00850
00851
00852
00853
00854
00855 static int
00856 start_reply(struct packet *packet,
00857 const struct data_string *client_id,
00858 const struct data_string *server_id,
00859 struct option_state **opt_state,
00860 struct dhcpv6_packet *reply)
00861 {
00862 struct option_cache *oc;
00863 const unsigned char *server_id_data;
00864 int server_id_len;
00865
00866
00867
00868
00869 *opt_state = NULL;
00870 if (!option_state_allocate(opt_state, MDL)) {
00871 log_error("start_reply: no memory for option_state.");
00872 return 0;
00873 }
00874 execute_statements_in_scope(NULL, packet, NULL, NULL,
00875 packet->options, *opt_state,
00876 &global_scope, root_group, NULL, NULL);
00877
00878
00879
00880
00881
00882
00883
00884 if (packet->dhcpv6_msg_type == DHCPV6_SOLICIT) {
00885 reply->msg_type = DHCPV6_ADVERTISE;
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895 oc = lookup_option(&dhcpv6_universe,
00896 *opt_state, D6O_RAPID_COMMIT);
00897 if (oc != NULL) {
00898 oc = lookup_option(&dhcpv6_universe,
00899 packet->options, D6O_RAPID_COMMIT);
00900 if (oc != NULL) {
00901
00902 reply->msg_type = DHCPV6_REPLY;
00903 } else {
00904
00905 delete_option(&dhcpv6_universe,
00906 *opt_state, D6O_RAPID_COMMIT);
00907 }
00908 }
00909 } else {
00910 reply->msg_type = DHCPV6_REPLY;
00911
00912 oc = lookup_option(&dhcpv6_universe,
00913 *opt_state, D6O_RAPID_COMMIT);
00914 if (oc != NULL) {
00915 delete_option(&dhcpv6_universe,
00916 *opt_state, D6O_RAPID_COMMIT);
00917 }
00918 }
00919
00920
00921
00922
00923 memcpy(reply->transaction_id, packet->dhcpv6_transaction_id,
00924 sizeof(reply->transaction_id));
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937 oc = lookup_option(&dhcpv6_universe, *opt_state, D6O_SERVERID);
00938 if (oc == NULL) {
00939 if (server_id == NULL) {
00940 server_id_data = server_duid.data;
00941 server_id_len = server_duid.len;
00942 } else {
00943 server_id_data = server_id->data;
00944 server_id_len = server_id->len;
00945 }
00946 if (!save_option_buffer(&dhcpv6_universe, *opt_state,
00947 NULL, (unsigned char *)server_id_data,
00948 server_id_len, D6O_SERVERID, 0)) {
00949 log_error("start_reply: "
00950 "error saving server identifier.");
00951 return 0;
00952 }
00953 }
00954
00955 if (client_id->buffer != NULL) {
00956 if (!save_option_buffer(&dhcpv6_universe, *opt_state,
00957 client_id->buffer,
00958 (unsigned char *)client_id->data,
00959 client_id->len,
00960 D6O_CLIENTID, 0)) {
00961 log_error("start_reply: error saving "
00962 "client identifier.");
00963 return 0;
00964 }
00965 }
00966
00967
00968
00969
00970
00971
00972
00973
00974 oc = lookup_option(&dhcpv6_universe, packet->options,
00975 D6O_RECONF_ACCEPT);
00976 if (oc != NULL) {
00977 if (!save_option_buffer(&dhcpv6_universe, *opt_state,
00978 NULL, (unsigned char *)"", 0,
00979 D6O_RECONF_ACCEPT, 0)) {
00980 log_error("start_reply: "
00981 "error saving RECONF_ACCEPT option.");
00982 option_state_dereference(opt_state, MDL);
00983 return 0;
00984 }
00985 }
00986
00987 return 1;
00988 }
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998 static isc_result_t
00999 try_client_v6_address(struct iasubopt **addr,
01000 struct ipv6_pool *pool,
01001 const struct data_string *requested_addr)
01002 {
01003 struct in6_addr tmp_addr;
01004 isc_result_t result;
01005
01006 if (requested_addr->len < sizeof(tmp_addr)) {
01007 return DHCP_R_INVALIDARG;
01008 }
01009 memcpy(&tmp_addr, requested_addr->data, sizeof(tmp_addr));
01010 if (IN6_IS_ADDR_UNSPECIFIED(&tmp_addr)) {
01011 return ISC_R_FAILURE;
01012 }
01013
01014
01015
01016
01017
01018 if (!ipv6_in_pool(&tmp_addr, pool)) {
01019 return ISC_R_ADDRNOTAVAIL;
01020 }
01021
01022 if (lease6_exists(pool, &tmp_addr)) {
01023 return ISC_R_ADDRINUSE;
01024 }
01025
01026 result = iasubopt_allocate(addr, MDL);
01027 if (result != ISC_R_SUCCESS) {
01028 return result;
01029 }
01030 (*addr)->addr = tmp_addr;
01031 (*addr)->plen = 0;
01032
01033
01034 result = add_lease6(pool, *addr, cur_time + 120);
01035 if (result != ISC_R_SUCCESS) {
01036 iasubopt_dereference(addr, MDL);
01037 }
01038 return result;
01039 }
01040
01041
01063 static isc_result_t
01064 pick_v6_address(struct reply_state *reply)
01065 {
01066 struct ipv6_pool *p = NULL;
01067 struct ipv6_pond *pond;
01068 int i;
01069 int start_pool;
01070 unsigned int attempts;
01071 char tmp_buf[INET6_ADDRSTRLEN];
01072 struct iasubopt **addr = &reply->lease;
01073
01074
01075
01076
01077
01078 for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
01079 if (pond->ipv6_pools == NULL)
01080 continue;
01081
01082 for (i = 0; (p = pond->ipv6_pools[i]) != NULL; i++) {
01083 if (p->pool_type == D6O_IA_NA)
01084 break;
01085 }
01086 if (p != NULL)
01087 break;
01088 }
01089
01090
01091 if (p == NULL) {
01092 log_debug("Unable to pick client address: "
01093 "no IPv6 pools on this shared network");
01094 return ISC_R_NORESOURCES;
01095 }
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108 for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
01109 if (((pond->prohibit_list != NULL) &&
01110 (permitted(reply->packet, pond->prohibit_list))) ||
01111 ((pond->permit_list != NULL) &&
01112 (!permitted(reply->packet, pond->permit_list))))
01113 continue;
01114
01115 start_pool = pond->last_ipv6_pool;
01116 i = start_pool;
01117 do {
01118 p = pond->ipv6_pools[i];
01119 if ((p->pool_type == D6O_IA_NA) &&
01120 (create_lease6(p, addr, &attempts,
01121 &reply->ia->iaid_duid,
01122 cur_time + 120) == ISC_R_SUCCESS)) {
01123
01124
01125
01126
01127 if (attempts > 1) {
01128 i++;
01129 if (pond->ipv6_pools[i] == NULL) {
01130 i = 0;
01131 }
01132 }
01133 pond->last_ipv6_pool = i;
01134
01135 log_debug("Picking pool address %s",
01136 inet_ntop(AF_INET6, &((*addr)->addr),
01137 tmp_buf, sizeof(tmp_buf)));
01138 return (ISC_R_SUCCESS);
01139 }
01140
01141 i++;
01142 if (pond->ipv6_pools[i] == NULL) {
01143 i = 0;
01144 }
01145 } while (i != start_pool);
01146 }
01147
01148
01149
01150
01151
01152 log_debug("Unable to pick client address: no addresses available");
01153 return ISC_R_NORESOURCES;
01154 }
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164 static isc_result_t
01165 try_client_v6_prefix(struct iasubopt **pref,
01166 struct ipv6_pool *pool,
01167 const struct data_string *requested_pref)
01168 {
01169 u_int8_t tmp_plen;
01170 struct in6_addr tmp_pref;
01171 struct iaddr ia;
01172 isc_result_t result;
01173
01174 if (requested_pref->len < sizeof(tmp_plen) + sizeof(tmp_pref)) {
01175 return DHCP_R_INVALIDARG;
01176 }
01177 tmp_plen = (int) requested_pref->data[0];
01178 if ((tmp_plen < 3) || (tmp_plen > 128) ||
01179 ((int)tmp_plen != pool->units)) {
01180 return ISC_R_FAILURE;
01181 }
01182 memcpy(&tmp_pref, requested_pref->data + 1, sizeof(tmp_pref));
01183 if (IN6_IS_ADDR_UNSPECIFIED(&tmp_pref)) {
01184 return ISC_R_FAILURE;
01185 }
01186 ia.len = 16;
01187 memcpy(&ia.iabuf, &tmp_pref, 16);
01188 if (!is_cidr_mask_valid(&ia, (int) tmp_plen)) {
01189 return ISC_R_FAILURE;
01190 }
01191
01192 if (!ipv6_in_pool(&tmp_pref, pool)) {
01193 return ISC_R_ADDRNOTAVAIL;
01194 }
01195
01196 if (prefix6_exists(pool, &tmp_pref, tmp_plen)) {
01197 return ISC_R_ADDRINUSE;
01198 }
01199
01200 result = iasubopt_allocate(pref, MDL);
01201 if (result != ISC_R_SUCCESS) {
01202 return result;
01203 }
01204 (*pref)->addr = tmp_pref;
01205 (*pref)->plen = tmp_plen;
01206
01207
01208 result = add_lease6(pool, *pref, cur_time + 120);
01209 if (result != ISC_R_SUCCESS) {
01210 iasubopt_dereference(pref, MDL);
01211 }
01212 return result;
01213 }
01214
01237 static isc_result_t
01238 pick_v6_prefix(struct reply_state *reply)
01239 {
01240 struct ipv6_pool *p = NULL;
01241 struct ipv6_pond *pond;
01242 int i;
01243 unsigned int attempts;
01244 char tmp_buf[INET6_ADDRSTRLEN];
01245 struct iasubopt **pref = &reply->lease;
01246
01247
01248
01249
01250
01251 for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
01252 if (pond->ipv6_pools == NULL)
01253 continue;
01254
01255 for (i = 0; (p = pond->ipv6_pools[i]) != NULL; i++) {
01256 if (p->pool_type == D6O_IA_PD)
01257 break;
01258 }
01259 if (p != NULL)
01260 break;
01261 }
01262
01263
01264 if (p == NULL) {
01265 log_debug("Unable to pick client prefix: "
01266 "no IPv6 pools on this shared network");
01267 return ISC_R_NORESOURCES;
01268 }
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278 for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
01279 if (((pond->prohibit_list != NULL) &&
01280 (permitted(reply->packet, pond->prohibit_list))) ||
01281 ((pond->permit_list != NULL) &&
01282 (!permitted(reply->packet, pond->permit_list))))
01283 continue;
01284
01285 for (i = 0; (p = pond->ipv6_pools[i]) != NULL; i++) {
01286 if (p->pool_type != D6O_IA_PD) {
01287 continue;
01288 }
01289
01290
01291
01292
01293 if ((reply->preflen >= 0) && (p->units != reply->preflen)) {
01294 continue;
01295 }
01296
01297 if (create_prefix6(p, pref, &attempts, &reply->ia->iaid_duid,
01298 cur_time + 120) == ISC_R_SUCCESS) {
01299 log_debug("Picking pool prefix %s/%u",
01300 inet_ntop(AF_INET6, &((*pref)->addr),
01301 tmp_buf, sizeof(tmp_buf)),
01302 (unsigned) (*pref)->plen);
01303
01304 return (ISC_R_SUCCESS);
01305 }
01306 }
01307 }
01308
01309
01310
01311
01312
01313 log_debug("Unable to pick client prefix: no prefixes available");
01314 return ISC_R_NORESOURCES;
01315 }
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352 static void
01353 lease_to_client(struct data_string *reply_ret,
01354 struct packet *packet,
01355 const struct data_string *client_id,
01356 const struct data_string *server_id)
01357 {
01358 static struct reply_state reply;
01359 struct option_cache *oc;
01360 struct data_string packet_oro;
01361 #if defined (RFC3315_PRE_ERRATA_2010_08)
01362 isc_boolean_t no_resources_avail = ISC_FALSE;
01363 #endif
01364 int i;
01365
01366 memset(&packet_oro, 0, sizeof(packet_oro));
01367
01368
01369 if (shared_network_from_packet6(&reply.shared,
01370 packet) != ISC_R_SUCCESS)
01371 goto exit;
01372
01373
01374
01375
01376 packet_reference(&reply.packet, packet, MDL);
01377 data_string_copy(&reply.client_id, client_id, MDL);
01378
01379 if (!start_reply(packet, client_id, server_id, &reply.opt_state,
01380 &reply.buf.reply))
01381 goto exit;
01382
01383
01384 reply.cursor = REPLY_OPTIONS_INDEX;
01385
01386
01387
01388
01389 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_ORO);
01390 if (oc != NULL) {
01391 if (!evaluate_option_cache(&packet_oro, packet,
01392 NULL, NULL,
01393 packet->options, NULL,
01394 &global_scope, oc, MDL)) {
01395 log_error("lease_to_client: error evaluating ORO.");
01396 goto exit;
01397 }
01398 }
01399
01400
01401
01402
01403
01404 if (find_hosts_by_uid(&reply.host, client_id->data, client_id->len,
01405 MDL)) {
01406 packet->known = 1;
01407 seek_shared_host(&reply.host, reply.shared);
01408 }
01409
01410 if ((reply.host == NULL) &&
01411 find_hosts_by_option(&reply.host, packet, packet->options, MDL)) {
01412 packet->known = 1;
01413 seek_shared_host(&reply.host, reply.shared);
01414 }
01415
01416
01417
01418
01419
01420 if ((reply.host == NULL) &&
01421 find_hosts_by_duid_chaddr(&reply.host, client_id)) {
01422 packet->known = 1;
01423 seek_shared_host(&reply.host, reply.shared);
01424 }
01425
01426
01427 reply.ia_count = 0;
01428 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA);
01429
01430 for (; oc != NULL ; oc = oc->next) {
01431 isc_result_t status;
01432
01433
01434 reply.client_resources = 0;
01435 reply.resources_included = ISC_FALSE;
01436
01437 status = reply_process_ia_na(&reply, oc);
01438
01439
01440
01441
01442
01443 if ((status != ISC_R_SUCCESS) &&
01444 (status != ISC_R_NORESOURCES))
01445 goto exit;
01446
01447 #if defined (RFC3315_PRE_ERRATA_2010_08)
01448
01449
01450
01451
01452 if (reply.client_resources == 0)
01453 no_resources_avail = ISC_TRUE;
01454 #endif
01455 }
01456 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_TA);
01457 for (; oc != NULL ; oc = oc->next) {
01458 isc_result_t status;
01459
01460
01461 reply.client_resources = 0;
01462 reply.resources_included = ISC_FALSE;
01463
01464 status = reply_process_ia_ta(&reply, oc);
01465
01466
01467
01468
01469
01470 if ((status != ISC_R_SUCCESS) &&
01471 (status != ISC_R_NORESOURCES))
01472 goto exit;
01473
01474 #if defined (RFC3315_PRE_ERRATA_2010_08)
01475
01476
01477
01478
01479 if (reply.client_resources == 0)
01480 no_resources_avail = ISC_TRUE;
01481 #endif
01482 }
01483
01484
01485 reply.pd_count = 0;
01486 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_PD);
01487 for (; oc != NULL ; oc = oc->next) {
01488 isc_result_t status;
01489
01490
01491 reply.client_resources = 0;
01492 reply.resources_included = ISC_FALSE;
01493
01494 status = reply_process_ia_pd(&reply, oc);
01495
01496
01497
01498
01499
01500 if ((status != ISC_R_SUCCESS) &&
01501 (status != ISC_R_NORESOURCES))
01502 goto exit;
01503 }
01504
01505
01506
01507
01508
01509 if ((reply.ia_count == 0) && (reply.pd_count == 0)) {
01510 if (reply.packet->dhcpv6_msg_type !=
01511 DHCPV6_INFORMATION_REQUEST)
01512 goto exit;
01513
01514
01515
01516
01517
01518
01519 execute_statements_in_scope(NULL, reply.packet, NULL, NULL,
01520 reply.packet->options,
01521 reply.opt_state, &global_scope,
01522 reply.shared->group, root_group,
01523 NULL);
01524
01525
01526 for (i = reply.packet->class_count; i > 0; i--) {
01527 execute_statements_in_scope(NULL, reply.packet,
01528 NULL, NULL,
01529 reply.packet->options,
01530 reply.opt_state,
01531 &global_scope,
01532 reply.packet->classes[i - 1]->group,
01533 reply.shared->group, NULL);
01534 }
01535
01536
01537 if (reply.host != NULL)
01538 execute_statements_in_scope(NULL, reply.packet,
01539 NULL, NULL,
01540 reply.packet->options,
01541 reply.opt_state,
01542 &global_scope,
01543 reply.host->group,
01544 reply.shared->group, NULL);
01545 }
01546
01547
01548 if ((packet->unicast == ISC_TRUE) && !is_unicast_option_defined())
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568 {
01569
01570 if (!set_status_code(STATUS_UseMulticast,
01571 "Unicast not allowed by server.",
01572 reply.opt_state)) {
01573 log_error("lease_to_client: Unable to set "
01574 "UseMulticast status code.");
01575 goto exit;
01576 }
01577
01578
01579 reply.cursor = REPLY_OPTIONS_INDEX;
01580
01581
01582
01583
01584
01585
01586
01587
01588 reply.cursor += store_options6((char *)reply.buf.data +
01589 reply.cursor,
01590 sizeof(reply.buf) -
01591 reply.cursor,
01592 reply.opt_state, reply.packet,
01593 required_opts_NAA,
01594 NULL);
01595 }
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621 #if defined (RFC3315_PRE_ERRATA_2010_08)
01622 else if (no_resources_avail && (reply.ia_count != 0) &&
01623 (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
01624 {
01625
01626 if (!set_status_code(STATUS_NoAddrsAvail,
01627 "No addresses available for this "
01628 "interface.", reply.opt_state)) {
01629 log_error("lease_to_client: Unable to set "
01630 "NoAddrsAvail status code.");
01631 goto exit;
01632 }
01633
01634
01635 reply.cursor = REPLY_OPTIONS_INDEX;
01636
01637
01638
01639
01640
01641
01642
01643
01644 reply.buf.reply.msg_type = DHCPV6_ADVERTISE;
01645 reply.cursor += store_options6((char *)reply.buf.data +
01646 reply.cursor,
01647 sizeof(reply.buf) -
01648 reply.cursor,
01649 reply.opt_state, reply.packet,
01650 required_opts_NAA,
01651 NULL);
01652 } else {
01653
01654
01655
01656
01657 reply.cursor += store_options6((char *)reply.buf.data +
01658 reply.cursor,
01659 sizeof(reply.buf) -
01660 reply.cursor,
01661 reply.opt_state, reply.packet,
01662 required_opts_solicit,
01663 &packet_oro);
01664 }
01665 #else
01666
01667
01668
01669
01670 else
01671 reply.cursor += store_options6((char *)reply.buf.data + reply.cursor,
01672 sizeof(reply.buf) - reply.cursor,
01673 reply.opt_state, reply.packet,
01674 required_opts_solicit,
01675 &packet_oro);
01676 #endif
01677
01678
01679 reply_ret->len = reply.cursor;
01680 reply_ret->buffer = NULL;
01681 if (!buffer_allocate(&reply_ret->buffer, reply.cursor, MDL)) {
01682 log_fatal("No memory to store Reply.");
01683 }
01684 memcpy(reply_ret->buffer->data, reply.buf.data, reply.cursor);
01685 reply_ret->data = reply_ret->buffer->data;
01686
01687
01688 (void) commit_leases_timed();
01689
01690 exit:
01691
01692 if (reply.shared != NULL)
01693 shared_network_dereference(&reply.shared, MDL);
01694 if (reply.host != NULL)
01695 host_dereference(&reply.host, MDL);
01696 if (reply.opt_state != NULL)
01697 option_state_dereference(&reply.opt_state, MDL);
01698 if (reply.packet != NULL)
01699 packet_dereference(&reply.packet, MDL);
01700 if (reply.client_id.data != NULL)
01701 data_string_forget(&reply.client_id, MDL);
01702 if (packet_oro.buffer != NULL)
01703 data_string_forget(&packet_oro, MDL);
01704 reply.renew = reply.rebind = reply.prefer = reply.valid = 0;
01705 reply.cursor = 0;
01706 }
01707
01708
01709
01710
01711 static isc_result_t
01712 reply_process_ia_na(struct reply_state *reply, struct option_cache *ia) {
01713 isc_result_t status = ISC_R_SUCCESS;
01714 u_int32_t iaid;
01715 unsigned ia_cursor;
01716 struct option_state *packet_ia;
01717 struct option_cache *oc;
01718 struct data_string ia_data, data;
01719
01720
01721 packet_ia = NULL;
01722 memset(&ia_data, 0, sizeof(ia_data));
01723 memset(&data, 0, sizeof(data));
01724
01725
01726
01727
01728
01729 if ((reply->cursor + IA_NA_OFFSET + 4) > sizeof(reply->buf)) {
01730 log_error("reply_process_ia_na: Reply too long for IA.");
01731 return ISC_R_NOSPACE;
01732 }
01733
01734
01735
01736 if (!get_encapsulated_IA_state(&packet_ia, &ia_data, reply->packet,
01737 ia, IA_NA_OFFSET)) {
01738 log_error("reply_process_ia_na: error evaluating ia");
01739 status = ISC_R_FAILURE;
01740 goto cleanup;
01741 }
01742
01743
01744 iaid = getULong(ia_data.data);
01745 reply->renew = getULong(ia_data.data + 4);
01746 reply->rebind = getULong(ia_data.data + 8);
01747
01748
01749 if (ia_allocate(&reply->ia, iaid, (char *)reply->client_id.data,
01750 reply->client_id.len, MDL) != ISC_R_SUCCESS) {
01751 log_error("reply_process_ia_na: no memory for ia.");
01752 status = ISC_R_NOMEMORY;
01753 goto cleanup;
01754 }
01755 reply->ia->ia_type = D6O_IA_NA;
01756
01757
01758 ia_hash_lookup(&reply->old_ia, ia_na_active,
01759 (unsigned char *)reply->ia->iaid_duid.data,
01760 reply->ia->iaid_duid.len, MDL);
01761
01762
01763
01764
01765
01766 if (!option_state_allocate(&reply->reply_ia, MDL)) {
01767 status = ISC_R_NOMEMORY;
01768 goto cleanup;
01769 }
01770
01771
01772 if ((reply->host != NULL) && (reply->host->fixed_addr != NULL)) {
01773 struct iaddr tmp_addr;
01774
01775 if (!evaluate_option_cache(&reply->fixed, NULL, NULL, NULL,
01776 NULL, NULL, &global_scope,
01777 reply->host->fixed_addr, MDL)) {
01778 log_error("reply_process_ia_na: unable to evaluate "
01779 "fixed address.");
01780 status = ISC_R_FAILURE;
01781 goto cleanup;
01782 }
01783
01784 if (reply->fixed.len < 16) {
01785 log_error("reply_process_ia_na: invalid fixed address.");
01786 status = DHCP_R_INVALIDARG;
01787 goto cleanup;
01788 }
01789
01790
01791 tmp_addr.len = 16;
01792 memcpy(tmp_addr.iabuf, reply->fixed.data, 16);
01793
01794 if (find_grouped_subnet(&reply->subnet, reply->shared,
01795 tmp_addr, MDL) == 0)
01796 log_fatal("Impossible condition at %s:%d.", MDL);
01797
01798 reply->static_lease = ISC_TRUE;
01799 } else
01800 reply->static_lease = ISC_FALSE;
01801
01802
01803
01804
01805
01806
01807
01808 ia_cursor = reply->cursor;
01809
01810
01811 putUShort(reply->buf.data + reply->cursor, (unsigned)D6O_IA_NA);
01812 reply->cursor += 2;
01813
01814
01815 putUShort(reply->buf.data + reply->cursor, 0x0Cu);
01816 reply->cursor += 2;
01817
01818
01819 putULong(reply->buf.data + reply->cursor, iaid);
01820 reply->cursor += 4;
01821
01822
01823 putULong(reply->buf.data + reply->cursor, reply->renew);
01824 reply->cursor += 4;
01825
01826
01827 putULong(reply->buf.data + reply->cursor, reply->rebind);
01828 reply->cursor += 4;
01829
01830
01831
01832
01833
01834
01835
01836
01837
01838
01839 oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAADDR);
01840 reply->valid = reply->prefer = 0xffffffff;
01841 reply->client_valid = reply->client_prefer = 0;
01842 for (; oc != NULL ; oc = oc->next) {
01843 status = reply_process_addr(reply, oc);
01844
01845
01846
01847
01848
01849
01850
01851 if (status == ISC_R_CANCELED)
01852 break;
01853
01854 if ((status != ISC_R_SUCCESS) &&
01855 (status != ISC_R_ADDRINUSE) &&
01856 (status != ISC_R_ADDRNOTAVAIL))
01857 goto cleanup;
01858 }
01859
01860 reply->ia_count++;
01861
01862
01863
01864
01865
01866 if ((status != ISC_R_CANCELED) && (reply->client_resources == 0)) {
01867 status = find_client_address(reply);
01868
01869 if (status == ISC_R_NORESOURCES) {
01870 switch (reply->packet->dhcpv6_msg_type) {
01871 case DHCPV6_SOLICIT:
01872
01873
01874
01875
01876
01877
01878 case DHCPV6_REQUEST:
01879
01880
01881
01882
01883
01884
01885
01886
01887
01888 option_state_dereference(&reply->reply_ia, MDL);
01889 if (!option_state_allocate(&reply->reply_ia,
01890 MDL))
01891 {
01892 log_error("reply_process_ia_na: No "
01893 "memory for option state "
01894 "wipe.");
01895 status = ISC_R_NOMEMORY;
01896 goto cleanup;
01897 }
01898
01899 if (!set_status_code(STATUS_NoAddrsAvail,
01900 "No addresses available "
01901 "for this interface.",
01902 reply->reply_ia)) {
01903 log_error("reply_process_ia_na: Unable "
01904 "to set NoAddrsAvail status "
01905 "code.");
01906 status = ISC_R_FAILURE;
01907 goto cleanup;
01908 }
01909
01910 status = ISC_R_SUCCESS;
01911 break;
01912
01913 default:
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927
01928
01929
01930 if (reply->resources_included)
01931 status = ISC_R_SUCCESS;
01932 else
01933 goto cleanup;
01934 break;
01935 }
01936 }
01937
01938 if (status != ISC_R_SUCCESS)
01939 goto cleanup;
01940 }
01941
01942 reply->cursor += store_options6((char *)reply->buf.data + reply->cursor,
01943 sizeof(reply->buf) - reply->cursor,
01944 reply->reply_ia, reply->packet,
01945 required_opts_IA, NULL);
01946
01947
01948 putUShort(reply->buf.data + ia_cursor + 2,
01949 reply->cursor - (ia_cursor + 4));
01950
01951
01952
01953
01954
01955
01956
01957 reply->renew = 0;
01958 oc = lookup_option(&dhcp_universe, reply->opt_state,
01959 DHO_DHCP_RENEWAL_TIME);
01960 if (oc != NULL) {
01961 if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
01962 reply->packet->options,
01963 reply->opt_state, &global_scope,
01964 oc, MDL) ||
01965 (data.len != 4)) {
01966 log_error("Invalid renewal time.");
01967 } else {
01968 reply->renew = getULong(data.data);
01969 }
01970
01971 if (data.data != NULL)
01972 data_string_forget(&data, MDL);
01973 }
01974 putULong(reply->buf.data + ia_cursor + 8, reply->renew);
01975
01976
01977 reply->rebind = 0;
01978 oc = lookup_option(&dhcp_universe, reply->opt_state,
01979 DHO_DHCP_REBINDING_TIME);
01980 if (oc != NULL) {
01981 if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
01982 reply->packet->options,
01983 reply->opt_state, &global_scope,
01984 oc, MDL) ||
01985 (data.len != 4)) {
01986 log_error("Invalid rebinding time.");
01987 } else {
01988 reply->rebind = getULong(data.data);
01989 }
01990
01991 if (data.data != NULL)
01992 data_string_forget(&data, MDL);
01993 }
01994 putULong(reply->buf.data + ia_cursor + 12, reply->rebind);
01995
01996
01997
01998
01999
02000 if (status == ISC_R_CANCELED)
02001 goto cleanup;
02002
02003
02004
02005
02006
02007 if (reply->static_lease) {
02008 char tmp_addr[INET6_ADDRSTRLEN];
02009 log_info("%s NA: address %s to client with duid %s iaid = %d "
02010 "static",
02011 dhcpv6_type_names[reply->buf.reply.msg_type],
02012 inet_ntop(AF_INET6, reply->fixed.data, tmp_addr,
02013 sizeof(tmp_addr)),
02014 print_hex_1(reply->client_id.len,
02015 reply->client_id.data, 60),
02016 iaid);
02017
02018 if ((reply->buf.reply.msg_type == DHCPV6_REPLY) &&
02019 (reply->on_star.on_commit != NULL)) {
02020 execute_statements(NULL, reply->packet, NULL, NULL,
02021 reply->packet->options,
02022 reply->opt_state, NULL,
02023 reply->on_star.on_commit, NULL);
02024 executable_statement_dereference
02025 (&reply->on_star.on_commit, MDL);
02026 }
02027 goto cleanup;
02028 }
02029
02030
02031
02032
02033 if (reply->ia->num_iasubopt != 0) {
02034 struct iasubopt *tmp;
02035 int i;
02036 char tmp_addr[INET6_ADDRSTRLEN];
02037
02038 for (i = 0 ; i < reply->ia->num_iasubopt ; i++) {
02039 tmp = reply->ia->iasubopt[i];
02040
02041 log_info("%s NA: address %s to client with duid %s "
02042 "iaid = %d valid for %d seconds",
02043 dhcpv6_type_names[reply->buf.reply.msg_type],
02044 inet_ntop(AF_INET6, &tmp->addr,
02045 tmp_addr, sizeof(tmp_addr)),
02046 print_hex_1(reply->client_id.len,
02047 reply->client_id.data, 60),
02048 iaid, tmp->valid);
02049 }
02050 }
02051
02052
02053
02054
02055
02056
02057
02058
02059
02060
02061 if ((reply->ia->num_iasubopt != 0) &&
02062 (reply->buf.reply.msg_type == DHCPV6_REPLY)) {
02063 struct iasubopt *tmp;
02064 struct data_string *ia_id;
02065 int i;
02066
02067 for (i = 0 ; i < reply->ia->num_iasubopt ; i++) {
02068 tmp = reply->ia->iasubopt[i];
02069
02070 if (tmp->ia != NULL)
02071 ia_dereference(&tmp->ia, MDL);
02072 ia_reference(&tmp->ia, reply->ia, MDL);
02073
02074
02075 renew_lease6(tmp->ipv6_pool, tmp);
02076 schedule_lease_timeout(tmp->ipv6_pool);
02077
02078
02079 if (tmp->on_star.on_commit != NULL) {
02080 execute_statements(NULL, reply->packet,
02081 NULL, NULL,
02082 reply->packet->options,
02083 reply->opt_state,
02084 &tmp->scope,
02085 tmp->on_star.on_commit,
02086 &tmp->on_star);
02087 executable_statement_dereference
02088 (&tmp->on_star.on_commit, MDL);
02089 }
02090
02091 #if defined (NSUPDATE)
02092
02093
02094
02095 oc = lookup_option(&server_universe, reply->opt_state,
02096 SV_DDNS_UPDATES);
02097 if ((oc == NULL) ||
02098 evaluate_boolean_option_cache(NULL, reply->packet,
02099 NULL, NULL,
02100 reply->packet->options,
02101 reply->opt_state,
02102 &tmp->scope,
02103 oc, MDL)) {
02104 ddns_updates(reply->packet, NULL, NULL,
02105 tmp, NULL, reply->opt_state);
02106 }
02107 #endif
02108 }
02109
02110
02111 if (reply->old_ia != NULL) {
02112 ia_id = &reply->old_ia->iaid_duid;
02113 ia_hash_delete(ia_na_active,
02114 (unsigned char *)ia_id->data,
02115 ia_id->len, MDL);
02116 ia_dereference(&reply->old_ia, MDL);
02117 }
02118
02119
02120 reply->ia->cltt = cur_time;
02121 ia_id = &reply->ia->iaid_duid;
02122 ia_hash_add(ia_na_active, (unsigned char *)ia_id->data,
02123 ia_id->len, reply->ia, MDL);
02124
02125 write_ia(reply->ia);
02126 }
02127
02128 cleanup:
02129 if (packet_ia != NULL)
02130 option_state_dereference(&packet_ia, MDL);
02131 if (reply->reply_ia != NULL)
02132 option_state_dereference(&reply->reply_ia, MDL);
02133 if (ia_data.data != NULL)
02134 data_string_forget(&ia_data, MDL);
02135 if (data.data != NULL)
02136 data_string_forget(&data, MDL);
02137 if (reply->ia != NULL)
02138 ia_dereference(&reply->ia, MDL);
02139 if (reply->old_ia != NULL)
02140 ia_dereference(&reply->old_ia, MDL);
02141 if (reply->lease != NULL)
02142 iasubopt_dereference(&reply->lease, MDL);
02143 if (reply->fixed.data != NULL)
02144 data_string_forget(&reply->fixed, MDL);
02145 if (reply->subnet != NULL)
02146 subnet_dereference(&reply->subnet, MDL);
02147 if (reply->on_star.on_expiry != NULL)
02148 executable_statement_dereference
02149 (&reply->on_star.on_expiry, MDL);
02150 if (reply->on_star.on_release != NULL)
02151 executable_statement_dereference
02152 (&reply->on_star.on_release, MDL);
02153
02154
02155
02156
02157
02158
02159 return((status == ISC_R_CANCELED) ? ISC_R_SUCCESS : status);
02160 }
02161
02162
02163
02164
02165
02166
02167
02168 static isc_result_t
02169 reply_process_addr(struct reply_state *reply, struct option_cache *addr) {
02170 u_int32_t pref_life, valid_life;
02171 struct binding_scope **scope;
02172 struct group *group;
02173 struct subnet *subnet;
02174 struct iaddr tmp_addr;
02175 struct option_cache *oc;
02176 struct data_string iaaddr, data;
02177 isc_result_t status = ISC_R_SUCCESS;
02178
02179
02180 memset(&iaaddr, 0, sizeof(iaaddr));
02181 memset(&data, 0, sizeof(data));
02182
02183
02184
02185
02186
02187
02188 if ((reply->cursor + 28) > sizeof(reply->buf)) {
02189 log_error("reply_process_addr: Out of room for address.");
02190 return ISC_R_NOSPACE;
02191 }
02192
02193
02194 if (!evaluate_option_cache(&iaaddr, reply->packet, NULL, NULL,
02195 reply->packet->options, NULL, &global_scope,
02196 addr, MDL) ||
02197 (iaaddr.len < IAADDR_OFFSET)) {
02198 log_error("reply_process_addr: error evaluating IAADDR.");
02199 status = ISC_R_FAILURE;
02200 goto cleanup;
02201 }
02202
02203
02204 pref_life = getULong(iaaddr.data + 16);
02205 valid_life = getULong(iaaddr.data + 20);
02206
02207 if ((reply->client_valid == 0) ||
02208 (reply->client_valid > valid_life))
02209 reply->client_valid = valid_life;
02210
02211 if ((reply->client_prefer == 0) ||
02212 (reply->client_prefer > pref_life))
02213 reply->client_prefer = pref_life;
02214
02215
02216
02217
02218
02219 tmp_addr.len = 16;
02220 memset(tmp_addr.iabuf, 0, 16);
02221 if (!memcmp(iaaddr.data, tmp_addr.iabuf, 16)) {
02222
02223 goto cleanup;
02224 }
02225
02226
02227 memcpy(tmp_addr.iabuf, iaaddr.data, 16);
02228
02229
02230
02231
02232 for (subnet = reply->shared->subnets ; subnet != NULL ;
02233 subnet = subnet->next_sibling) {
02234 if (addr_eq(subnet_number(tmp_addr, subnet->netmask),
02235 subnet->net))
02236 break;
02237 }
02238
02239
02240 if (subnet == NULL) {
02241
02242 if (reply->packet->dhcpv6_msg_type == DHCPV6_SOLICIT) {
02243
02244 reply->buf.reply.msg_type = DHCPV6_ADVERTISE;
02245 delete_option(&dhcpv6_universe,
02246 reply->opt_state,
02247 D6O_RAPID_COMMIT);
02248
02249 goto cleanup;
02250 }
02251
02252
02253
02254
02255
02256
02257
02258
02259
02260
02261 if (reply->packet->dhcpv6_msg_type == DHCPV6_REQUEST) {
02262
02263 option_state_dereference(&reply->reply_ia, MDL);
02264 if (!option_state_allocate(&reply->reply_ia, MDL)) {
02265 log_error("reply_process_addr: No memory for "
02266 "option state wipe.");
02267 status = ISC_R_NOMEMORY;
02268 goto cleanup;
02269 }
02270
02271
02272 if (!set_status_code(STATUS_NotOnLink,
02273 "Address not for use on this "
02274 "link.", reply->reply_ia)) {
02275 log_error("reply_process_addr: Failure "
02276 "setting status code.");
02277 status = ISC_R_FAILURE;
02278 goto cleanup;
02279 }
02280
02281
02282 status = ISC_R_CANCELED;
02283 goto cleanup;
02284 }
02285
02286
02287
02288
02289
02290
02291
02292
02293
02294 if ((reply->packet->dhcpv6_msg_type != DHCPV6_RENEW) &&
02295 (reply->packet->dhcpv6_msg_type != DHCPV6_REBIND)) {
02296 log_error("It is impossible to lease a client that is "
02297 "not sending a solicit, request, renew, or "
02298 "rebind.");
02299 status = ISC_R_FAILURE;
02300 goto cleanup;
02301 }
02302
02303 reply->send_prefer = reply->send_valid = 0;
02304 goto send_addr;
02305 }
02306
02307
02308 if (!address_is_owned(reply, &tmp_addr)) {
02309
02310
02311
02312
02313
02314
02315
02316 if ((reply->packet->dhcpv6_msg_type == DHCPV6_SOLICIT) ||
02317 (reply->packet->dhcpv6_msg_type == DHCPV6_REQUEST) ||
02318 (reply->packet->dhcpv6_msg_type == DHCPV6_REBIND)) {
02319 status = reply_process_try_addr(reply, &tmp_addr);
02320
02321
02322
02323
02324
02325
02326 if ((status != ISC_R_SUCCESS) &&
02327 (status != ISC_R_ADDRINUSE) &&
02328 (status != ISC_R_ADDRNOTAVAIL))
02329 goto cleanup;
02330
02331
02332
02333
02334
02335
02336 if (reply->lease == NULL) {
02337 if (reply->packet->dhcpv6_msg_type ==
02338 DHCPV6_REBIND) {
02339 reply->send_prefer = 0;
02340 reply->send_valid = 0;
02341 goto send_addr;
02342 }
02343
02344
02345 goto cleanup;
02346 }
02347
02348
02349
02350
02351
02352
02353
02354
02355
02356
02357 } else if (reply->packet->dhcpv6_msg_type == DHCPV6_RENEW) {
02358
02359 option_state_dereference(&reply->reply_ia, MDL);
02360 if (!option_state_allocate(&reply->reply_ia, MDL)) {
02361 log_error("reply_process_addr: No memory for "
02362 "option state wipe.");
02363 status = ISC_R_NOMEMORY;
02364 goto cleanup;
02365 }
02366
02367
02368 if (!set_status_code(STATUS_NoBinding,
02369 "Address not bound to this "
02370 "interface.", reply->reply_ia)) {
02371 log_error("reply_process_addr: Unable to "
02372 "attach status code.");
02373 status = ISC_R_FAILURE;
02374 goto cleanup;
02375 }
02376
02377
02378 status = ISC_R_CANCELED;
02379 goto cleanup;
02380 } else {
02381 log_error("It is impossible to lease a client that is "
02382 "not sending a solicit, request, renew, or "
02383 "rebind message.");
02384 status = ISC_R_FAILURE;
02385 goto cleanup;
02386 }
02387 }
02388
02389 if (reply->static_lease) {
02390 if (reply->host == NULL)
02391 log_fatal("Impossible condition at %s:%d.", MDL);
02392
02393 scope = &global_scope;
02394 group = reply->subnet->group;
02395 } else {
02396 if (reply->lease == NULL)
02397 log_fatal("Impossible condition at %s:%d.", MDL);
02398
02399 scope = &reply->lease->scope;
02400 group = reply->lease->ipv6_pool->ipv6_pond->group;
02401 }
02402
02403
02404
02405
02406
02407
02408
02409 if (reply->client_resources != 0) {
02410 unsigned limit = 1;
02411
02412
02413
02414
02415
02416
02417 oc = lookup_option(&server_universe, reply->opt_state,
02418 SV_LIMIT_ADDRS_PER_IA);
02419 if (oc != NULL) {
02420 if (!evaluate_option_cache(&data, reply->packet,
02421 NULL, NULL,
02422 reply->packet->options,
02423 reply->opt_state,
02424 scope, oc, MDL) ||
02425 (data.len != 4)) {
02426 log_error("reply_process_addr: unable to "
02427 "evaluate addrs-per-ia value.");
02428 status = ISC_R_FAILURE;
02429 goto cleanup;
02430 }
02431
02432 limit = getULong(data.data);
02433 data_string_forget(&data, MDL);
02434 }
02435
02436
02437
02438
02439
02440 if (reply->client_resources >= limit)
02441 goto cleanup;
02442 }
02443
02444 status = reply_process_is_addressed(reply, scope, group);
02445 if (status != ISC_R_SUCCESS)
02446 goto cleanup;
02447
02448 send_addr:
02449 status = reply_process_send_addr(reply, &tmp_addr);
02450
02451 cleanup:
02452 if (iaaddr.data != NULL)
02453 data_string_forget(&iaaddr, MDL);
02454 if (data.data != NULL)
02455 data_string_forget(&data, MDL);
02456 if (reply->lease != NULL)
02457 iasubopt_dereference(&reply->lease, MDL);
02458
02459 return status;
02460 }
02461
02462
02463
02464
02465
02466
02467
02468 static isc_boolean_t
02469 address_is_owned(struct reply_state *reply, struct iaddr *addr) {
02470 int i;
02471 struct ipv6_pond *pond;
02472
02473
02474
02475
02476 if (reply->static_lease) {
02477 if (reply->fixed.data == NULL)
02478 log_fatal("Impossible condition at %s:%d.", MDL);
02479
02480 if (memcmp(addr->iabuf, reply->fixed.data, 16) == 0)
02481 return (ISC_TRUE);
02482
02483 return (ISC_FALSE);
02484 }
02485
02486 if ((reply->old_ia == NULL) || (reply->old_ia->num_iasubopt == 0))
02487 return (ISC_FALSE);
02488
02489 for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
02490 struct iasubopt *tmp;
02491
02492 tmp = reply->old_ia->iasubopt[i];
02493
02494 if (memcmp(addr->iabuf, &tmp->addr, 16) == 0) {
02495 if (lease6_usable(tmp) == ISC_FALSE) {
02496 return (ISC_FALSE);
02497 }
02498
02499 pond = tmp->ipv6_pool->ipv6_pond;
02500 if (((pond->prohibit_list != NULL) &&
02501 (permitted(reply->packet, pond->prohibit_list))) ||
02502 ((pond->permit_list != NULL) &&
02503 (!permitted(reply->packet, pond->permit_list))))
02504 return (ISC_FALSE);
02505
02506 iasubopt_reference(&reply->lease, tmp, MDL);
02507
02508 return (ISC_TRUE);
02509 }
02510 }
02511
02512 return (ISC_FALSE);
02513 }
02514
02515
02516
02517
02518 static isc_result_t
02519 reply_process_ia_ta(struct reply_state *reply, struct option_cache *ia) {
02520 isc_result_t status = ISC_R_SUCCESS;
02521 u_int32_t iaid;
02522 unsigned ia_cursor;
02523 struct option_state *packet_ia;
02524 struct option_cache *oc;
02525 struct data_string ia_data, data;
02526 struct data_string iaaddr;
02527 u_int32_t pref_life, valid_life;
02528 struct iaddr tmp_addr;
02529
02530
02531 packet_ia = NULL;
02532 memset(&ia_data, 0, sizeof(ia_data));
02533 memset(&data, 0, sizeof(data));
02534 memset(&iaaddr, 0, sizeof(iaaddr));
02535
02536
02537 if ((reply->cursor + IA_TA_OFFSET + 4) > sizeof(reply->buf)) {
02538 log_error("reply_process_ia_ta: Reply too long for IA.");
02539 return ISC_R_NOSPACE;
02540 }
02541
02542
02543
02544 if (!get_encapsulated_IA_state(&packet_ia, &ia_data, reply->packet,
02545 ia, IA_TA_OFFSET)) {
02546 log_error("reply_process_ia_ta: error evaluating ia");
02547 status = ISC_R_FAILURE;
02548 goto cleanup;
02549 }
02550
02551
02552 iaid = getULong(ia_data.data);
02553
02554
02555 if (ia_allocate(&reply->ia, iaid, (char *)reply->client_id.data,
02556 reply->client_id.len, MDL) != ISC_R_SUCCESS) {
02557 log_error("reply_process_ia_ta: no memory for ia.");
02558 status = ISC_R_NOMEMORY;
02559 goto cleanup;
02560 }
02561 reply->ia->ia_type = D6O_IA_TA;
02562
02563
02564 ia_hash_lookup(&reply->old_ia, ia_ta_active,
02565 (unsigned char *)reply->ia->iaid_duid.data,
02566 reply->ia->iaid_duid.len, MDL);
02567
02568
02569
02570
02571
02572 if (!option_state_allocate(&reply->reply_ia, MDL)) {
02573 status = ISC_R_NOMEMORY;
02574 goto cleanup;
02575 }
02576
02577
02578
02579
02580 reply->static_lease = ISC_FALSE;
02581
02582
02583
02584
02585
02586
02587
02588 ia_cursor = reply->cursor;
02589
02590
02591 putUShort(reply->buf.data + reply->cursor, (unsigned)D6O_IA_TA);
02592 reply->cursor += 2;
02593
02594
02595 putUShort(reply->buf.data + reply->cursor, 0x04u);
02596 reply->cursor += 2;
02597
02598
02599 putULong(reply->buf.data + reply->cursor, iaid);
02600 reply->cursor += 4;
02601
02602
02603
02604
02605
02606 reply->valid = reply->prefer = 0xffffffff;
02607 reply->client_valid = reply->client_prefer = 0;
02608 oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAADDR);
02609 for (; oc != NULL; oc = oc->next) {
02610 memset(&iaaddr, 0, sizeof(iaaddr));
02611 if (!evaluate_option_cache(&iaaddr, reply->packet,
02612 NULL, NULL,
02613 reply->packet->options, NULL,
02614 &global_scope, oc, MDL) ||
02615 (iaaddr.len < IAADDR_OFFSET)) {
02616 log_error("reply_process_ia_ta: error "
02617 "evaluating IAADDR.");
02618 status = ISC_R_FAILURE;
02619 goto cleanup;
02620 }
02621
02622 pref_life = getULong(iaaddr.data + 16);
02623 valid_life = getULong(iaaddr.data + 20);
02624
02625 if ((reply->client_valid == 0) ||
02626 (reply->client_valid > valid_life))
02627 reply->client_valid = valid_life;
02628
02629 if ((reply->client_prefer == 0) ||
02630 (reply->client_prefer > pref_life))
02631 reply->client_prefer = pref_life;
02632
02633
02634 if (status == ISC_R_CANCELED)
02635 continue;
02636
02637 tmp_addr.len = 16;
02638 memcpy(tmp_addr.iabuf, iaaddr.data, 16);
02639 if (!temporary_is_available(reply, &tmp_addr))
02640 goto bad_temp;
02641 status = reply_process_is_addressed(reply,
02642 &reply->lease->scope,
02643 reply->lease->ipv6_pool->ipv6_pond->group);
02644 if (status != ISC_R_SUCCESS)
02645 goto bad_temp;
02646 status = reply_process_send_addr(reply, &tmp_addr);
02647 if (status != ISC_R_SUCCESS)
02648 goto bad_temp;
02649 if (reply->lease != NULL)
02650 iasubopt_dereference(&reply->lease, MDL);
02651 continue;
02652
02653 bad_temp:
02654
02655 option_state_dereference(&reply->reply_ia, MDL);
02656 if (!option_state_allocate(&reply->reply_ia, MDL)) {
02657 status = ISC_R_NOMEMORY;
02658 goto cleanup;
02659 }
02660 status = ISC_R_CANCELED;
02661 reply->client_resources = 0;
02662 reply->resources_included = ISC_FALSE;
02663 if (reply->lease != NULL)
02664 iasubopt_dereference(&reply->lease, MDL);
02665 }
02666 reply->ia_count++;
02667
02668
02669
02670
02671 if (reply->client_resources != 0)
02672 goto store;
02673 status = find_client_temporaries(reply);
02674 if (status == ISC_R_NORESOURCES) {
02675 switch (reply->packet->dhcpv6_msg_type) {
02676 case DHCPV6_SOLICIT:
02677
02678
02679
02680
02681
02682
02683 case DHCPV6_REQUEST:
02684
02685
02686
02687
02688
02689
02690
02691
02692
02693 option_state_dereference(&reply->reply_ia, MDL);
02694 if (!option_state_allocate(&reply->reply_ia, MDL)) {
02695 log_error("reply_process_ia_ta: No "
02696 "memory for option state wipe.");
02697 status = ISC_R_NOMEMORY;
02698 goto cleanup;
02699 }
02700
02701 if (!set_status_code(STATUS_NoAddrsAvail,
02702 "No addresses available "
02703 "for this interface.",
02704 reply->reply_ia)) {
02705 log_error("reply_process_ia_ta: Unable "
02706 "to set NoAddrsAvail status code.");
02707 status = ISC_R_FAILURE;
02708 goto cleanup;
02709 }
02710
02711 status = ISC_R_SUCCESS;
02712 break;
02713
02714 default:
02715
02716
02717
02718
02719
02720 if (reply->resources_included)
02721 status = ISC_R_SUCCESS;
02722 else
02723 goto cleanup;
02724 break;
02725 }
02726 } else if (status != ISC_R_SUCCESS)
02727 goto cleanup;
02728
02729 store:
02730 reply->cursor += store_options6((char *)reply->buf.data + reply->cursor,
02731 sizeof(reply->buf) - reply->cursor,
02732 reply->reply_ia, reply->packet,
02733 required_opts_IA, NULL);
02734
02735
02736 putUShort(reply->buf.data + ia_cursor + 2,
02737 reply->cursor - (ia_cursor + 4));
02738
02739
02740
02741
02742
02743 if (status == ISC_R_CANCELED)
02744 goto cleanup;
02745
02746
02747
02748
02749 if (reply->ia->num_iasubopt != 0) {
02750 struct iasubopt *tmp;
02751 int i;
02752 char tmp_addr[INET6_ADDRSTRLEN];
02753
02754 for (i = 0 ; i < reply->ia->num_iasubopt ; i++) {
02755 tmp = reply->ia->iasubopt[i];
02756
02757 log_info("%s TA: address %s to client with duid %s "
02758 "iaid = %d valid for %d seconds",
02759 dhcpv6_type_names[reply->buf.reply.msg_type],
02760 inet_ntop(AF_INET6, &tmp->addr,
02761 tmp_addr, sizeof(tmp_addr)),
02762 print_hex_1(reply->client_id.len,
02763 reply->client_id.data, 60),
02764 iaid,
02765 tmp->valid);
02766 }
02767 }
02768
02769
02770
02771
02772
02773
02774
02775
02776
02777 if ((reply->ia->num_iasubopt != 0) &&
02778 (reply->buf.reply.msg_type == DHCPV6_REPLY)) {
02779 struct iasubopt *tmp;
02780 struct data_string *ia_id;
02781 int i;
02782
02783 for (i = 0 ; i < reply->ia->num_iasubopt ; i++) {
02784 tmp = reply->ia->iasubopt[i];
02785
02786 if (tmp->ia != NULL)
02787 ia_dereference(&tmp->ia, MDL);
02788 ia_reference(&tmp->ia, reply->ia, MDL);
02789
02790
02791 renew_lease6(tmp->ipv6_pool, tmp);
02792 schedule_lease_timeout(tmp->ipv6_pool);
02793
02794
02795 if (tmp->on_star.on_commit != NULL) {
02796 execute_statements(NULL, reply->packet,
02797 NULL, NULL,
02798 reply->packet->options,
02799 reply->opt_state,
02800 &tmp->scope,
02801 tmp->on_star.on_commit,
02802 &tmp->on_star);
02803 executable_statement_dereference
02804 (&tmp->on_star.on_commit, MDL);
02805 }
02806
02807 #if defined (NSUPDATE)
02808
02809
02810
02811 oc = lookup_option(&server_universe, reply->opt_state,
02812 SV_DDNS_UPDATES);
02813 if ((oc == NULL) ||
02814 evaluate_boolean_option_cache(NULL, reply->packet,
02815 NULL, NULL,
02816 reply->packet->options,
02817 reply->opt_state,
02818 &tmp->scope,
02819 oc, MDL)) {
02820 ddns_updates(reply->packet, NULL, NULL,
02821 tmp, NULL, reply->opt_state);
02822 }
02823 #endif
02824 }
02825
02826
02827 if (reply->old_ia != NULL) {
02828 ia_id = &reply->old_ia->iaid_duid;
02829 ia_hash_delete(ia_ta_active,
02830 (unsigned char *)ia_id->data,
02831 ia_id->len, MDL);
02832 ia_dereference(&reply->old_ia, MDL);
02833 }
02834
02835
02836 reply->ia->cltt = cur_time;
02837 ia_id = &reply->ia->iaid_duid;
02838 ia_hash_add(ia_ta_active, (unsigned char *)ia_id->data,
02839 ia_id->len, reply->ia, MDL);
02840
02841 write_ia(reply->ia);
02842 }
02843
02844 cleanup:
02845 if (packet_ia != NULL)
02846 option_state_dereference(&packet_ia, MDL);
02847 if (iaaddr.data != NULL)
02848 data_string_forget(&iaaddr, MDL);
02849 if (reply->reply_ia != NULL)
02850 option_state_dereference(&reply->reply_ia, MDL);
02851 if (ia_data.data != NULL)
02852 data_string_forget(&ia_data, MDL);
02853 if (data.data != NULL)
02854 data_string_forget(&data, MDL);
02855 if (reply->ia != NULL)
02856 ia_dereference(&reply->ia, MDL);
02857 if (reply->old_ia != NULL)
02858 ia_dereference(&reply->old_ia, MDL);
02859 if (reply->lease != NULL)
02860 iasubopt_dereference(&reply->lease, MDL);
02861
02862
02863
02864
02865
02866
02867 return((status == ISC_R_CANCELED) ? ISC_R_SUCCESS : status);
02868 }
02869
02870
02871
02872
02873 static isc_boolean_t
02874 temporary_is_available(struct reply_state *reply, struct iaddr *addr) {
02875 struct in6_addr tmp_addr;
02876 struct subnet *subnet;
02877 struct ipv6_pool *pool = NULL;
02878 struct ipv6_pond *pond = NULL;
02879 int i;
02880
02881 memcpy(&tmp_addr, addr->iabuf, sizeof(tmp_addr));
02882
02883
02884
02885
02886
02887 if (IN6_IS_ADDR_UNSPECIFIED(&tmp_addr))
02888 return ISC_FALSE;
02889
02890
02891
02892
02893 for (subnet = reply->shared->subnets ; subnet != NULL ;
02894 subnet = subnet->next_sibling) {
02895 if (addr_eq(subnet_number(*addr, subnet->netmask),
02896 subnet->net))
02897 break;
02898 }
02899
02900
02901 if (subnet == NULL)
02902 return ISC_FALSE;
02903
02904
02905
02906
02907 if (address_is_owned(reply, addr))
02908 return ISC_TRUE;
02909
02910
02911
02912
02913 for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
02914 if (((pond->prohibit_list != NULL) &&
02915 (permitted(reply->packet, pond->prohibit_list))) ||
02916 ((pond->permit_list != NULL) &&
02917 (!permitted(reply->packet, pond->permit_list))))
02918 continue;
02919
02920 for (i = 0 ; (pool = pond->ipv6_pools[i]) != NULL ; i++) {
02921 if (pool->pool_type != D6O_IA_TA)
02922 continue;
02923
02924 if (ipv6_in_pool(&tmp_addr, pool))
02925 break;
02926 }
02927
02928 if (pool != NULL)
02929 break;
02930 }
02931
02932 if (pool == NULL)
02933 return ISC_FALSE;
02934 if (lease6_exists(pool, &tmp_addr))
02935 return ISC_FALSE;
02936 if (iasubopt_allocate(&reply->lease, MDL) != ISC_R_SUCCESS)
02937 return ISC_FALSE;
02938 reply->lease->addr = tmp_addr;
02939 reply->lease->plen = 0;
02940
02941 if (add_lease6(pool, reply->lease, cur_time + 120) != ISC_R_SUCCESS)
02942 return ISC_FALSE;
02943
02944 return ISC_TRUE;
02945 }
02946
02947
02948
02949
02950 static isc_result_t
02951 find_client_temporaries(struct reply_state *reply) {
02952 int i;
02953 struct ipv6_pool *p = NULL;
02954 struct ipv6_pond *pond;
02955 isc_result_t status = ISC_R_NORESOURCES;;
02956 unsigned int attempts;
02957 struct iaddr send_addr;
02958
02959
02960
02961
02962
02963 for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
02964 if (pond->ipv6_pools == NULL)
02965 continue;
02966
02967 for (i = 0; (p = pond->ipv6_pools[i]) != NULL; i++) {
02968 if (p->pool_type == D6O_IA_TA)
02969 break;
02970 }
02971 if (p != NULL)
02972 break;
02973 }
02974
02975
02976 if (p == NULL) {
02977 log_debug("Unable to get client addresses: "
02978 "no IPv6 pools on this shared network");
02979 return ISC_R_NORESOURCES;
02980 }
02981
02982
02983
02984
02985
02986
02987
02988
02989 for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
02990 if (((pond->prohibit_list != NULL) &&
02991 (permitted(reply->packet, pond->prohibit_list))) ||
02992 ((pond->permit_list != NULL) &&
02993 (!permitted(reply->packet, pond->permit_list))))
02994 continue;
02995
02996 for (i = 0; (p = pond->ipv6_pools[i]) != NULL; i++) {
02997 if (p->pool_type != D6O_IA_TA) {
02998 continue;
02999 }
03000
03001
03002
03003
03004 status = create_lease6(p, &reply->lease, &attempts,
03005 &reply->client_id, cur_time + 120);
03006 if (status != ISC_R_SUCCESS) {
03007 log_debug("Unable to get a temporary address.");
03008 goto cleanup;
03009 }
03010
03011 status = reply_process_is_addressed(reply,
03012 &reply->lease->scope,
03013 pond->group);
03014 if (status != ISC_R_SUCCESS) {
03015 goto cleanup;
03016 }
03017 send_addr.len = 16;
03018 memcpy(send_addr.iabuf, &reply->lease->addr, 16);
03019 status = reply_process_send_addr(reply, &send_addr);
03020 if (status != ISC_R_SUCCESS) {
03021 goto cleanup;
03022 }
03023
03024
03025
03026
03027 iasubopt_dereference(&reply->lease, MDL);
03028 }
03029 }
03030
03031 cleanup:
03032 if (reply->lease != NULL) {
03033 iasubopt_dereference(&reply->lease, MDL);
03034 }
03035 return status;
03036 }
03037
03038
03039
03040
03041
03042 static isc_result_t
03043 reply_process_try_addr(struct reply_state *reply, struct iaddr *addr) {
03044 isc_result_t status = ISC_R_ADDRNOTAVAIL;
03045 struct ipv6_pool *pool = NULL;
03046 struct ipv6_pond *pond = NULL;
03047 int i;
03048 struct data_string data_addr;
03049
03050 if ((reply == NULL) || (reply->shared == NULL) ||
03051 (addr == NULL) || (reply->lease != NULL))
03052 return (DHCP_R_INVALIDARG);
03053
03054
03055
03056
03057
03058 for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
03059 if (pond->ipv6_pools == NULL)
03060 continue;
03061
03062 for (i = 0; ; i++) {
03063 pool = pond->ipv6_pools[i];
03064 if ((pool == NULL) ||
03065 (pool->pool_type == D6O_IA_NA))
03066 break;
03067 }
03068 if (pool != NULL)
03069 break;
03070 }
03071
03072
03073 if (pool == NULL) {
03074 return (ISC_R_ADDRNOTAVAIL);
03075 }
03076
03077 memset(&data_addr, 0, sizeof(data_addr));
03078 data_addr.len = addr->len;
03079 data_addr.data = addr->iabuf;
03080
03081
03082
03083
03084
03085
03086
03087
03088
03089
03090
03091
03092 for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
03093 if (((pond->prohibit_list != NULL) &&
03094 (permitted(reply->packet, pond->prohibit_list))) ||
03095 ((pond->permit_list != NULL) &&
03096 (!permitted(reply->packet, pond->permit_list))))
03097 continue;
03098
03099 for (i = 0 ; (pool = pond->ipv6_pools[i]) != NULL ; i++) {
03100 if (pool->pool_type != D6O_IA_NA)
03101 continue;
03102
03103 status = try_client_v6_address(&reply->lease, pool,
03104 &data_addr);
03105 if (status == ISC_R_SUCCESS)
03106 break;
03107 }
03108
03109 if (status == ISC_R_SUCCESS)
03110 break;
03111 }
03112
03113
03114 data_string_forget(&data_addr, MDL);
03115
03116 return (status);
03117 }
03118
03119
03120
03121
03122
03123 static isc_result_t
03124 find_client_address(struct reply_state *reply) {
03125 struct iaddr send_addr;
03126 isc_result_t status = ISC_R_NORESOURCES;
03127 struct iasubopt *lease, *best_lease = NULL;
03128 struct binding_scope **scope;
03129 struct group *group;
03130 int i;
03131
03132 if (reply->static_lease) {
03133 if (reply->host == NULL)
03134 return DHCP_R_INVALIDARG;
03135
03136 send_addr.len = 16;
03137 memcpy(send_addr.iabuf, reply->fixed.data, 16);
03138
03139 scope = &global_scope;
03140 group = reply->subnet->group;
03141 goto send_addr;
03142 }
03143
03144 if (reply->old_ia != NULL) {
03145 for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
03146 struct shared_network *candidate_shared;
03147 struct ipv6_pond *pond;
03148
03149 lease = reply->old_ia->iasubopt[i];
03150 candidate_shared = lease->ipv6_pool->shared_network;
03151 pond = lease->ipv6_pool->ipv6_pond;
03152
03153
03154
03155
03156
03157
03158 if ((candidate_shared != reply->shared) ||
03159 (lease6_usable(lease) != ISC_TRUE))
03160 continue;
03161
03162 if (((pond->prohibit_list != NULL) &&
03163 (permitted(reply->packet, pond->prohibit_list))) ||
03164 ((pond->permit_list != NULL) &&
03165 (!permitted(reply->packet, pond->permit_list))))
03166 continue;
03167
03168 best_lease = lease_compare(lease, best_lease);
03169 }
03170 }
03171
03172
03173
03174
03175 if ((best_lease == NULL) || (best_lease->state == FTS_ABANDONED)) {
03176 status = pick_v6_address(reply);
03177 } else if (best_lease != NULL) {
03178 iasubopt_reference(&reply->lease, best_lease, MDL);
03179 status = ISC_R_SUCCESS;
03180 }
03181
03182
03183 if ((status == ISC_R_NORESOURCES) && (best_lease != NULL)) {
03184
03185 log_error("Reclaiming abandoned addresses is not yet "
03186 "supported. Treating this as an out of space "
03187 "condition.");
03188
03189 }
03190
03191
03192 if (status != ISC_R_SUCCESS)
03193 return status;
03194
03195 if (reply->lease == NULL)
03196 log_fatal("Impossible condition at %s:%d.", MDL);
03197
03198
03199
03200
03201
03202 scope = &reply->lease->scope;
03203 group = reply->lease->ipv6_pool->ipv6_pond->group;
03204
03205 send_addr.len = 16;
03206 memcpy(send_addr.iabuf, &reply->lease->addr, 16);
03207
03208 send_addr:
03209 status = reply_process_is_addressed(reply, scope, group);
03210 if (status != ISC_R_SUCCESS)
03211 return status;
03212
03213 status = reply_process_send_addr(reply, &send_addr);
03214 return status;
03215 }
03216
03217
03218
03219
03220
03221 static isc_result_t
03222 reply_process_is_addressed(struct reply_state *reply,
03223 struct binding_scope **scope, struct group *group)
03224 {
03225 isc_result_t status = ISC_R_SUCCESS;
03226 struct data_string data;
03227 struct option_cache *oc;
03228 struct option_state *tmp_options = NULL;
03229 struct on_star *on_star;
03230 int i;
03231
03232
03233 memset(&data, 0, sizeof(data));
03234
03235
03236
03237
03238
03239
03240
03241 if (reply->lease) {
03242 on_star = &reply->lease->on_star;
03243 } else {
03244 on_star = &reply->on_star;
03245 }
03246
03247
03248
03249
03250
03251
03252 option_state_allocate(&tmp_options, MDL);
03253 execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
03254 reply->packet->options, tmp_options,
03255 &global_scope, root_group, NULL,
03256 on_star);
03257 if (tmp_options != NULL) {
03258 option_state_dereference(&tmp_options, MDL);
03259 }
03260
03261
03262
03263
03264
03265
03266 execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
03267 reply->packet->options, reply->opt_state,
03268 scope, group, root_group, on_star);
03269
03270
03271 for (i = reply->packet->class_count; i > 0; i--) {
03272 execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
03273 reply->packet->options,
03274 reply->opt_state, scope,
03275 reply->packet->classes[i - 1]->group,
03276 group, on_star);
03277 }
03278
03279
03280
03281
03282
03283
03284 if (reply->host != NULL)
03285 execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
03286 reply->packet->options,
03287 reply->opt_state, scope,
03288 reply->host->group, group,
03289 on_star);
03290
03291
03292 if (reply->client_valid == 0)
03293 reply->send_valid = DEFAULT_DEFAULT_LEASE_TIME;
03294 else
03295 reply->send_valid = reply->client_valid;
03296
03297 oc = lookup_option(&server_universe, reply->opt_state,
03298 SV_DEFAULT_LEASE_TIME);
03299 if (oc != NULL) {
03300 if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
03301 reply->packet->options,
03302 reply->opt_state,
03303 scope, oc, MDL) ||
03304 (data.len != 4)) {
03305 log_error("reply_process_is_addressed: unable to "
03306 "evaluate default lease time");
03307 status = ISC_R_FAILURE;
03308 goto cleanup;
03309 }
03310
03311 reply->send_valid = getULong(data.data);
03312 data_string_forget(&data, MDL);
03313 }
03314
03315 if (reply->client_prefer == 0)
03316 reply->send_prefer = reply->send_valid;
03317 else
03318 reply->send_prefer = reply->client_prefer;
03319
03320 if (reply->send_prefer >= reply->send_valid)
03321 reply->send_prefer = (reply->send_valid / 2) +
03322 (reply->send_valid / 8);
03323
03324 oc = lookup_option(&server_universe, reply->opt_state,
03325 SV_PREFER_LIFETIME);
03326 if (oc != NULL) {
03327 if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
03328 reply->packet->options,
03329 reply->opt_state,
03330 scope, oc, MDL) ||
03331 (data.len != 4)) {
03332 log_error("reply_process_is_addressed: unable to "
03333 "evaluate preferred lease time");
03334 status = ISC_R_FAILURE;
03335 goto cleanup;
03336 }
03337
03338 reply->send_prefer = getULong(data.data);
03339 data_string_forget(&data, MDL);
03340 }
03341
03342
03343 if (reply->prefer > reply->send_prefer)
03344 reply->prefer = reply->send_prefer;
03345
03346 if (reply->valid > reply->send_valid)
03347 reply->valid = reply->send_valid;
03348
03349 #if 0
03350
03351
03352
03353
03354
03355
03356
03357
03358
03359 if (reply->host != NULL)
03360 change_host_uid(host, reply->client_id->data,
03361 reply->client_id->len);
03362 #endif
03363
03364
03365 if (reply->lease != NULL) {
03366
03367 reply->lease->prefer = reply->send_prefer;
03368 reply->lease->valid = reply->send_valid;
03369
03370
03371 if (reply->buf.reply.msg_type == DHCPV6_REPLY) {
03372 reply->lease->soft_lifetime_end_time =
03373 cur_time + reply->send_valid;
03374
03375 }
03376
03377 status = ia_add_iasubopt(reply->ia, reply->lease, MDL);
03378 if (status != ISC_R_SUCCESS) {
03379 log_fatal("reply_process_is_addressed: Unable to "
03380 "attach lease to new IA: %s",
03381 isc_result_totext(status));
03382 }
03383
03384
03385
03386
03387 if (reply->lease->ia == NULL) {
03388 ia_reference(&reply->lease->ia, reply->ia, MDL);
03389 }
03390 }
03391
03392
03393 execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
03394 reply->packet->options, reply->reply_ia,
03395 scope, group, root_group, NULL);
03396
03397
03398 for (i = reply->packet->class_count; i > 0; i--) {
03399 execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
03400 reply->packet->options,
03401 reply->reply_ia, scope,
03402 reply->packet->classes[i - 1]->group,
03403 group, NULL);
03404 }
03405
03406
03407
03408
03409
03410 if (reply->host != NULL)
03411 execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
03412 reply->packet->options,
03413 reply->reply_ia, scope,
03414 reply->host->group, group, NULL);
03415
03416 cleanup:
03417 if (data.data != NULL)
03418 data_string_forget(&data, MDL);
03419
03420 if (status == ISC_R_SUCCESS)
03421 reply->client_resources++;
03422
03423 return status;
03424 }
03425
03426
03427 static isc_result_t
03428 reply_process_send_addr(struct reply_state *reply, struct iaddr *addr) {
03429 isc_result_t status = ISC_R_SUCCESS;
03430 struct data_string data;
03431
03432 memset(&data, 0, sizeof(data));
03433
03434
03435 data.len = IAADDR_OFFSET;
03436 if (!buffer_allocate(&data.buffer, data.len, MDL)) {
03437 log_error("reply_process_send_addr: out of memory"
03438 "allocating new IAADDR buffer.");
03439 status = ISC_R_NOMEMORY;
03440 goto cleanup;
03441 }
03442 data.data = data.buffer->data;
03443
03444 memcpy(data.buffer->data, addr->iabuf, 16);
03445 putULong(data.buffer->data + 16, reply->send_prefer);
03446 putULong(data.buffer->data + 20, reply->send_valid);
03447
03448 if (!append_option_buffer(&dhcpv6_universe, reply->reply_ia,
03449 data.buffer, data.buffer->data,
03450 data.len, D6O_IAADDR, 0)) {
03451 log_error("reply_process_send_addr: unable "
03452 "to save IAADDR option");
03453 status = ISC_R_FAILURE;
03454 goto cleanup;
03455 }
03456
03457 reply->resources_included = ISC_TRUE;
03458
03459 cleanup:
03460 if (data.data != NULL)
03461 data_string_forget(&data, MDL);
03462
03463 return status;
03464 }
03465
03466
03467 static struct iasubopt *
03468 lease_compare(struct iasubopt *alpha, struct iasubopt *beta) {
03469 if (alpha == NULL)
03470 return beta;
03471 if (beta == NULL)
03472 return alpha;
03473
03474 switch(alpha->state) {
03475 case FTS_ACTIVE:
03476 switch(beta->state) {
03477 case FTS_ACTIVE:
03478
03479
03480
03481 if (alpha->hard_lifetime_end_time <
03482 beta->hard_lifetime_end_time)
03483 return beta;
03484 else
03485 return alpha;
03486
03487 case FTS_EXPIRED:
03488 case FTS_ABANDONED:
03489 return alpha;
03490
03491 default:
03492 log_fatal("Impossible condition at %s:%d.", MDL);
03493 }
03494 break;
03495
03496 case FTS_EXPIRED:
03497 switch (beta->state) {
03498 case FTS_ACTIVE:
03499 return beta;
03500
03501 case FTS_EXPIRED:
03502
03503 if (alpha->hard_lifetime_end_time <
03504 beta->hard_lifetime_end_time)
03505 return beta;
03506 else if ((alpha->hard_lifetime_end_time ==
03507 beta->hard_lifetime_end_time) &&
03508 (alpha->soft_lifetime_end_time <
03509 beta->soft_lifetime_end_time))
03510 return beta;
03511 else
03512 return alpha;
03513
03514 case FTS_ABANDONED:
03515 return alpha;
03516
03517 default:
03518 log_fatal("Impossible condition at %s:%d.", MDL);
03519 }
03520 break;
03521
03522 case FTS_ABANDONED:
03523 switch (beta->state) {
03524 case FTS_ACTIVE:
03525 case FTS_EXPIRED:
03526 return alpha;
03527
03528 case FTS_ABANDONED:
03529
03530 if (alpha->hard_lifetime_end_time <
03531 beta->hard_lifetime_end_time)
03532 return alpha;
03533
03534 default:
03535 log_fatal("Impossible condition at %s:%d.", MDL);
03536 }
03537 break;
03538
03539 default:
03540 log_fatal("Impossible condition at %s:%d.", MDL);
03541 }
03542
03543 log_fatal("Triple impossible condition at %s:%d.", MDL);
03544 return NULL;
03545 }
03546
03547
03548
03549
03550 static isc_result_t
03551 reply_process_ia_pd(struct reply_state *reply, struct option_cache *ia) {
03552 isc_result_t status = ISC_R_SUCCESS;
03553 u_int32_t iaid;
03554 unsigned ia_cursor;
03555 struct option_state *packet_ia;
03556 struct option_cache *oc;
03557 struct data_string ia_data, data;
03558
03559
03560 packet_ia = NULL;
03561 memset(&ia_data, 0, sizeof(ia_data));
03562 memset(&data, 0, sizeof(data));
03563
03564
03565
03566
03567
03568 if ((reply->cursor + IA_PD_OFFSET + 4) > sizeof(reply->buf)) {
03569 log_error("reply_process_ia_pd: Reply too long for IA.");
03570 return ISC_R_NOSPACE;
03571 }
03572
03573
03574
03575 if (!get_encapsulated_IA_state(&packet_ia, &ia_data, reply->packet,
03576 ia, IA_PD_OFFSET)) {
03577 log_error("reply_process_ia_pd: error evaluating ia");
03578 status = ISC_R_FAILURE;
03579 goto cleanup;
03580 }
03581
03582
03583 iaid = getULong(ia_data.data);
03584 reply->renew = getULong(ia_data.data + 4);
03585 reply->rebind = getULong(ia_data.data + 8);
03586
03587
03588 if (ia_allocate(&reply->ia, iaid, (char *)reply->client_id.data,
03589 reply->client_id.len, MDL) != ISC_R_SUCCESS) {
03590 log_error("reply_process_ia_pd: no memory for ia.");
03591 status = ISC_R_NOMEMORY;
03592 goto cleanup;
03593 }
03594 reply->ia->ia_type = D6O_IA_PD;
03595
03596
03597 ia_hash_lookup(&reply->old_ia, ia_pd_active,
03598 (unsigned char *)reply->ia->iaid_duid.data,
03599 reply->ia->iaid_duid.len, MDL);
03600
03601
03602
03603
03604
03605 if (!option_state_allocate(&reply->reply_ia, MDL)) {
03606 status = ISC_R_NOMEMORY;
03607 goto cleanup;
03608 }
03609
03610
03611 reply->static_prefixes = 0;
03612 if ((reply->host != NULL) && (reply->host->fixed_prefix != NULL)) {
03613 struct iaddrcidrnetlist *fp;
03614
03615 for (fp = reply->host->fixed_prefix; fp != NULL;
03616 fp = fp->next) {
03617 reply->static_prefixes += 1;
03618 }
03619 }
03620
03621
03622
03623
03624
03625
03626
03627 ia_cursor = reply->cursor;
03628
03629
03630 putUShort(reply->buf.data + reply->cursor, (unsigned)D6O_IA_PD);
03631 reply->cursor += 2;
03632
03633
03634 putUShort(reply->buf.data + reply->cursor, 0x0Cu);
03635 reply->cursor += 2;
03636
03637
03638 putULong(reply->buf.data + reply->cursor, iaid);
03639 reply->cursor += 4;
03640
03641
03642 putULong(reply->buf.data + reply->cursor, reply->renew);
03643 reply->cursor += 4;
03644
03645
03646 putULong(reply->buf.data + reply->cursor, reply->rebind);
03647 reply->cursor += 4;
03648
03649
03650
03651
03652 oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAPREFIX);
03653 reply->valid = reply->prefer = 0xffffffff;
03654 reply->client_valid = reply->client_prefer = 0;
03655 reply->preflen = -1;
03656 for (; oc != NULL ; oc = oc->next) {
03657 status = reply_process_prefix(reply, oc);
03658
03659
03660
03661
03662
03663
03664
03665 if (status == ISC_R_CANCELED)
03666 break;
03667
03668 if ((status != ISC_R_SUCCESS) &&
03669 (status != ISC_R_ADDRINUSE) &&
03670 (status != ISC_R_ADDRNOTAVAIL))
03671 goto cleanup;
03672 }
03673
03674 reply->pd_count++;
03675
03676
03677
03678
03679
03680 if ((status != ISC_R_CANCELED) && (reply->client_resources == 0)) {
03681 status = find_client_prefix(reply);
03682
03683 if (status == ISC_R_NORESOURCES) {
03684 switch (reply->packet->dhcpv6_msg_type) {
03685 case DHCPV6_SOLICIT:
03686
03687
03688
03689
03690
03691
03692 case DHCPV6_REQUEST:
03693
03694 option_state_dereference(&reply->reply_ia, MDL);
03695 if (!option_state_allocate(&reply->reply_ia,
03696 MDL))
03697 {
03698 log_error("reply_process_ia_pd: No "
03699 "memory for option state "
03700 "wipe.");
03701 status = ISC_R_NOMEMORY;
03702 goto cleanup;
03703 }
03704
03705 if (!set_status_code(STATUS_NoPrefixAvail,
03706 "No prefixes available "
03707 "for this interface.",
03708 reply->reply_ia)) {
03709 log_error("reply_process_ia_pd: "
03710 "Unable to set "
03711 "NoPrefixAvail status "
03712 "code.");
03713 status = ISC_R_FAILURE;
03714 goto cleanup;
03715 }
03716
03717 status = ISC_R_SUCCESS;
03718 break;
03719
03720 default:
03721 if (reply->resources_included)
03722 status = ISC_R_SUCCESS;
03723 else
03724 goto cleanup;
03725 break;
03726 }
03727 }
03728
03729 if (status != ISC_R_SUCCESS)
03730 goto cleanup;
03731 }
03732
03733 reply->cursor += store_options6((char *)reply->buf.data + reply->cursor,
03734 sizeof(reply->buf) - reply->cursor,
03735 reply->reply_ia, reply->packet,
03736 required_opts_IA_PD, NULL);
03737
03738
03739 putUShort(reply->buf.data + ia_cursor + 2,
03740 reply->cursor - (ia_cursor + 4));
03741
03742
03743
03744
03745
03746
03747
03748 reply->renew = 0;
03749 oc = lookup_option(&dhcp_universe, reply->opt_state,
03750 DHO_DHCP_RENEWAL_TIME);
03751 if (oc != NULL) {
03752 if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
03753 reply->packet->options,
03754 reply->opt_state, &global_scope,
03755 oc, MDL) ||
03756 (data.len != 4)) {
03757 log_error("Invalid renewal time.");
03758 } else {
03759 reply->renew = getULong(data.data);
03760 }
03761
03762 if (data.data != NULL)
03763 data_string_forget(&data, MDL);
03764 }
03765 putULong(reply->buf.data + ia_cursor + 8, reply->renew);
03766
03767
03768 reply->rebind = 0;
03769 oc = lookup_option(&dhcp_universe, reply->opt_state,
03770 DHO_DHCP_REBINDING_TIME);
03771 if (oc != NULL) {
03772 if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
03773 reply->packet->options,
03774 reply->opt_state, &global_scope,
03775 oc, MDL) ||
03776 (data.len != 4)) {
03777 log_error("Invalid rebinding time.");
03778 } else {
03779 reply->rebind = getULong(data.data);
03780 }
03781
03782 if (data.data != NULL)
03783 data_string_forget(&data, MDL);
03784 }
03785 putULong(reply->buf.data + ia_cursor + 12, reply->rebind);
03786
03787
03788
03789
03790
03791 if (status == ISC_R_CANCELED)
03792 goto cleanup;
03793
03794
03795
03796
03797
03798 if (reply->static_prefixes != 0) {
03799 char tmp_addr[INET6_ADDRSTRLEN];
03800 log_info("%s PD: address %s/%d to client with duid %s "
03801 "iaid = %d static",
03802 dhcpv6_type_names[reply->buf.reply.msg_type],
03803 inet_ntop(AF_INET6, reply->fixed_pref.lo_addr.iabuf,
03804 tmp_addr, sizeof(tmp_addr)),
03805 reply->fixed_pref.bits,
03806 print_hex_1(reply->client_id.len,
03807 reply->client_id.data, 60),
03808 iaid);
03809 if ((reply->buf.reply.msg_type == DHCPV6_REPLY) &&
03810 (reply->on_star.on_commit != NULL)) {
03811 execute_statements(NULL, reply->packet, NULL, NULL,
03812 reply->packet->options,
03813 reply->opt_state,
03814 NULL, reply->on_star.on_commit,
03815 NULL);
03816 executable_statement_dereference
03817 (&reply->on_star.on_commit, MDL);
03818 }
03819 goto cleanup;
03820 }
03821
03822
03823
03824
03825 if (reply->ia->num_iasubopt != 0) {
03826 struct iasubopt *tmp;
03827 int i;
03828 char tmp_addr[INET6_ADDRSTRLEN];
03829
03830 for (i = 0 ; i < reply->ia->num_iasubopt ; i++) {
03831 tmp = reply->ia->iasubopt[i];
03832
03833 log_info("%s PD: address %s/%d to client with duid %s"
03834 " iaid = %d valid for %d seconds",
03835 dhcpv6_type_names[reply->buf.reply.msg_type],
03836 inet_ntop(AF_INET6, &tmp->addr,
03837 tmp_addr, sizeof(tmp_addr)),
03838 (int)tmp->plen,
03839 print_hex_1(reply->client_id.len,
03840 reply->client_id.data, 60),
03841 iaid, tmp->valid);
03842 }
03843 }
03844
03845
03846
03847
03848
03849
03850
03851
03852
03853 if ((reply->buf.reply.msg_type == DHCPV6_REPLY) &&
03854 (reply->ia->num_iasubopt != 0)) {
03855 struct iasubopt *tmp;
03856 struct data_string *ia_id;
03857 int i;
03858
03859 for (i = 0 ; i < reply->ia->num_iasubopt ; i++) {
03860 tmp = reply->ia->iasubopt[i];
03861
03862 if (tmp->ia != NULL)
03863 ia_dereference(&tmp->ia, MDL);
03864 ia_reference(&tmp->ia, reply->ia, MDL);
03865
03866
03867 renew_lease6(tmp->ipv6_pool, tmp);
03868 schedule_lease_timeout(tmp->ipv6_pool);
03869
03870
03871 if (tmp->on_star.on_commit != NULL) {
03872 execute_statements(NULL, reply->packet,
03873 NULL, NULL,
03874 reply->packet->options,
03875 reply->opt_state,
03876 &tmp->scope,
03877 tmp->on_star.on_commit,
03878 &tmp->on_star);
03879 executable_statement_dereference
03880 (&tmp->on_star.on_commit, MDL);
03881 }
03882 }
03883
03884
03885 if (reply->old_ia != NULL) {
03886 ia_id = &reply->old_ia->iaid_duid;
03887 ia_hash_delete(ia_pd_active,
03888 (unsigned char *)ia_id->data,
03889 ia_id->len, MDL);
03890 ia_dereference(&reply->old_ia, MDL);
03891 }
03892
03893
03894 reply->ia->cltt = cur_time;
03895 ia_id = &reply->ia->iaid_duid;
03896 ia_hash_add(ia_pd_active, (unsigned char *)ia_id->data,
03897 ia_id->len, reply->ia, MDL);
03898
03899 write_ia(reply->ia);
03900 }
03901
03902 cleanup:
03903 if (packet_ia != NULL)
03904 option_state_dereference(&packet_ia, MDL);
03905 if (reply->reply_ia != NULL)
03906 option_state_dereference(&reply->reply_ia, MDL);
03907 if (ia_data.data != NULL)
03908 data_string_forget(&ia_data, MDL);
03909 if (data.data != NULL)
03910 data_string_forget(&data, MDL);
03911 if (reply->ia != NULL)
03912 ia_dereference(&reply->ia, MDL);
03913 if (reply->old_ia != NULL)
03914 ia_dereference(&reply->old_ia, MDL);
03915 if (reply->lease != NULL)
03916 iasubopt_dereference(&reply->lease, MDL);
03917 if (reply->on_star.on_expiry != NULL)
03918 executable_statement_dereference
03919 (&reply->on_star.on_expiry, MDL);
03920 if (reply->on_star.on_release != NULL)
03921 executable_statement_dereference
03922 (&reply->on_star.on_release, MDL);
03923
03924
03925
03926
03927
03928
03929 return((status == ISC_R_CANCELED) ? ISC_R_SUCCESS : status);
03930 }
03931
03932
03933
03934
03935
03936
03937
03938 static isc_result_t
03939 reply_process_prefix(struct reply_state *reply, struct option_cache *pref) {
03940 u_int32_t pref_life, valid_life;
03941 struct binding_scope **scope;
03942 struct iaddrcidrnet tmp_pref;
03943 struct option_cache *oc;
03944 struct data_string iapref, data;
03945 isc_result_t status = ISC_R_SUCCESS;
03946 struct group *group;
03947
03948
03949 memset(&iapref, 0, sizeof(iapref));
03950 memset(&data, 0, sizeof(data));
03951
03952
03953
03954
03955
03956
03957 if ((reply->cursor + 29) > sizeof(reply->buf)) {
03958 log_error("reply_process_prefix: Out of room for prefix.");
03959 return ISC_R_NOSPACE;
03960 }
03961
03962
03963 if (!evaluate_option_cache(&iapref, reply->packet, NULL, NULL,
03964 reply->packet->options, NULL, &global_scope,
03965 pref, MDL) ||
03966 (iapref.len < IAPREFIX_OFFSET)) {
03967 log_error("reply_process_prefix: error evaluating IAPREFIX.");
03968 status = ISC_R_FAILURE;
03969 goto cleanup;
03970 }
03971
03972
03973
03974
03975
03976 pref_life = getULong(iapref.data);
03977 valid_life = getULong(iapref.data + 4);
03978
03979 if ((reply->client_valid == 0) ||
03980 (reply->client_valid > valid_life))
03981 reply->client_valid = valid_life;
03982
03983 if ((reply->client_prefer == 0) ||
03984 (reply->client_prefer > pref_life))
03985 reply->client_prefer = pref_life;
03986
03987
03988
03989
03990
03991 tmp_pref.lo_addr.len = 16;
03992 memset(tmp_pref.lo_addr.iabuf, 0, 16);
03993 if ((iapref.data[8] == 0) &&
03994 (memcmp(iapref.data + 9, tmp_pref.lo_addr.iabuf, 16) == 0)) {
03995
03996 goto cleanup;
03997 }
03998
03999
04000
04001
04002
04003 tmp_pref.bits = (int) iapref.data[8];
04004 if (reply->preflen < 0) {
04005
04006 reply->preflen = tmp_pref.bits;
04007 }
04008 if (memcmp(iapref.data + 9, tmp_pref.lo_addr.iabuf, 16) == 0) {
04009 goto cleanup;
04010 }
04011
04012 memcpy(tmp_pref.lo_addr.iabuf, iapref.data + 9, 16);
04013
04014
04015 if (!prefix_is_owned(reply, &tmp_pref)) {
04016
04017 if ((reply->packet->dhcpv6_msg_type == DHCPV6_SOLICIT) ||
04018 (reply->packet->dhcpv6_msg_type == DHCPV6_REQUEST) ||
04019 (reply->packet->dhcpv6_msg_type == DHCPV6_REBIND)) {
04020 status = reply_process_try_prefix(reply, &tmp_pref);
04021
04022
04023 if ((status != ISC_R_SUCCESS) &&
04024 (status != ISC_R_ADDRINUSE) &&
04025 (status != ISC_R_ADDRNOTAVAIL))
04026 goto cleanup;
04027
04028 if (reply->lease == NULL) {
04029 if (reply->packet->dhcpv6_msg_type ==
04030 DHCPV6_REBIND) {
04031 reply->send_prefer = 0;
04032 reply->send_valid = 0;
04033 goto send_pref;
04034 }
04035
04036
04037 goto cleanup;
04038 }
04039
04040
04041
04042
04043
04044
04045
04046
04047
04048
04049
04050
04051 } else if (reply->packet->dhcpv6_msg_type == DHCPV6_RENEW) {
04052
04053 option_state_dereference(&reply->reply_ia, MDL);
04054 if (!option_state_allocate(&reply->reply_ia, MDL)) {
04055 log_error("reply_process_prefix: No memory "
04056 "for option state wipe.");
04057 status = ISC_R_NOMEMORY;
04058 goto cleanup;
04059 }
04060
04061
04062 if (!set_status_code(STATUS_NoBinding,
04063 "Prefix not bound to this "
04064 "interface.", reply->reply_ia)) {
04065 log_error("reply_process_prefix: Unable to "
04066 "attach status code.");
04067 status = ISC_R_FAILURE;
04068 goto cleanup;
04069 }
04070
04071
04072 status = ISC_R_CANCELED;
04073 goto cleanup;
04074 } else {
04075 log_error("It is impossible to lease a client that is "
04076 "not sending a solicit, request, renew, or "
04077 "rebind message.");
04078 status = ISC_R_FAILURE;
04079 goto cleanup;
04080 }
04081 }
04082
04083 if (reply->static_prefixes > 0) {
04084 if (reply->host == NULL)
04085 log_fatal("Impossible condition at %s:%d.", MDL);
04086
04087 scope = &global_scope;
04088
04089
04090 if (find_grouped_subnet(&reply->subnet, reply->shared,
04091 tmp_pref.lo_addr, MDL) == 0)
04092 log_fatal("Impossible condition at %s:%d.", MDL);
04093 group = reply->subnet->group;
04094 subnet_dereference(&reply->subnet, MDL);
04095
04096
04097 memcpy(&reply->fixed_pref, &tmp_pref, sizeof(tmp_pref));
04098 } else {
04099 if (reply->lease == NULL)
04100 log_fatal("Impossible condition at %s:%d.", MDL);
04101
04102 scope = &reply->lease->scope;
04103 group = reply->lease->ipv6_pool->ipv6_pond->group;
04104 }
04105
04106
04107
04108
04109
04110
04111
04112 if (reply->client_resources != 0) {
04113 unsigned limit = 1;
04114
04115
04116
04117
04118
04119
04120 oc = lookup_option(&server_universe, reply->opt_state,
04121 SV_LIMIT_PREFS_PER_IA);
04122 if (oc != NULL) {
04123 if (!evaluate_option_cache(&data, reply->packet,
04124 NULL, NULL,
04125 reply->packet->options,
04126 reply->opt_state,
04127 scope, oc, MDL) ||
04128 (data.len != 4)) {
04129 log_error("reply_process_prefix: unable to "
04130 "evaluate prefs-per-ia value.");
04131 status = ISC_R_FAILURE;
04132 goto cleanup;
04133 }
04134
04135 limit = getULong(data.data);
04136 data_string_forget(&data, MDL);
04137 }
04138
04139
04140
04141
04142
04143 if (reply->client_resources >= limit)
04144 goto cleanup;
04145 }
04146
04147 status = reply_process_is_prefixed(reply, scope, group);
04148 if (status != ISC_R_SUCCESS)
04149 goto cleanup;
04150
04151 send_pref:
04152 status = reply_process_send_prefix(reply, &tmp_pref);
04153
04154 cleanup:
04155 if (iapref.data != NULL)
04156 data_string_forget(&iapref, MDL);
04157 if (data.data != NULL)
04158 data_string_forget(&data, MDL);
04159 if (reply->lease != NULL)
04160 iasubopt_dereference(&reply->lease, MDL);
04161
04162 return status;
04163 }
04164
04165
04166
04167
04168
04169
04170
04171 static isc_boolean_t
04172 prefix_is_owned(struct reply_state *reply, struct iaddrcidrnet *pref) {
04173 struct iaddrcidrnetlist *l;
04174 int i;
04175 struct ipv6_pond *pond;
04176
04177
04178
04179
04180 if (reply->static_prefixes > 0) {
04181 for (l = reply->host->fixed_prefix; l != NULL; l = l->next) {
04182 if ((pref->bits == l->cidrnet.bits) &&
04183 (memcmp(pref->lo_addr.iabuf,
04184 l->cidrnet.lo_addr.iabuf, 16) == 0))
04185 return (ISC_TRUE);
04186 }
04187 return (ISC_FALSE);
04188 }
04189
04190 if ((reply->old_ia == NULL) ||
04191 (reply->old_ia->num_iasubopt == 0))
04192 return (ISC_FALSE);
04193
04194 for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
04195 struct iasubopt *tmp;
04196
04197 tmp = reply->old_ia->iasubopt[i];
04198
04199 if ((pref->bits == (int) tmp->plen) &&
04200 (memcmp(pref->lo_addr.iabuf, &tmp->addr, 16) == 0)) {
04201 if (lease6_usable(tmp) == ISC_FALSE) {
04202 return (ISC_FALSE);
04203 }
04204
04205 pond = tmp->ipv6_pool->ipv6_pond;
04206 if (((pond->prohibit_list != NULL) &&
04207 (permitted(reply->packet, pond->prohibit_list))) ||
04208 ((pond->permit_list != NULL) &&
04209 (!permitted(reply->packet, pond->permit_list))))
04210 return (ISC_FALSE);
04211
04212 iasubopt_reference(&reply->lease, tmp, MDL);
04213 return (ISC_TRUE);
04214 }
04215 }
04216
04217 return (ISC_FALSE);
04218 }
04219
04220
04221
04222
04223
04224 static isc_result_t
04225 reply_process_try_prefix(struct reply_state *reply,
04226 struct iaddrcidrnet *pref) {
04227 isc_result_t status = ISC_R_ADDRNOTAVAIL;
04228 struct ipv6_pool *pool = NULL;
04229 struct ipv6_pond *pond = NULL;
04230 int i;
04231 struct data_string data_pref;
04232
04233 if ((reply == NULL) || (reply->shared == NULL) ||
04234 (pref == NULL) || (reply->lease != NULL))
04235 return (DHCP_R_INVALIDARG);
04236
04237
04238
04239
04240
04241 for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
04242 if (pond->ipv6_pools == NULL)
04243 continue;
04244
04245 for (i = 0; (pool = pond->ipv6_pools[i]) != NULL; i++) {
04246 if (pool->pool_type == D6O_IA_PD)
04247 break;
04248 }
04249 if (pool != NULL)
04250 break;
04251 }
04252
04253
04254 if (pool == NULL) {
04255 return (ISC_R_ADDRNOTAVAIL);
04256 }
04257
04258 memset(&data_pref, 0, sizeof(data_pref));
04259 data_pref.len = 17;
04260 if (!buffer_allocate(&data_pref.buffer, data_pref.len, MDL)) {
04261 log_error("reply_process_try_prefix: out of memory.");
04262 return (ISC_R_NOMEMORY);
04263 }
04264 data_pref.data = data_pref.buffer->data;
04265 data_pref.buffer->data[0] = (u_int8_t) pref->bits;
04266 memcpy(data_pref.buffer->data + 1, pref->lo_addr.iabuf, 16);
04267
04268
04269
04270
04271
04272
04273
04274
04275
04276 for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
04277 if (((pond->prohibit_list != NULL) &&
04278 (permitted(reply->packet, pond->prohibit_list))) ||
04279 ((pond->permit_list != NULL) &&
04280 (!permitted(reply->packet, pond->permit_list))))
04281 continue;
04282
04283 for (i = 0; (pool = pond->ipv6_pools[i]) != NULL; i++) {
04284 if (pool->pool_type != D6O_IA_PD) {
04285 continue;
04286 }
04287
04288 status = try_client_v6_prefix(&reply->lease, pool,
04289 &data_pref);
04290
04291
04292 if ( (status == ISC_R_SUCCESS) || (status == ISC_R_ADDRINUSE) )
04293 break;
04294 }
04295 if ( (status == ISC_R_SUCCESS) || (status == ISC_R_ADDRINUSE) )
04296 break;
04297 }
04298
04299 data_string_forget(&data_pref, MDL);
04300
04301 return (status);
04302 }
04303
04304
04305
04306
04307
04308 static isc_result_t
04309 find_client_prefix(struct reply_state *reply) {
04310 struct iaddrcidrnet send_pref;
04311 isc_result_t status = ISC_R_NORESOURCES;
04312 struct iasubopt *prefix, *best_prefix = NULL;
04313 struct binding_scope **scope;
04314 int i;
04315 struct group *group;
04316
04317 if (reply->static_prefixes > 0) {
04318 struct iaddrcidrnetlist *l;
04319
04320 if (reply->host == NULL)
04321 return DHCP_R_INVALIDARG;
04322
04323 for (l = reply->host->fixed_prefix; l != NULL; l = l->next) {
04324 if (l->cidrnet.bits == reply->preflen)
04325 break;
04326 }
04327 if (l == NULL) {
04328
04329
04330
04331
04332 l = reply->host->fixed_prefix;
04333 }
04334 memcpy(&send_pref, &l->cidrnet, sizeof(send_pref));
04335
04336 scope = &global_scope;
04337
04338
04339 if (find_grouped_subnet(&reply->subnet, reply->shared,
04340 send_pref.lo_addr, MDL) == 0)
04341 log_fatal("Impossible condition at %s:%d.", MDL);
04342 group = reply->subnet->group;
04343 subnet_dereference(&reply->subnet, MDL);
04344
04345
04346 memcpy(&reply->fixed_pref, &l->cidrnet, sizeof(send_pref));
04347
04348 goto send_pref;
04349 }
04350
04351 if (reply->old_ia != NULL) {
04352 for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
04353 struct shared_network *candidate_shared;
04354 struct ipv6_pond *pond;
04355
04356 prefix = reply->old_ia->iasubopt[i];
04357 candidate_shared = prefix->ipv6_pool->shared_network;
04358 pond = prefix->ipv6_pool->ipv6_pond;
04359
04360
04361
04362
04363
04364
04365 if (((candidate_shared != NULL) &&
04366 (candidate_shared != reply->shared)) ||
04367 (lease6_usable(prefix) != ISC_TRUE))
04368 continue;
04369
04370
04371
04372
04373
04374 if (((pond->prohibit_list != NULL) &&
04375 (permitted(reply->packet, pond->prohibit_list))) ||
04376 ((pond->permit_list != NULL) &&
04377 (!permitted(reply->packet, pond->permit_list))))
04378 continue;
04379
04380 best_prefix = prefix_compare(reply, prefix,
04381 best_prefix);
04382 }
04383 }
04384
04385
04386
04387
04388 if ((best_prefix == NULL) || (best_prefix->state == FTS_ABANDONED)) {
04389 status = pick_v6_prefix(reply);
04390 } else if (best_prefix != NULL) {
04391 iasubopt_reference(&reply->lease, best_prefix, MDL);
04392 status = ISC_R_SUCCESS;
04393 }
04394
04395
04396 if ((status == ISC_R_NORESOURCES) && (best_prefix != NULL)) {
04397
04398 log_error("Reclaiming abandoned prefixes is not yet "
04399 "supported. Treating this as an out of space "
04400 "condition.");
04401
04402 }
04403
04404
04405 if (status != ISC_R_SUCCESS)
04406 return status;
04407
04408 if (reply->lease == NULL)
04409 log_fatal("Impossible condition at %s:%d.", MDL);
04410
04411 scope = &reply->lease->scope;
04412 group = reply->lease->ipv6_pool->ipv6_pond->group;
04413
04414 send_pref.lo_addr.len = 16;
04415 memcpy(send_pref.lo_addr.iabuf, &reply->lease->addr, 16);
04416 send_pref.bits = (int) reply->lease->plen;
04417
04418 send_pref:
04419 status = reply_process_is_prefixed(reply, scope, group);
04420 if (status != ISC_R_SUCCESS)
04421 return status;
04422
04423 status = reply_process_send_prefix(reply, &send_pref);
04424 return status;
04425 }
04426
04427
04428
04429
04430
04431 static isc_result_t
04432 reply_process_is_prefixed(struct reply_state *reply,
04433 struct binding_scope **scope, struct group *group)
04434 {
04435 isc_result_t status = ISC_R_SUCCESS;
04436 struct data_string data;
04437 struct option_cache *oc;
04438 struct option_state *tmp_options = NULL;
04439 struct on_star *on_star;
04440 int i;
04441
04442
04443 memset(&data, 0, sizeof(data));
04444
04445
04446
04447
04448
04449
04450
04451 if (reply->lease) {
04452 on_star = &reply->lease->on_star;
04453 } else {
04454 on_star = &reply->on_star;
04455 }
04456
04457
04458
04459
04460
04461
04462 option_state_allocate(&tmp_options, MDL);
04463 execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
04464 reply->packet->options, tmp_options,
04465 &global_scope, root_group, NULL,
04466 on_star);
04467 if (tmp_options != NULL) {
04468 option_state_dereference(&tmp_options, MDL);
04469 }
04470
04471
04472
04473
04474
04475
04476 execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
04477 reply->packet->options, reply->opt_state,
04478 scope, group, root_group, on_star);
04479
04480
04481 for (i = reply->packet->class_count; i > 0; i--) {
04482 execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
04483 reply->packet->options,
04484 reply->opt_state, scope,
04485 reply->packet->classes[i - 1]->group,
04486 group, on_star);
04487 }
04488
04489
04490
04491
04492
04493
04494 if (reply->host != NULL)
04495 execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
04496 reply->packet->options,
04497 reply->opt_state, scope,
04498 reply->host->group, group,
04499 on_star);
04500
04501
04502 if (reply->client_valid == 0)
04503 reply->send_valid = DEFAULT_DEFAULT_LEASE_TIME;
04504 else
04505 reply->send_valid = reply->client_valid;
04506
04507 oc = lookup_option(&server_universe, reply->opt_state,
04508 SV_DEFAULT_LEASE_TIME);
04509 if (oc != NULL) {
04510 if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
04511 reply->packet->options,
04512 reply->opt_state,
04513 scope, oc, MDL) ||
04514 (data.len != 4)) {
04515 log_error("reply_process_is_prefixed: unable to "
04516 "evaluate default prefix time");
04517 status = ISC_R_FAILURE;
04518 goto cleanup;
04519 }
04520
04521 reply->send_valid = getULong(data.data);
04522 data_string_forget(&data, MDL);
04523 }
04524
04525 if (reply->client_prefer == 0)
04526 reply->send_prefer = reply->send_valid;
04527 else
04528 reply->send_prefer = reply->client_prefer;
04529
04530 if (reply->send_prefer >= reply->send_valid)
04531 reply->send_prefer = (reply->send_valid / 2) +
04532 (reply->send_valid / 8);
04533
04534 oc = lookup_option(&server_universe, reply->opt_state,
04535 SV_PREFER_LIFETIME);
04536 if (oc != NULL) {
04537 if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
04538 reply->packet->options,
04539 reply->opt_state,
04540 scope, oc, MDL) ||
04541 (data.len != 4)) {
04542 log_error("reply_process_is_prefixed: unable to "
04543 "evaluate preferred prefix time");
04544 status = ISC_R_FAILURE;
04545 goto cleanup;
04546 }
04547
04548 reply->send_prefer = getULong(data.data);
04549 data_string_forget(&data, MDL);
04550 }
04551
04552
04553 if (reply->prefer > reply->send_prefer)
04554 reply->prefer = reply->send_prefer;
04555
04556 if (reply->valid > reply->send_valid)
04557 reply->valid = reply->send_valid;
04558
04559
04560 if (reply->lease != NULL) {
04561
04562 reply->lease->prefer = reply->send_prefer;
04563 reply->lease->valid = reply->send_valid;
04564
04565
04566 if (reply->buf.reply.msg_type == DHCPV6_REPLY) {
04567 reply->lease->soft_lifetime_end_time =
04568 cur_time + reply->send_valid;
04569
04570 }
04571
04572 status = ia_add_iasubopt(reply->ia, reply->lease, MDL);
04573 if (status != ISC_R_SUCCESS) {
04574 log_fatal("reply_process_is_prefixed: Unable to "
04575 "attach prefix to new IA_PD: %s",
04576 isc_result_totext(status));
04577 }
04578
04579
04580
04581
04582 if (reply->lease->ia == NULL) {
04583 ia_reference(&reply->lease->ia, reply->ia, MDL);
04584 }
04585 }
04586
04587
04588 execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
04589 reply->packet->options, reply->reply_ia,
04590 scope, group, root_group, NULL);
04591
04592
04593 for (i = reply->packet->class_count; i > 0; i--) {
04594 execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
04595 reply->packet->options,
04596 reply->reply_ia, scope,
04597 reply->packet->classes[i - 1]->group,
04598 group, NULL);
04599 }
04600
04601
04602
04603
04604
04605 if (reply->host != NULL)
04606 execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
04607 reply->packet->options,
04608 reply->reply_ia, scope,
04609 reply->host->group, group, NULL);
04610
04611 cleanup:
04612 if (data.data != NULL)
04613 data_string_forget(&data, MDL);
04614
04615 if (status == ISC_R_SUCCESS)
04616 reply->client_resources++;
04617
04618 return status;
04619 }
04620
04621
04622 static isc_result_t
04623 reply_process_send_prefix(struct reply_state *reply,
04624 struct iaddrcidrnet *pref) {
04625 isc_result_t status = ISC_R_SUCCESS;
04626 struct data_string data;
04627
04628 memset(&data, 0, sizeof(data));
04629
04630
04631 data.len = IAPREFIX_OFFSET;
04632 if (!buffer_allocate(&data.buffer, data.len, MDL)) {
04633 log_error("reply_process_send_prefix: out of memory"
04634 "allocating new IAPREFIX buffer.");
04635 status = ISC_R_NOMEMORY;
04636 goto cleanup;
04637 }
04638 data.data = data.buffer->data;
04639
04640 putULong(data.buffer->data, reply->send_prefer);
04641 putULong(data.buffer->data + 4, reply->send_valid);
04642 data.buffer->data[8] = pref->bits;
04643 memcpy(data.buffer->data + 9, pref->lo_addr.iabuf, 16);
04644
04645 if (!append_option_buffer(&dhcpv6_universe, reply->reply_ia,
04646 data.buffer, data.buffer->data,
04647 data.len, D6O_IAPREFIX, 0)) {
04648 log_error("reply_process_send_prefix: unable "
04649 "to save IAPREFIX option");
04650 status = ISC_R_FAILURE;
04651 goto cleanup;
04652 }
04653
04654 reply->resources_included = ISC_TRUE;
04655
04656 cleanup:
04657 if (data.data != NULL)
04658 data_string_forget(&data, MDL);
04659
04660 return status;
04661 }
04662
04663
04664 static struct iasubopt *
04665 prefix_compare(struct reply_state *reply,
04666 struct iasubopt *alpha, struct iasubopt *beta) {
04667 if (alpha == NULL)
04668 return beta;
04669 if (beta == NULL)
04670 return alpha;
04671
04672 if (reply->preflen >= 0) {
04673 if ((alpha->plen == reply->preflen) &&
04674 (beta->plen != reply->preflen))
04675 return alpha;
04676 if ((beta->plen == reply->preflen) &&
04677 (alpha->plen != reply->preflen))
04678 return beta;
04679 }
04680
04681 switch(alpha->state) {
04682 case FTS_ACTIVE:
04683 switch(beta->state) {
04684 case FTS_ACTIVE:
04685
04686
04687
04688 if (alpha->hard_lifetime_end_time <
04689 beta->hard_lifetime_end_time)
04690 return beta;
04691 else
04692 return alpha;
04693
04694 case FTS_EXPIRED:
04695 case FTS_ABANDONED:
04696 return alpha;
04697
04698 default:
04699 log_fatal("Impossible condition at %s:%d.", MDL);
04700 }
04701 break;
04702
04703 case FTS_EXPIRED:
04704 switch (beta->state) {
04705 case FTS_ACTIVE:
04706 return beta;
04707
04708 case FTS_EXPIRED:
04709
04710 if (alpha->hard_lifetime_end_time <
04711 beta->hard_lifetime_end_time)
04712 return beta;
04713 else if ((alpha->hard_lifetime_end_time ==
04714 beta->hard_lifetime_end_time) &&
04715 (alpha->soft_lifetime_end_time <
04716 beta->soft_lifetime_end_time))
04717 return beta;
04718 else
04719 return alpha;
04720
04721 case FTS_ABANDONED:
04722 return alpha;
04723
04724 default:
04725 log_fatal("Impossible condition at %s:%d.", MDL);
04726 }
04727 break;
04728
04729 case FTS_ABANDONED:
04730 switch (beta->state) {
04731 case FTS_ACTIVE:
04732 case FTS_EXPIRED:
04733 return alpha;
04734
04735 case FTS_ABANDONED:
04736
04737 if (alpha->hard_lifetime_end_time <
04738 beta->hard_lifetime_end_time)
04739 return alpha;
04740
04741 default:
04742 log_fatal("Impossible condition at %s:%d.", MDL);
04743 }
04744 break;
04745
04746 default:
04747 log_fatal("Impossible condition at %s:%d.", MDL);
04748 }
04749
04750 log_fatal("Triple impossible condition at %s:%d.", MDL);
04751 return NULL;
04752 }
04753
04754
04755
04756
04757
04758
04759
04760
04761
04762
04763 static void
04764 dhcpv6_solicit(struct data_string *reply_ret, struct packet *packet) {
04765 struct data_string client_id;
04766
04767 TRACE(DHCPD_6_SOLICIT_START());
04768
04769
04770
04771
04772 if (!valid_client_msg(packet, &client_id)) {
04773 return;
04774 }
04775
04776 lease_to_client(reply_ret, packet, &client_id, NULL);
04777
04778
04779
04780
04781 data_string_forget(&client_id, MDL);
04782
04783 TRACE(DHCPD_6_SOLICIT_DONE());
04784 }
04785
04786
04787
04788
04789
04790
04791
04792 static void
04793 dhcpv6_request(struct data_string *reply_ret, struct packet *packet) {
04794 struct data_string client_id;
04795 struct data_string server_id;
04796
04797 TRACE(DHCPD_6_REQUEST_START());
04798
04799
04800
04801
04802 if (!valid_client_resp(packet, &client_id, &server_id)) {
04803 return;
04804 }
04805
04806
04807
04808
04809 lease_to_client(reply_ret, packet, &client_id, &server_id);
04810
04811
04812
04813
04814 data_string_forget(&client_id, MDL);
04815 data_string_forget(&server_id, MDL);
04816
04817 TRACE(DHCPD_6_REQUEST_DONE());
04818 }
04819
04820
04821
04822 static isc_result_t
04823 shared_network_from_packet6(struct shared_network **shared,
04824 struct packet *packet)
04825 {
04826 const struct packet *chk_packet;
04827 const struct in6_addr *link_addr, *first_link_addr;
04828 struct iaddr tmp_addr;
04829 struct subnet *subnet;
04830 isc_result_t status;
04831
04832 if ((shared == NULL) || (*shared != NULL) || (packet == NULL))
04833 return DHCP_R_INVALIDARG;
04834
04835
04836
04837
04838
04839 first_link_addr = NULL;
04840 chk_packet = packet->dhcpv6_container_packet;
04841 while (chk_packet != NULL) {
04842 link_addr = &chk_packet->dhcpv6_link_address;
04843 if (!IN6_IS_ADDR_UNSPECIFIED(link_addr) &&
04844 !IN6_IS_ADDR_LINKLOCAL(link_addr)) {
04845 first_link_addr = link_addr;
04846 break;
04847 }
04848 chk_packet = chk_packet->dhcpv6_container_packet;
04849 }
04850
04851
04852
04853
04854
04855
04856 if (first_link_addr != NULL) {
04857 tmp_addr.len = sizeof(*first_link_addr);
04858 memcpy(tmp_addr.iabuf,
04859 first_link_addr, sizeof(*first_link_addr));
04860 subnet = NULL;
04861 if (!find_subnet(&subnet, tmp_addr, MDL)) {
04862 log_debug("No subnet found for link-address %s.",
04863 piaddr(tmp_addr));
04864 return ISC_R_NOTFOUND;
04865 }
04866 status = shared_network_reference(shared,
04867 subnet->shared_network, MDL);
04868 subnet_dereference(&subnet, MDL);
04869
04870
04871
04872
04873
04874 } else if (packet->interface != NULL) {
04875 status = shared_network_reference(shared,
04876 packet->interface->shared_network,
04877 MDL);
04878 if (packet->dhcpv6_container_packet != NULL) {
04879 log_info("[L2 Relay] No link address in relay packet "
04880 "assuming L2 relay and using receiving "
04881 "interface");
04882 }
04883
04884 } else {
04885
04886
04887
04888
04889
04890 log_error("No interface and no link address "
04891 "can't determine pool");
04892 status = DHCP_R_INVALIDARG;
04893 }
04894
04895 return status;
04896 }
04897
04898
04899
04900
04901
04902
04903
04904
04905
04906
04907
04908
04909
04910
04911
04912
04913
04914
04915
04916 static void
04917 dhcpv6_confirm(struct data_string *reply_ret, struct packet *packet) {
04918 struct shared_network *shared;
04919 struct subnet *subnet;
04920 struct option_cache *ia, *ta, *oc;
04921 struct data_string cli_enc_opt_data, iaaddr, client_id, packet_oro;
04922 struct option_state *cli_enc_opt_state, *opt_state;
04923 struct iaddr cli_addr;
04924 int pass;
04925 isc_boolean_t inappropriate, has_addrs;
04926 char reply_data[65536];
04927 struct dhcpv6_packet *reply = (struct dhcpv6_packet *)reply_data;
04928 int reply_ofs = (int)(offsetof(struct dhcpv6_packet, options));
04929
04930 TRACE(DHCPD_6_CONFIRM_START());
04931
04932
04933
04934
04935 memset(&client_id, 0, sizeof(client_id));
04936 if (!valid_client_msg(packet, &client_id)) {
04937 return;
04938 }
04939
04940
04941
04942
04943 ia = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA);
04944 ta = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_TA);
04945 if ((ia == NULL) && (ta == NULL))
04946 return;
04947
04948
04949
04950
04951 delete_option(&dhcpv6_universe, packet->options, D6O_IA_PD);
04952
04953
04954
04955
04956 opt_state = cli_enc_opt_state = NULL;
04957 memset(&cli_enc_opt_data, 0, sizeof(cli_enc_opt_data));
04958 memset(&iaaddr, 0, sizeof(iaaddr));
04959 memset(&packet_oro, 0, sizeof(packet_oro));
04960
04961
04962
04963
04964
04965 shared = NULL;
04966 if ((shared_network_from_packet6(&shared, packet) != ISC_R_SUCCESS) ||
04967 (shared == NULL))
04968 goto exit;
04969
04970
04971
04972
04973 subnet = shared->subnets;
04974 if (subnet == NULL)
04975 goto exit;
04976
04977
04978 has_addrs = inappropriate = ISC_FALSE;
04979 pass = D6O_IA_NA;
04980 while(!inappropriate) {
04981
04982
04983
04984 if ((pass == D6O_IA_NA) && (ia == NULL)) {
04985 pass = D6O_IA_TA;
04986 ia = ta;
04987 }
04988
04989
04990 if (ia == NULL)
04991 break;
04992
04993 if (((pass == D6O_IA_NA) &&
04994 !get_encapsulated_IA_state(&cli_enc_opt_state,
04995 &cli_enc_opt_data,
04996 packet, ia, IA_NA_OFFSET)) ||
04997 ((pass == D6O_IA_TA) &&
04998 !get_encapsulated_IA_state(&cli_enc_opt_state,
04999 &cli_enc_opt_data,
05000 packet, ia, IA_TA_OFFSET))) {
05001 goto exit;
05002 }
05003
05004 oc = lookup_option(&dhcpv6_universe, cli_enc_opt_state,
05005 D6O_IAADDR);
05006
05007 for ( ; oc != NULL ; oc = oc->next) {
05008 if (!evaluate_option_cache(&iaaddr, packet, NULL, NULL,
05009 packet->options, NULL,
05010 &global_scope, oc, MDL) ||
05011 (iaaddr.len < IAADDR_OFFSET)) {
05012 log_error("dhcpv6_confirm: "
05013 "error evaluating IAADDR.");
05014 goto exit;
05015 }
05016
05017
05018 cli_addr.len = 16;
05019 memcpy(cli_addr.iabuf, iaaddr.data, 16);
05020
05021 data_string_forget(&iaaddr, MDL);
05022
05023
05024 has_addrs = ISC_TRUE;
05025
05026
05027 for (subnet = shared->subnets ; subnet != NULL ;
05028 subnet = subnet->next_sibling) {
05029 if (addr_eq(subnet_number(cli_addr,
05030 subnet->netmask),
05031 subnet->net))
05032 break;
05033 }
05034
05035
05036
05037
05038
05039
05040
05041
05042 if (subnet == NULL) {
05043 inappropriate = ISC_TRUE;
05044 break;
05045 }
05046 }
05047
05048 option_state_dereference(&cli_enc_opt_state, MDL);
05049 data_string_forget(&cli_enc_opt_data, MDL);
05050
05051
05052 ia = ia->next;
05053 }
05054
05055
05056 if (!has_addrs)
05057 goto exit;
05058
05059
05060
05061
05062 if (!start_reply(packet, &client_id, NULL, &opt_state, reply)) {
05063 goto exit;
05064 }
05065
05066
05067
05068
05069 if (inappropriate) {
05070 if (!set_status_code(STATUS_NotOnLink,
05071 "Some of the addresses are not on link.",
05072 opt_state)) {
05073 goto exit;
05074 }
05075 } else {
05076 if (!set_status_code(STATUS_Success,
05077 "All addresses still on link.",
05078 opt_state)) {
05079 goto exit;
05080 }
05081 }
05082
05083
05084
05085
05086 reply_ofs += store_options6(reply_data+reply_ofs,
05087 sizeof(reply_data)-reply_ofs,
05088 opt_state, packet,
05089 required_opts, &packet_oro);
05090
05091
05092
05093
05094 reply_ret->len = reply_ofs;
05095 reply_ret->buffer = NULL;
05096 if (!buffer_allocate(&reply_ret->buffer, reply_ofs, MDL)) {
05097 log_fatal("No memory to store reply.");
05098 }
05099 reply_ret->data = reply_ret->buffer->data;
05100 memcpy(reply_ret->buffer->data, reply, reply_ofs);
05101
05102 exit:
05103
05104 if (cli_enc_opt_data.buffer != NULL)
05105 data_string_forget(&cli_enc_opt_data, MDL);
05106 if (iaaddr.buffer != NULL)
05107 data_string_forget(&iaaddr, MDL);
05108 if (client_id.buffer != NULL)
05109 data_string_forget(&client_id, MDL);
05110 if (packet_oro.buffer != NULL)
05111 data_string_forget(&packet_oro, MDL);
05112
05113
05114 if (cli_enc_opt_state != NULL)
05115 option_state_dereference(&cli_enc_opt_state, MDL);
05116 if (opt_state != NULL)
05117 option_state_dereference(&opt_state, MDL);
05118
05119 TRACE(DHCPD_6_CONFIRM_DONE());
05120 }
05121
05122
05123
05124
05125
05126
05127
05128
05129 static void
05130 dhcpv6_renew(struct data_string *reply, struct packet *packet) {
05131 struct data_string client_id;
05132 struct data_string server_id;
05133
05134 TRACE(DHCPD_6_RENEW_START());
05135
05136
05137
05138
05139 if (!valid_client_resp(packet, &client_id, &server_id)) {
05140 return;
05141 }
05142
05143
05144
05145
05146 lease_to_client(reply, packet, &client_id, &server_id);
05147
05148
05149
05150
05151 data_string_forget(&server_id, MDL);
05152 data_string_forget(&client_id, MDL);
05153
05154 TRACE(DHCPD_6_RENEW_DONE());
05155 }
05156
05157
05158
05159
05160
05161
05162
05163
05164 static void
05165 dhcpv6_rebind(struct data_string *reply, struct packet *packet) {
05166 struct data_string client_id;
05167
05168 TRACE(DHCPD_6_REBIND_START());
05169
05170 if (!valid_client_msg(packet, &client_id)) {
05171 return;
05172 }
05173
05174 lease_to_client(reply, packet, &client_id, NULL);
05175
05176 data_string_forget(&client_id, MDL);
05177
05178 TRACE(DHCPD_6_REBIND_DONE());
05179 }
05180
05181 static void
05182 ia_na_match_decline(const struct data_string *client_id,
05183 const struct data_string *iaaddr,
05184 struct iasubopt *lease)
05185 {
05186 char tmp_addr[INET6_ADDRSTRLEN];
05187
05188 log_error("Client %s reports address %s is "
05189 "already in use by another host!",
05190 print_hex_1(client_id->len, client_id->data, 60),
05191 inet_ntop(AF_INET6, iaaddr->data,
05192 tmp_addr, sizeof(tmp_addr)));
05193 if (lease != NULL) {
05194 decline_lease6(lease->ipv6_pool, lease);
05195 lease->ia->cltt = cur_time;
05196 write_ia(lease->ia);
05197 }
05198 }
05199
05200 static void
05201 ia_na_nomatch_decline(const struct data_string *client_id,
05202 const struct data_string *iaaddr,
05203 u_int32_t *ia_na_id,
05204 struct packet *packet,
05205 char *reply_data,
05206 int *reply_ofs,
05207 int reply_len)
05208 {
05209 char tmp_addr[INET6_ADDRSTRLEN];
05210 struct option_state *host_opt_state;
05211 int len;
05212
05213 log_info("Client %s declines address %s, which is not offered to it.",
05214 print_hex_1(client_id->len, client_id->data, 60),
05215 inet_ntop(AF_INET6, iaaddr->data, tmp_addr, sizeof(tmp_addr)));
05216
05217
05218
05219
05220 host_opt_state = NULL;
05221 if (!option_state_allocate(&host_opt_state, MDL)) {
05222 log_error("ia_na_nomatch_decline: out of memory "
05223 "allocating option_state.");
05224 goto exit;
05225 }
05226
05227 if (!set_status_code(STATUS_NoBinding, "Decline for unknown address.",
05228 host_opt_state)) {
05229 goto exit;
05230 }
05231
05232
05233
05234
05235 if (reply_len < (*reply_ofs + 16)) {
05236 log_error("ia_na_nomatch_decline: "
05237 "out of space for reply packet.");
05238 goto exit;
05239 }
05240
05241
05242
05243
05244 len = store_options6(reply_data+(*reply_ofs)+16,
05245 reply_len-(*reply_ofs)-16,
05246 host_opt_state, packet,
05247 required_opts_STATUS_CODE, NULL);
05248
05249
05250
05251
05252
05253
05254
05255 putUShort((unsigned char *)reply_data+(*reply_ofs), D6O_IA_NA);
05256
05257 putUShort((unsigned char *)reply_data+(*reply_ofs)+2, len + 12);
05258
05259 memcpy(reply_data+(*reply_ofs)+4, ia_na_id, 4);
05260
05261 putULong((unsigned char *)reply_data+(*reply_ofs)+8, 0);
05262 putULong((unsigned char *)reply_data+(*reply_ofs)+12, 0);
05263
05264
05265
05266
05267 *reply_ofs += (len + 16);
05268
05269 exit:
05270 option_state_dereference(&host_opt_state, MDL);
05271 }
05272
05273 static void
05274 iterate_over_ia_na(struct data_string *reply_ret,
05275 struct packet *packet,
05276 const struct data_string *client_id,
05277 const struct data_string *server_id,
05278 const char *packet_type,
05279 void (*ia_na_match)(),
05280 void (*ia_na_nomatch)())
05281 {
05282 struct option_state *opt_state;
05283 struct host_decl *packet_host;
05284 struct option_cache *ia;
05285 struct option_cache *oc;
05286
05287 struct data_string cli_enc_opt_data;
05288 struct option_state *cli_enc_opt_state;
05289 struct host_decl *host;
05290 struct option_state *host_opt_state;
05291 struct data_string iaaddr;
05292 struct data_string fixed_addr;
05293 char reply_data[65536];
05294 struct dhcpv6_packet *reply = (struct dhcpv6_packet *)reply_data;
05295 int reply_ofs = (int)(offsetof(struct dhcpv6_packet, options));
05296 char status_msg[32];
05297 struct iasubopt *lease;
05298 struct ia_xx *existing_ia_na;
05299 int i;
05300 struct data_string key;
05301 u_int32_t iaid;
05302
05303
05304
05305
05306 opt_state = NULL;
05307 memset(&cli_enc_opt_data, 0, sizeof(cli_enc_opt_data));
05308 cli_enc_opt_state = NULL;
05309 memset(&iaaddr, 0, sizeof(iaaddr));
05310 memset(&fixed_addr, 0, sizeof(fixed_addr));
05311 host_opt_state = NULL;
05312 lease = NULL;
05313
05314
05315
05316
05317 packet_host = NULL;
05318 if (!find_hosts_by_uid(&packet_host,
05319 client_id->data, client_id->len, MDL)) {
05320 packet_host = NULL;
05321
05322
05323
05324
05325
05326
05327 if (!find_hosts_by_option(&packet_host,
05328 packet, packet->options, MDL)) {
05329 packet_host = NULL;
05330
05331 if (!find_hosts_by_duid_chaddr(&packet_host,
05332 client_id))
05333 packet_host = NULL;
05334 }
05335 }
05336
05337
05338
05339
05340 reply->msg_type = DHCPV6_REPLY;
05341 memcpy(reply->transaction_id, packet->dhcpv6_transaction_id,
05342 sizeof(reply->transaction_id));
05343
05344
05345
05346
05347 opt_state = NULL;
05348 if (!option_state_allocate(&opt_state, MDL)) {
05349 log_error("iterate_over_ia_na: no memory for option_state.");
05350 goto exit;
05351 }
05352 execute_statements_in_scope(NULL, packet, NULL, NULL,
05353 packet->options, opt_state,
05354 &global_scope, root_group, NULL, NULL);
05355
05356
05357
05358
05359 oc = lookup_option(&dhcpv6_universe, opt_state, D6O_SERVERID);
05360 if (oc == NULL) {
05361 if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL,
05362 (unsigned char *)server_duid.data,
05363 server_duid.len, D6O_SERVERID, 0)) {
05364 log_error("iterate_over_ia_na: "
05365 "error saving server identifier.");
05366 goto exit;
05367 }
05368 }
05369
05370 if (!save_option_buffer(&dhcpv6_universe, opt_state,
05371 client_id->buffer,
05372 (unsigned char *)client_id->data,
05373 client_id->len,
05374 D6O_CLIENTID, 0)) {
05375 log_error("iterate_over_ia_na: "
05376 "error saving client identifier.");
05377 goto exit;
05378 }
05379
05380
05381 if ((packet->unicast == ISC_TRUE) && !is_unicast_option_defined()) {
05382
05383
05384
05385
05386
05387
05388
05389
05390
05391
05392
05393
05394
05395
05396
05397
05398
05399
05400
05401 snprintf(status_msg, sizeof(status_msg),
05402 "%s received unicast.", packet_type);
05403 if (!set_status_code(STATUS_UseMulticast, status_msg, opt_state)) {
05404 goto exit;
05405 }
05406
05407
05408
05409
05410
05411
05412
05413
05414 reply_ofs += store_options6(reply_data+reply_ofs,
05415 sizeof(reply_data)-reply_ofs,
05416 opt_state, packet,
05417 required_opts_NAA, NULL);
05418
05419 goto return_reply;
05420 } else {
05421 snprintf(status_msg, sizeof(status_msg), "%s received.", packet_type);
05422 if (!set_status_code(STATUS_Success, status_msg, opt_state)) {
05423 goto exit;
05424 }
05425
05426
05427
05428
05429 reply_ofs += store_options6(reply_data+reply_ofs,
05430 sizeof(reply_data)-reply_ofs,
05431 opt_state, packet,
05432 required_opts, NULL);
05433 }
05434
05435
05436
05437
05438
05439 for (ia = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA);
05440 ia != NULL; ia = ia->next) {
05441
05442 if (!get_encapsulated_IA_state(&cli_enc_opt_state,
05443 &cli_enc_opt_data,
05444 packet, ia, IA_NA_OFFSET)) {
05445 goto exit;
05446 }
05447
05448 iaid = getULong(cli_enc_opt_data.data);
05449
05450
05451
05452
05453
05454
05455
05456
05457 oc = lookup_option(&dhcpv6_universe, cli_enc_opt_state,
05458 D6O_IAADDR);
05459 if (oc == NULL) {
05460
05461 option_state_dereference(&cli_enc_opt_state, MDL);
05462 data_string_forget(&cli_enc_opt_data, MDL);
05463 continue;
05464 }
05465
05466 memset(&iaaddr, 0, sizeof(iaaddr));
05467 if (!evaluate_option_cache(&iaaddr, packet, NULL, NULL,
05468 packet->options, NULL,
05469 &global_scope, oc, MDL)) {
05470 log_error("iterate_over_ia_na: "
05471 "error evaluating IAADDR.");
05472 goto exit;
05473 }
05474
05475
05476
05477
05478
05479
05480
05481
05482
05483 host = NULL;
05484 if (!find_hosts_by_option(&host, packet,
05485 cli_enc_opt_state, MDL)) {
05486 if (packet_host != NULL) {
05487 host = packet_host;
05488 } else {
05489 host = NULL;
05490 }
05491 }
05492 while (host != NULL) {
05493 if (host->fixed_addr != NULL) {
05494 if (!evaluate_option_cache(&fixed_addr, NULL,
05495 NULL, NULL, NULL,
05496 NULL, &global_scope,
05497 host->fixed_addr,
05498 MDL)) {
05499 log_error("iterate_over_ia_na: error "
05500 "evaluating host address.");
05501 goto exit;
05502 }
05503 if ((iaaddr.len >= 16) &&
05504 !memcmp(fixed_addr.data, iaaddr.data, 16)) {
05505 data_string_forget(&fixed_addr, MDL);
05506 break;
05507 }
05508 data_string_forget(&fixed_addr, MDL);
05509 }
05510 host = host->n_ipaddr;
05511 }
05512
05513 if ((host == NULL) && (iaaddr.len >= IAADDR_OFFSET)) {
05514
05515
05516
05517 if (ia_make_key(&key, iaid,
05518 (char *)client_id->data,
05519 client_id->len,
05520 MDL) != ISC_R_SUCCESS) {
05521 log_fatal("iterate_over_ia_na: no memory for "
05522 "key.");
05523 }
05524
05525 existing_ia_na = NULL;
05526 if (ia_hash_lookup(&existing_ia_na, ia_na_active,
05527 (unsigned char *)key.data,
05528 key.len, MDL)) {
05529
05530
05531
05532 for (i=0; i<existing_ia_na->num_iasubopt; i++) {
05533 struct iasubopt *tmp;
05534 struct in6_addr *in6_addr;
05535
05536 tmp = existing_ia_na->iasubopt[i];
05537 in6_addr = &tmp->addr;
05538 if (memcmp(in6_addr,
05539 iaaddr.data, 16) == 0) {
05540 iasubopt_reference(&lease,
05541 tmp, MDL);
05542 break;
05543 }
05544 }
05545 }
05546
05547 data_string_forget(&key, MDL);
05548 }
05549
05550 if ((host != NULL) || (lease != NULL)) {
05551 ia_na_match(client_id, &iaaddr, lease);
05552 } else {
05553 ia_na_nomatch(client_id, &iaaddr,
05554 (u_int32_t *)cli_enc_opt_data.data,
05555 packet, reply_data, &reply_ofs,
05556 sizeof(reply_data));
05557 }
05558
05559 if (lease != NULL) {
05560 iasubopt_dereference(&lease, MDL);
05561 }
05562
05563 data_string_forget(&iaaddr, MDL);
05564 option_state_dereference(&cli_enc_opt_state, MDL);
05565 data_string_forget(&cli_enc_opt_data, MDL);
05566 }
05567
05568
05569
05570
05571 return_reply:
05572 reply_ret->len = reply_ofs;
05573 reply_ret->buffer = NULL;
05574 if (!buffer_allocate(&reply_ret->buffer, reply_ofs, MDL)) {
05575 log_fatal("No memory to store reply.");
05576 }
05577 reply_ret->data = reply_ret->buffer->data;
05578 memcpy(reply_ret->buffer->data, reply, reply_ofs);
05579
05580 exit:
05581 if (lease != NULL) {
05582 iasubopt_dereference(&lease, MDL);
05583 }
05584 if (host_opt_state != NULL) {
05585 option_state_dereference(&host_opt_state, MDL);
05586 }
05587 if (fixed_addr.buffer != NULL) {
05588 data_string_forget(&fixed_addr, MDL);
05589 }
05590 if (iaaddr.buffer != NULL) {
05591 data_string_forget(&iaaddr, MDL);
05592 }
05593 if (cli_enc_opt_state != NULL) {
05594 option_state_dereference(&cli_enc_opt_state, MDL);
05595 }
05596 if (cli_enc_opt_data.buffer != NULL) {
05597 data_string_forget(&cli_enc_opt_data, MDL);
05598 }
05599 if (opt_state != NULL) {
05600 option_state_dereference(&opt_state, MDL);
05601 }
05602 }
05603
05604
05605
05606
05607
05608
05609
05610
05611
05612
05613
05614
05615
05616
05617
05618 static void
05619 dhcpv6_decline(struct data_string *reply, struct packet *packet) {
05620 struct data_string client_id;
05621 struct data_string server_id;
05622
05623 TRACE(DHCPD_6_DECLINE_START());
05624
05625
05626
05627
05628 if (!valid_client_resp(packet, &client_id, &server_id)) {
05629 return;
05630 }
05631
05632
05633
05634
05635 delete_option(&dhcpv6_universe, packet->options, D6O_IA_PD);
05636
05637
05638
05639
05640 iterate_over_ia_na(reply, packet, &client_id, &server_id, "Decline",
05641 ia_na_match_decline, ia_na_nomatch_decline);
05642
05643 data_string_forget(&server_id, MDL);
05644 data_string_forget(&client_id, MDL);
05645
05646 TRACE(DHCPD_6_DECLINE_DONE());
05647 }
05648
05649 static void
05650 ia_na_match_release(const struct data_string *client_id,
05651 const struct data_string *iaaddr,
05652 struct iasubopt *lease)
05653 {
05654 char tmp_addr[INET6_ADDRSTRLEN];
05655
05656 log_info("Client %s releases address %s",
05657 print_hex_1(client_id->len, client_id->data, 60),
05658 inet_ntop(AF_INET6, iaaddr->data, tmp_addr, sizeof(tmp_addr)));
05659 if (lease != NULL) {
05660 release_lease6(lease->ipv6_pool, lease);
05661 lease->ia->cltt = cur_time;
05662 write_ia(lease->ia);
05663 }
05664 }
05665
05666 static void
05667 ia_na_nomatch_release(const struct data_string *client_id,
05668 const struct data_string *iaaddr,
05669 u_int32_t *ia_na_id,
05670 struct packet *packet,
05671 char *reply_data,
05672 int *reply_ofs,
05673 int reply_len)
05674 {
05675 char tmp_addr[INET6_ADDRSTRLEN];
05676 struct option_state *host_opt_state;
05677 int len;
05678
05679 log_info("Client %s releases address %s, which is not leased to it.",
05680 print_hex_1(client_id->len, client_id->data, 60),
05681 inet_ntop(AF_INET6, iaaddr->data, tmp_addr, sizeof(tmp_addr)));
05682
05683
05684
05685
05686 host_opt_state = NULL;
05687 if (!option_state_allocate(&host_opt_state, MDL)) {
05688 log_error("ia_na_nomatch_release: out of memory "
05689 "allocating option_state.");
05690 goto exit;
05691 }
05692
05693 if (!set_status_code(STATUS_NoBinding,
05694 "Release for non-leased address.",
05695 host_opt_state)) {
05696 goto exit;
05697 }
05698
05699
05700
05701
05702 if (reply_len < (*reply_ofs + 16)) {
05703 log_error("ia_na_nomatch_release: "
05704 "out of space for reply packet.");
05705 goto exit;
05706 }
05707
05708
05709
05710
05711 len = store_options6(reply_data+(*reply_ofs)+16,
05712 reply_len-(*reply_ofs)-16,
05713 host_opt_state, packet,
05714 required_opts_STATUS_CODE, NULL);
05715
05716
05717
05718
05719
05720
05721
05722 putUShort((unsigned char *)reply_data+(*reply_ofs), D6O_IA_NA);
05723
05724 putUShort((unsigned char *)reply_data+(*reply_ofs)+2, len + 12);
05725
05726 memcpy(reply_data+(*reply_ofs)+4, ia_na_id, 4);
05727
05728 putULong((unsigned char *)reply_data+(*reply_ofs)+8, 0);
05729 putULong((unsigned char *)reply_data+(*reply_ofs)+12, 0);
05730
05731
05732
05733
05734 *reply_ofs += (len + 16);
05735
05736 exit:
05737 option_state_dereference(&host_opt_state, MDL);
05738 }
05739
05740 static void
05741 ia_pd_match_release(const struct data_string *client_id,
05742 const struct data_string *iapref,
05743 struct iasubopt *prefix)
05744 {
05745 char tmp_addr[INET6_ADDRSTRLEN];
05746
05747 log_info("Client %s releases prefix %s/%u",
05748 print_hex_1(client_id->len, client_id->data, 60),
05749 inet_ntop(AF_INET6, iapref->data + 9,
05750 tmp_addr, sizeof(tmp_addr)),
05751 (unsigned) getUChar(iapref->data + 8));
05752 if (prefix != NULL) {
05753 release_lease6(prefix->ipv6_pool, prefix);
05754 prefix->ia->cltt = cur_time;
05755 write_ia(prefix->ia);
05756 }
05757 }
05758
05759 static void
05760 ia_pd_nomatch_release(const struct data_string *client_id,
05761 const struct data_string *iapref,
05762 u_int32_t *ia_pd_id,
05763 struct packet *packet,
05764 char *reply_data,
05765 int *reply_ofs,
05766 int reply_len)
05767 {
05768 char tmp_addr[INET6_ADDRSTRLEN];
05769 struct option_state *host_opt_state;
05770 int len;
05771
05772 log_info("Client %s releases prefix %s/%u, which is not leased to it.",
05773 print_hex_1(client_id->len, client_id->data, 60),
05774 inet_ntop(AF_INET6, iapref->data + 9,
05775 tmp_addr, sizeof(tmp_addr)),
05776 (unsigned) getUChar(iapref->data + 8));
05777
05778
05779
05780
05781 host_opt_state = NULL;
05782 if (!option_state_allocate(&host_opt_state, MDL)) {
05783 log_error("ia_pd_nomatch_release: out of memory "
05784 "allocating option_state.");
05785 goto exit;
05786 }
05787
05788 if (!set_status_code(STATUS_NoBinding,
05789 "Release for non-leased prefix.",
05790 host_opt_state)) {
05791 goto exit;
05792 }
05793
05794
05795
05796
05797 if (reply_len < (*reply_ofs + 16)) {
05798 log_error("ia_pd_nomatch_release: "
05799 "out of space for reply packet.");
05800 goto exit;
05801 }
05802
05803
05804
05805
05806 len = store_options6(reply_data+(*reply_ofs)+16,
05807 reply_len-(*reply_ofs)-16,
05808 host_opt_state, packet,
05809 required_opts_STATUS_CODE, NULL);
05810
05811
05812
05813
05814
05815
05816
05817 putUShort((unsigned char *)reply_data+(*reply_ofs), D6O_IA_PD);
05818
05819 putUShort((unsigned char *)reply_data+(*reply_ofs)+2, len + 12);
05820
05821 memcpy(reply_data+(*reply_ofs)+4, ia_pd_id, 4);
05822
05823 putULong((unsigned char *)reply_data+(*reply_ofs)+8, 0);
05824 putULong((unsigned char *)reply_data+(*reply_ofs)+12, 0);
05825
05826
05827
05828
05829 *reply_ofs += (len + 16);
05830
05831 exit:
05832 option_state_dereference(&host_opt_state, MDL);
05833 }
05834
05835 static void
05836 iterate_over_ia_pd(struct data_string *reply_ret,
05837 struct packet *packet,
05838 const struct data_string *client_id,
05839 const struct data_string *server_id,
05840 const char *packet_type,
05841 void (*ia_pd_match)(),
05842 void (*ia_pd_nomatch)())
05843 {
05844 struct data_string reply_new;
05845 int reply_len;
05846 struct option_state *opt_state;
05847 struct host_decl *packet_host;
05848 struct option_cache *ia;
05849 struct option_cache *oc;
05850
05851 struct data_string cli_enc_opt_data;
05852 struct option_state *cli_enc_opt_state;
05853 struct host_decl *host;
05854 struct option_state *host_opt_state;
05855 struct data_string iaprefix;
05856 char reply_data[65536];
05857 int reply_ofs;
05858 struct iasubopt *prefix;
05859 struct ia_xx *existing_ia_pd;
05860 int i;
05861 struct data_string key;
05862 u_int32_t iaid;
05863
05864
05865
05866
05867 memset(&reply_new, 0, sizeof(reply_new));
05868 opt_state = NULL;
05869 memset(&cli_enc_opt_data, 0, sizeof(cli_enc_opt_data));
05870 cli_enc_opt_state = NULL;
05871 memset(&iaprefix, 0, sizeof(iaprefix));
05872 host_opt_state = NULL;
05873 prefix = NULL;
05874
05875
05876
05877
05878 reply_len = sizeof(reply_data) - reply_ret->len;
05879 reply_ofs = 0;
05880
05881
05882
05883
05884 packet_host = NULL;
05885 if (!find_hosts_by_uid(&packet_host,
05886 client_id->data, client_id->len, MDL)) {
05887 packet_host = NULL;
05888
05889
05890
05891
05892
05893
05894 if (!find_hosts_by_option(&packet_host,
05895 packet, packet->options, MDL)) {
05896 packet_host = NULL;
05897
05898 if (!find_hosts_by_duid_chaddr(&packet_host,
05899 client_id))
05900 packet_host = NULL;
05901 }
05902 }
05903
05904
05905
05906
05907 opt_state = NULL;
05908 if (!option_state_allocate(&opt_state, MDL)) {
05909 log_error("iterate_over_ia_pd: no memory for option_state.");
05910 goto exit;
05911 }
05912 execute_statements_in_scope(NULL, packet, NULL, NULL,
05913 packet->options, opt_state,
05914 &global_scope, root_group, NULL, NULL);
05915
05916
05917
05918
05919
05920 for (ia = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_PD);
05921 ia != NULL; ia = ia->next) {
05922
05923 if (!get_encapsulated_IA_state(&cli_enc_opt_state,
05924 &cli_enc_opt_data,
05925 packet, ia, IA_PD_OFFSET)) {
05926 goto exit;
05927 }
05928
05929 iaid = getULong(cli_enc_opt_data.data);
05930
05931 oc = lookup_option(&dhcpv6_universe, cli_enc_opt_state,
05932 D6O_IAPREFIX);
05933 if (oc == NULL) {
05934
05935 option_state_dereference(&cli_enc_opt_state, MDL);
05936 data_string_forget(&cli_enc_opt_data, MDL);
05937 continue;
05938 }
05939
05940 for (; oc != NULL; oc = oc->next) {
05941 memset(&iaprefix, 0, sizeof(iaprefix));
05942 if (!evaluate_option_cache(&iaprefix, packet, NULL, NULL,
05943 packet->options, NULL,
05944 &global_scope, oc, MDL)) {
05945 log_error("iterate_over_ia_pd: "
05946 "error evaluating IAPREFIX.");
05947 goto exit;
05948 }
05949
05950
05951
05952
05953
05954
05955
05956
05957
05958 host = NULL;
05959 if (!find_hosts_by_option(&host, packet,
05960 cli_enc_opt_state, MDL)) {
05961 if (packet_host != NULL) {
05962 host = packet_host;
05963 } else {
05964 host = NULL;
05965 }
05966 }
05967 while (host != NULL) {
05968 if (host->fixed_prefix != NULL) {
05969 struct iaddrcidrnetlist *l;
05970 int plen = (int) getUChar(iaprefix.data + 8);
05971
05972 for (l = host->fixed_prefix; l != NULL;
05973 l = l->next) {
05974 if (plen != l->cidrnet.bits)
05975 continue;
05976 if (memcmp(iaprefix.data + 9,
05977 l->cidrnet.lo_addr.iabuf,
05978 16) == 0)
05979 break;
05980 }
05981 if ((l != NULL) && (iaprefix.len >= 17))
05982 break;
05983 }
05984 host = host->n_ipaddr;
05985 }
05986
05987 if ((host == NULL) && (iaprefix.len >= IAPREFIX_OFFSET)) {
05988
05989
05990
05991 if (ia_make_key(&key, iaid,
05992 (char *)client_id->data,
05993 client_id->len,
05994 MDL) != ISC_R_SUCCESS) {
05995 log_fatal("iterate_over_ia_pd: no memory for "
05996 "key.");
05997 }
05998
05999 existing_ia_pd = NULL;
06000 if (ia_hash_lookup(&existing_ia_pd, ia_pd_active,
06001 (unsigned char *)key.data,
06002 key.len, MDL)) {
06003
06004
06005
06006 for (i = 0;
06007 i < existing_ia_pd->num_iasubopt;
06008 i++) {
06009 struct iasubopt *tmp;
06010 u_int8_t plen;
06011
06012 plen = getUChar(iaprefix.data + 8);
06013 tmp = existing_ia_pd->iasubopt[i];
06014 if ((tmp->plen == plen) &&
06015 (memcmp(&tmp->addr,
06016 iaprefix.data + 9,
06017 16) == 0)) {
06018 iasubopt_reference(&prefix,
06019 tmp, MDL);
06020 break;
06021 }
06022 }
06023 }
06024
06025 data_string_forget(&key, MDL);
06026 }
06027
06028 if ((host != NULL) || (prefix != NULL)) {
06029 ia_pd_match(client_id, &iaprefix, prefix);
06030 } else {
06031 ia_pd_nomatch(client_id, &iaprefix,
06032 (u_int32_t *)cli_enc_opt_data.data,
06033 packet, reply_data, &reply_ofs,
06034 reply_len - reply_ofs);
06035 }
06036
06037 if (prefix != NULL) {
06038 iasubopt_dereference(&prefix, MDL);
06039 }
06040
06041 data_string_forget(&iaprefix, MDL);
06042 }
06043
06044 option_state_dereference(&cli_enc_opt_state, MDL);
06045 data_string_forget(&cli_enc_opt_data, MDL);
06046 }
06047
06048
06049
06050
06051
06052 reply_new.len = reply_ret->len + reply_ofs;
06053 if (!buffer_allocate(&reply_new.buffer, reply_new.len, MDL)) {
06054 log_fatal("No memory to store reply.");
06055 }
06056 reply_new.data = reply_new.buffer->data;
06057 memcpy(reply_new.buffer->data,
06058 reply_ret->buffer->data, reply_ret->len);
06059 memcpy(reply_new.buffer->data + reply_ret->len,
06060 reply_data, reply_ofs);
06061 data_string_forget(reply_ret, MDL);
06062 data_string_copy(reply_ret, &reply_new, MDL);
06063 data_string_forget(&reply_new, MDL);
06064
06065 exit:
06066 if (prefix != NULL) {
06067 iasubopt_dereference(&prefix, MDL);
06068 }
06069 if (host_opt_state != NULL) {
06070 option_state_dereference(&host_opt_state, MDL);
06071 }
06072 if (iaprefix.buffer != NULL) {
06073 data_string_forget(&iaprefix, MDL);
06074 }
06075 if (cli_enc_opt_state != NULL) {
06076 option_state_dereference(&cli_enc_opt_state, MDL);
06077 }
06078 if (cli_enc_opt_data.buffer != NULL) {
06079 data_string_forget(&cli_enc_opt_data, MDL);
06080 }
06081 if (opt_state != NULL) {
06082 option_state_dereference(&opt_state, MDL);
06083 }
06084 }
06085
06086
06087
06088
06089
06090 static void
06091 dhcpv6_release(struct data_string *reply, struct packet *packet) {
06092 struct data_string client_id;
06093 struct data_string server_id;
06094
06095 TRACE(DHCPD_6_RELEASE_START());
06096
06097
06098
06099
06100 if (!valid_client_resp(packet, &client_id, &server_id)) {
06101 return;
06102 }
06103
06104
06105
06106
06107 iterate_over_ia_na(reply, packet, &client_id, &server_id, "Release",
06108 ia_na_match_release, ia_na_nomatch_release);
06109
06110
06111
06112
06113 iterate_over_ia_pd(reply, packet, &client_id, &server_id, "Release",
06114 ia_pd_match_release, ia_pd_nomatch_release);
06115
06116 data_string_forget(&server_id, MDL);
06117 data_string_forget(&client_id, MDL);
06118
06119 TRACE(DHCPD_6_RELEASE_DONE());
06120 }
06121
06122
06123
06124
06125
06126
06127 static void
06128 dhcpv6_information_request(struct data_string *reply, struct packet *packet) {
06129 struct data_string client_id;
06130 struct data_string server_id;
06131
06132 TRACE(DHCPD_6_INFORMATION_REQUEST_START());
06133
06134
06135
06136
06137 if (!valid_client_info_req(packet, &server_id)) {
06138 return;
06139 }
06140
06141
06142
06143
06144 memset(&client_id, 0, sizeof(client_id));
06145 if (get_client_id(packet, &client_id) != ISC_R_SUCCESS) {
06146 data_string_forget(&client_id, MDL);
06147 }
06148
06149
06150
06151
06152
06153
06154
06155 lease_to_client(reply, packet, &client_id,
06156 server_id.data != NULL ? &server_id : NULL);
06157
06158
06159
06160
06161 if (client_id.data != NULL) {
06162 data_string_forget(&client_id, MDL);
06163 }
06164 data_string_forget(&server_id, MDL);
06165
06166 TRACE(DHCPD_6_INFORMATION_REQUEST_DONE());
06167 }
06168
06169
06170
06171
06172
06173
06174
06175
06176
06177
06178 static void
06179 dhcpv6_relay_forw(struct data_string *reply_ret, struct packet *packet) {
06180 struct option_cache *oc;
06181 struct data_string enc_opt_data;
06182 struct packet *enc_packet;
06183 unsigned char msg_type;
06184 const struct dhcpv6_packet *msg;
06185 const struct dhcpv6_relay_packet *relay;
06186 struct data_string enc_reply;
06187 char link_addr[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
06188 char peer_addr[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
06189 struct data_string a_opt, packet_ero;
06190 struct option_state *opt_state;
06191 static char reply_data[65536];
06192 struct dhcpv6_relay_packet *reply;
06193 int reply_ofs;
06194
06195 TRACE(DHCPD_6_RELAY_FORW_START());
06196
06197
06198
06199
06200 opt_state = NULL;
06201 memset(&a_opt, 0, sizeof(a_opt));
06202 memset(&packet_ero, 0, sizeof(packet_ero));
06203 memset(&enc_reply, 0, sizeof(enc_reply));
06204 memset(&enc_opt_data, 0, sizeof(enc_opt_data));
06205 enc_packet = NULL;
06206
06207
06208
06209
06210 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_RELAY_MSG);
06211 if (oc == NULL) {
06212 inet_ntop(AF_INET6, &packet->dhcpv6_link_address,
06213 link_addr, sizeof(link_addr));
06214 inet_ntop(AF_INET6, &packet->dhcpv6_peer_address,
06215 peer_addr, sizeof(peer_addr));
06216 log_info("Relay-forward from %s with link address=%s and "
06217 "peer address=%s missing Relay Message option.",
06218 piaddr(packet->client_addr), link_addr, peer_addr);
06219 goto exit;
06220 }
06221
06222 if (!evaluate_option_cache(&enc_opt_data, NULL, NULL, NULL,
06223 NULL, NULL, &global_scope, oc, MDL)) {
06224 log_error("dhcpv6_forw_relay: error evaluating "
06225 "relayed message.");
06226 goto exit;
06227 }
06228
06229 if (!packet6_len_okay((char *)enc_opt_data.data, enc_opt_data.len)) {
06230 log_error("dhcpv6_forw_relay: encapsulated packet too short.");
06231 goto exit;
06232 }
06233
06234
06235
06236
06237 enc_packet = NULL;
06238 if (!packet_allocate(&enc_packet, MDL)) {
06239 log_error("dhcpv6_forw_relay: "
06240 "no memory for encapsulated packet.");
06241 goto exit;
06242 }
06243
06244 if (!option_state_allocate(&enc_packet->options, MDL)) {
06245 log_error("dhcpv6_forw_relay: "
06246 "no memory for encapsulated packet's options.");
06247 goto exit;
06248 }
06249
06250 enc_packet->client_port = packet->client_port;
06251 enc_packet->client_addr = packet->client_addr;
06252 interface_reference(&enc_packet->interface, packet->interface, MDL);
06253 enc_packet->dhcpv6_container_packet = packet;
06254
06255 msg_type = enc_opt_data.data[0];
06256 if ((msg_type == DHCPV6_RELAY_FORW) ||
06257 (msg_type == DHCPV6_RELAY_REPL)) {
06258 int relaylen = (int)(offsetof(struct dhcpv6_relay_packet, options));
06259 relay = (struct dhcpv6_relay_packet *)enc_opt_data.data;
06260 enc_packet->dhcpv6_msg_type = relay->msg_type;
06261
06262
06263 enc_packet->dhcpv6_hop_count = relay->hop_count;
06264 memcpy(&enc_packet->dhcpv6_link_address,
06265 relay->link_address, sizeof(relay->link_address));
06266 memcpy(&enc_packet->dhcpv6_peer_address,
06267 relay->peer_address, sizeof(relay->peer_address));
06268
06269 if (!parse_option_buffer(enc_packet->options,
06270 relay->options,
06271 enc_opt_data.len - relaylen,
06272 &dhcpv6_universe)) {
06273
06274
06275 goto exit;
06276 }
06277 } else {
06278 int msglen = (int)(offsetof(struct dhcpv6_packet, options));
06279 msg = (struct dhcpv6_packet *)enc_opt_data.data;
06280 enc_packet->dhcpv6_msg_type = msg->msg_type;
06281
06282
06283 memcpy(enc_packet->dhcpv6_transaction_id,
06284 msg->transaction_id,
06285 sizeof(enc_packet->dhcpv6_transaction_id));
06286
06287 if (!parse_option_buffer(enc_packet->options,
06288 msg->options,
06289 enc_opt_data.len - msglen,
06290 &dhcpv6_universe)) {
06291
06292
06293 goto exit;
06294 }
06295 }
06296
06297
06298
06299
06300
06301 build_dhcpv6_reply(&enc_reply, enc_packet);
06302
06303
06304
06305
06306
06307 if (enc_reply.data == NULL) {
06308 goto exit;
06309 }
06310
06311
06312
06313
06314
06315 reply = (struct dhcpv6_relay_packet *)reply_data;
06316 reply->msg_type = DHCPV6_RELAY_REPL;
06317 reply->hop_count = packet->dhcpv6_hop_count;
06318 memcpy(reply->link_address, &packet->dhcpv6_link_address,
06319 sizeof(reply->link_address));
06320 memcpy(reply->peer_address, &packet->dhcpv6_peer_address,
06321 sizeof(reply->peer_address));
06322 reply_ofs = (int)(offsetof(struct dhcpv6_relay_packet, options));
06323
06324
06325
06326
06327 opt_state = NULL;
06328 if (!option_state_allocate(&opt_state, MDL)) {
06329 log_error("dhcpv6_relay_forw: no memory for option state.");
06330 goto exit;
06331 }
06332
06333
06334
06335
06336 oc = lookup_option(&dhcpv6_universe, packet->options,
06337 D6O_INTERFACE_ID);
06338 if (oc != NULL) {
06339 if (!evaluate_option_cache(&a_opt, packet,
06340 NULL, NULL,
06341 packet->options, NULL,
06342 &global_scope, oc, MDL)) {
06343 log_error("dhcpv6_relay_forw: error evaluating "
06344 "Interface ID.");
06345 goto exit;
06346 }
06347 if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL,
06348 (unsigned char *)a_opt.data,
06349 a_opt.len,
06350 D6O_INTERFACE_ID, 0)) {
06351 log_error("dhcpv6_relay_forw: error saving "
06352 "Interface ID.");
06353 goto exit;
06354 }
06355 data_string_forget(&a_opt, MDL);
06356 }
06357
06358
06359
06360
06361 if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL,
06362 (unsigned char *)enc_reply.data,
06363 enc_reply.len,
06364 D6O_RELAY_MSG, 0)) {
06365 log_error("dhcpv6_relay_forw: error saving Relay MSG.");
06366 goto exit;
06367 }
06368
06369
06370
06371
06372 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_ERO);
06373 if (oc != NULL) {
06374 unsigned req;
06375 int i;
06376
06377 if (!evaluate_option_cache(&packet_ero, packet,
06378 NULL, NULL,
06379 packet->options, NULL,
06380 &global_scope, oc, MDL) ||
06381 (packet_ero.len & 1)) {
06382 log_error("dhcpv6_relay_forw: error evaluating ERO.");
06383 goto exit;
06384 }
06385
06386
06387 for (i = 0; i < packet_ero.len; i += 2) {
06388 req = getUShort(packet_ero.data + i);
06389
06390 oc = lookup_option(&dhcpv6_universe, opt_state, req);
06391 if (oc != NULL)
06392 continue;
06393
06394 oc = lookup_option(&dhcpv6_universe,
06395 packet->options,
06396 req);
06397 if (oc == NULL)
06398 continue;
06399 if (!evaluate_option_cache(&a_opt, packet,
06400 NULL, NULL,
06401 packet->options, NULL,
06402 &global_scope, oc, MDL)) {
06403 log_error("dhcpv6_relay_forw: error "
06404 "evaluating option %u.", req);
06405 goto exit;
06406 }
06407 if (!save_option_buffer(&dhcpv6_universe,
06408 opt_state,
06409 NULL,
06410 (unsigned char *)a_opt.data,
06411 a_opt.len,
06412 req,
06413 0)) {
06414 log_error("dhcpv6_relay_forw: error saving "
06415 "option %u.", req);
06416 goto exit;
06417 }
06418 data_string_forget(&a_opt, MDL);
06419 }
06420 }
06421
06422 reply_ofs += store_options6(reply_data + reply_ofs,
06423 sizeof(reply_data) - reply_ofs,
06424 opt_state, packet,
06425 required_opts_agent, &packet_ero);
06426
06427
06428
06429
06430 reply_ret->len = reply_ofs;
06431 reply_ret->buffer = NULL;
06432 if (!buffer_allocate(&reply_ret->buffer, reply_ret->len, MDL)) {
06433 log_fatal("No memory to store reply.");
06434 }
06435 reply_ret->data = reply_ret->buffer->data;
06436 memcpy(reply_ret->buffer->data, reply_data, reply_ofs);
06437
06438 exit:
06439 if (opt_state != NULL)
06440 option_state_dereference(&opt_state, MDL);
06441 if (a_opt.data != NULL) {
06442 data_string_forget(&a_opt, MDL);
06443 }
06444 if (packet_ero.data != NULL) {
06445 data_string_forget(&packet_ero, MDL);
06446 }
06447 if (enc_reply.data != NULL) {
06448 data_string_forget(&enc_reply, MDL);
06449 }
06450 if (enc_opt_data.data != NULL) {
06451 data_string_forget(&enc_opt_data, MDL);
06452 }
06453 if (enc_packet != NULL) {
06454 packet_dereference(&enc_packet, MDL);
06455 }
06456
06457 TRACE(DHCPD_6_RELAY_FORW_DONE());
06458 }
06459
06460 static void
06461 dhcpv6_discard(struct packet *packet) {
06462
06463
06464
06465 log_debug("Discarding %s from %s; message type not handled by server",
06466 dhcpv6_type_names[packet->dhcpv6_msg_type],
06467 piaddr(packet->client_addr));
06468 }
06469
06470 static void
06471 build_dhcpv6_reply(struct data_string *reply, struct packet *packet) {
06472 memset(reply, 0, sizeof(*reply));
06473
06474
06475
06476
06477
06478
06479
06480
06481
06482 switch (packet->dhcpv6_msg_type) {
06483 case DHCPV6_SOLICIT:
06484 classify_client(packet);
06485 dhcpv6_solicit(reply, packet);
06486 break;
06487 case DHCPV6_ADVERTISE:
06488 dhcpv6_discard(packet);
06489 break;
06490 case DHCPV6_REQUEST:
06491 classify_client(packet);
06492 dhcpv6_request(reply, packet);
06493 break;
06494 case DHCPV6_CONFIRM:
06495 classify_client(packet);
06496 dhcpv6_confirm(reply, packet);
06497 break;
06498 case DHCPV6_RENEW:
06499 classify_client(packet);
06500 dhcpv6_renew(reply, packet);
06501 break;
06502 case DHCPV6_REBIND:
06503 classify_client(packet);
06504 dhcpv6_rebind(reply, packet);
06505 break;
06506 case DHCPV6_REPLY:
06507 dhcpv6_discard(packet);
06508 break;
06509 case DHCPV6_RELEASE:
06510 classify_client(packet);
06511 dhcpv6_release(reply, packet);
06512 break;
06513 case DHCPV6_DECLINE:
06514 classify_client(packet);
06515 dhcpv6_decline(reply, packet);
06516 break;
06517 case DHCPV6_RECONFIGURE:
06518 dhcpv6_discard(packet);
06519 break;
06520 case DHCPV6_INFORMATION_REQUEST:
06521 classify_client(packet);
06522 dhcpv6_information_request(reply, packet);
06523 break;
06524 case DHCPV6_RELAY_FORW:
06525 dhcpv6_relay_forw(reply, packet);
06526 break;
06527 case DHCPV6_RELAY_REPL:
06528 dhcpv6_discard(packet);
06529 break;
06530 case DHCPV6_LEASEQUERY:
06531 classify_client(packet);
06532 dhcpv6_leasequery(reply, packet);
06533 break;
06534 case DHCPV6_LEASEQUERY_REPLY:
06535 dhcpv6_discard(packet);
06536 break;
06537 default:
06538
06539
06540 log_info("Discarding unknown DHCPv6 message type %d "
06541 "from %s", packet->dhcpv6_msg_type,
06542 piaddr(packet->client_addr));
06543 }
06544 }
06545
06546 static void
06547 log_packet_in(const struct packet *packet) {
06548 struct data_string s;
06549 u_int32_t tid;
06550 char tmp_addr[INET6_ADDRSTRLEN];
06551 const void *addr;
06552
06553 memset(&s, 0, sizeof(s));
06554
06555 if (packet->dhcpv6_msg_type < dhcpv6_type_name_max) {
06556 data_string_sprintfa(&s, "%s message from %s port %d",
06557 dhcpv6_type_names[packet->dhcpv6_msg_type],
06558 piaddr(packet->client_addr),
06559 ntohs(packet->client_port));
06560 } else {
06561 data_string_sprintfa(&s,
06562 "Unknown message type %d from %s port %d",
06563 packet->dhcpv6_msg_type,
06564 piaddr(packet->client_addr),
06565 ntohs(packet->client_port));
06566 }
06567 if ((packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) ||
06568 (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL)) {
06569 addr = &packet->dhcpv6_link_address;
06570 data_string_sprintfa(&s, ", link address %s",
06571 inet_ntop(AF_INET6, addr,
06572 tmp_addr, sizeof(tmp_addr)));
06573 addr = &packet->dhcpv6_peer_address;
06574 data_string_sprintfa(&s, ", peer address %s",
06575 inet_ntop(AF_INET6, addr,
06576 tmp_addr, sizeof(tmp_addr)));
06577 } else {
06578 tid = 0;
06579 memcpy(((char *)&tid)+1, packet->dhcpv6_transaction_id, 3);
06580 data_string_sprintfa(&s, ", transaction ID 0x%06X", tid);
06581
06582
06583
06584
06585
06586
06587
06588
06589
06590
06591
06592
06593
06594
06595
06596
06597
06598
06599 }
06600 log_info("%s", s.data);
06601
06602 data_string_forget(&s, MDL);
06603 }
06604
06605 void
06606 dhcpv6(struct packet *packet) {
06607 struct data_string reply;
06608 struct sockaddr_in6 to_addr;
06609 int send_ret;
06610
06611
06612
06613
06614 log_packet_in(packet);
06615
06616
06617
06618
06619 build_dhcpv6_reply(&reply, packet);
06620
06621 if (reply.data != NULL) {
06622
06623
06624
06625 memset(&to_addr, 0, sizeof(to_addr));
06626 to_addr.sin6_family = AF_INET6;
06627 if ((packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) ||
06628 (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL)) {
06629 to_addr.sin6_port = local_port;
06630 } else {
06631 to_addr.sin6_port = remote_port;
06632 }
06633
06634 #if defined (REPLY_TO_SOURCE_PORT)
06635
06636
06637
06638
06639
06640
06641
06642 to_addr.sin6_port = packet->client_port;
06643 #endif
06644
06645 memcpy(&to_addr.sin6_addr, packet->client_addr.iabuf,
06646 sizeof(to_addr.sin6_addr));
06647
06648 log_info("Sending %s to %s port %d",
06649 dhcpv6_type_names[reply.data[0]],
06650 piaddr(packet->client_addr),
06651 ntohs(to_addr.sin6_port));
06652
06653 send_ret = send_packet6(packet->interface,
06654 reply.data, reply.len, &to_addr);
06655 if (send_ret != reply.len) {
06656 log_error("dhcpv6: send_packet6() sent %d of %d bytes",
06657 send_ret, reply.len);
06658 }
06659 data_string_forget(&reply, MDL);
06660 }
06661 }
06662
06663 static void
06664 seek_shared_host(struct host_decl **hp, struct shared_network *shared) {
06665 struct host_decl *nofixed = NULL;
06666 struct host_decl *seek, *hold = NULL;
06667
06668
06669
06670
06671
06672
06673 host_reference(&hold, *hp, MDL);
06674 host_dereference(hp, MDL);
06675 seek = hold;
06676 while (seek != NULL) {
06677 if (seek->fixed_addr == NULL)
06678 nofixed = seek;
06679 else if (fixed_matches_shared(seek, shared))
06680 break;
06681
06682 seek = seek->n_ipaddr;
06683 }
06684
06685 if ((seek == NULL) && (nofixed != NULL))
06686 seek = nofixed;
06687
06688 if (seek != NULL)
06689 host_reference(hp, seek, MDL);
06690 }
06691
06692 static isc_boolean_t
06693 fixed_matches_shared(struct host_decl *host, struct shared_network *shared) {
06694 struct subnet *subnet;
06695 struct data_string addr;
06696 isc_boolean_t matched;
06697 struct iaddr fixed;
06698
06699 if (host->fixed_addr == NULL)
06700 return ISC_FALSE;
06701
06702 memset(&addr, 0, sizeof(addr));
06703 if (!evaluate_option_cache(&addr, NULL, NULL, NULL, NULL, NULL,
06704 &global_scope, host->fixed_addr, MDL))
06705 return ISC_FALSE;
06706
06707 if (addr.len < 16) {
06708 data_string_forget(&addr, MDL);
06709 return ISC_FALSE;
06710 }
06711
06712 fixed.len = 16;
06713 memcpy(fixed.iabuf, addr.data, 16);
06714
06715 matched = ISC_FALSE;
06716 for (subnet = shared->subnets ; subnet != NULL ;
06717 subnet = subnet->next_sibling) {
06718 if (addr_eq(subnet_number(fixed, subnet->netmask),
06719 subnet->net)) {
06720 matched = ISC_TRUE;
06721 break;
06722 }
06723 }
06724
06725 data_string_forget(&addr, MDL);
06726 return matched;
06727 }
06728
06729
06730
06731
06732
06733
06734 static int
06735 find_hosts_by_duid_chaddr(struct host_decl **host,
06736 const struct data_string *client_id) {
06737 static int once_htype;
06738 int htype, hlen;
06739 const unsigned char *chaddr;
06740
06741
06742
06743
06744
06745 if (client_id->len < 4)
06746 return 0;
06747
06748
06749
06750
06751
06752 htype = getUShort(client_id->data + 2);
06753 hlen = 0;
06754 chaddr = NULL;
06755
06756
06757 switch(getUShort(client_id->data)) {
06758 case DUID_LLT:
06759 if (client_id->len > 8) {
06760 hlen = client_id->len - 8;
06761 chaddr = client_id->data + 8;
06762 }
06763 break;
06764
06765 case DUID_LL:
06766
06767
06768
06769
06770 hlen = client_id->len - 4;
06771 chaddr = client_id->data + 4;
06772 break;
06773
06774 default:
06775 break;
06776 }
06777
06778 if ((hlen == 0) || (hlen > HARDWARE_ADDR_LEN))
06779 return 0;
06780
06781
06782
06783
06784
06785
06786
06787
06788
06789
06790
06791 if ((htype & 0xFF00) && !once_htype) {
06792 once_htype = 1;
06793 log_error("Attention: At least one client advertises a "
06794 "hardware type of %d, which exceeds the software "
06795 "limitation of 255.", htype);
06796 }
06797
06798 return find_hosts_by_haddr(host, htype, chaddr, hlen, MDL);
06799 }
06800
06801 #endif
06802