Annotation of embedaddon/dhcp/server/dhcpv6.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2006-2011 by Internet Systems Consortium, Inc. ("ISC")
! 3: *
! 4: * Permission to use, copy, modify, and distribute this software for any
! 5: * purpose with or without fee is hereby granted, provided that the above
! 6: * copyright notice and this permission notice appear in all copies.
! 7: *
! 8: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
! 9: * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
! 10: * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
! 11: * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
! 12: * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
! 13: * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
! 14: * PERFORMANCE OF THIS SOFTWARE.
! 15: */
! 16:
! 17: #include "dhcpd.h"
! 18:
! 19: #ifdef DHCPv6
! 20:
! 21: /*
! 22: * We use print_hex_1() to output DUID values. We could actually output
! 23: * the DUID with more information... MAC address if using type 1 or 3,
! 24: * and so on. However, RFC 3315 contains Grave Warnings against actually
! 25: * attempting to understand a DUID.
! 26: */
! 27:
! 28: /*
! 29: * TODO: gettext() or other method of localization for the messages
! 30: * for status codes (and probably for log formats eventually)
! 31: * TODO: refactoring (simplify, simplify, simplify)
! 32: * TODO: support multiple shared_networks on each interface (this
! 33: * will allow the server to issue multiple IPv6 addresses to
! 34: * a single interface)
! 35: */
! 36:
! 37: /*
! 38: * DHCPv6 Reply workflow assist. A Reply packet is built by various
! 39: * different functions; this gives us one location where we keep state
! 40: * regarding a reply.
! 41: */
! 42: struct reply_state {
! 43: /* root level persistent state */
! 44: struct shared_network *shared;
! 45: struct host_decl *host;
! 46: struct subnet *subnet; /* Used to match fixed-addrs to subnet scopes. */
! 47: struct option_state *opt_state;
! 48: struct packet *packet;
! 49: struct data_string client_id;
! 50:
! 51: /* IA level persistent state */
! 52: unsigned ia_count;
! 53: unsigned pd_count;
! 54: unsigned client_resources;
! 55: isc_boolean_t resources_included;
! 56: isc_boolean_t static_lease;
! 57: unsigned static_prefixes;
! 58: struct ia_xx *ia;
! 59: struct ia_xx *old_ia;
! 60: struct option_state *reply_ia;
! 61: struct data_string fixed;
! 62:
! 63: /* IAADDR/PREFIX level persistent state */
! 64: struct iasubopt *lease;
! 65:
! 66: /*
! 67: * "t1", "t2", preferred, and valid lifetimes records for calculating
! 68: * t1 and t2 (min/max).
! 69: */
! 70: u_int32_t renew, rebind, prefer, valid;
! 71:
! 72: /* Client-requested valid and preferred lifetimes. */
! 73: u_int32_t client_valid, client_prefer;
! 74:
! 75: /* Chosen values to transmit for valid and preferred lifetimes. */
! 76: u_int32_t send_valid, send_prefer;
! 77:
! 78: /* Preferred prefix length (-1 is any). */
! 79: int preflen;
! 80:
! 81: /* Index into the data field that has been consumed. */
! 82: unsigned cursor;
! 83:
! 84: union reply_buffer {
! 85: unsigned char data[65536];
! 86: struct dhcpv6_packet reply;
! 87: } buf;
! 88: };
! 89:
! 90: /*
! 91: * Prototypes local to this file.
! 92: */
! 93: static int get_encapsulated_IA_state(struct option_state **enc_opt_state,
! 94: struct data_string *enc_opt_data,
! 95: struct packet *packet,
! 96: struct option_cache *oc,
! 97: int offset);
! 98: static void build_dhcpv6_reply(struct data_string *, struct packet *);
! 99: static isc_result_t shared_network_from_packet6(struct shared_network **shared,
! 100: struct packet *packet);
! 101: static void seek_shared_host(struct host_decl **hp,
! 102: struct shared_network *shared);
! 103: static isc_boolean_t fixed_matches_shared(struct host_decl *host,
! 104: struct shared_network *shared);
! 105: static isc_result_t reply_process_ia_na(struct reply_state *reply,
! 106: struct option_cache *ia);
! 107: static isc_result_t reply_process_ia_ta(struct reply_state *reply,
! 108: struct option_cache *ia);
! 109: static isc_result_t reply_process_addr(struct reply_state *reply,
! 110: struct option_cache *addr);
! 111: static isc_boolean_t address_is_owned(struct reply_state *reply,
! 112: struct iaddr *addr);
! 113: static isc_boolean_t temporary_is_available(struct reply_state *reply,
! 114: struct iaddr *addr);
! 115: static isc_result_t find_client_temporaries(struct reply_state *reply);
! 116: static isc_result_t reply_process_try_addr(struct reply_state *reply,
! 117: struct iaddr *addr);
! 118: static isc_result_t find_client_address(struct reply_state *reply);
! 119: static isc_result_t reply_process_is_addressed(struct reply_state *reply,
! 120: struct binding_scope **scope,
! 121: struct group *group);
! 122: static isc_result_t reply_process_send_addr(struct reply_state *reply,
! 123: struct iaddr *addr);
! 124: static struct iasubopt *lease_compare(struct iasubopt *alpha,
! 125: struct iasubopt *beta);
! 126: static isc_result_t reply_process_ia_pd(struct reply_state *reply,
! 127: struct option_cache *ia_pd);
! 128: static isc_result_t reply_process_prefix(struct reply_state *reply,
! 129: struct option_cache *pref);
! 130: static isc_boolean_t prefix_is_owned(struct reply_state *reply,
! 131: struct iaddrcidrnet *pref);
! 132: static isc_result_t find_client_prefix(struct reply_state *reply);
! 133: static isc_result_t reply_process_try_prefix(struct reply_state *reply,
! 134: struct iaddrcidrnet *pref);
! 135: static isc_result_t reply_process_is_prefixed(struct reply_state *reply,
! 136: struct binding_scope **scope,
! 137: struct group *group);
! 138: static isc_result_t reply_process_send_prefix(struct reply_state *reply,
! 139: struct iaddrcidrnet *pref);
! 140: static struct iasubopt *prefix_compare(struct reply_state *reply,
! 141: struct iasubopt *alpha,
! 142: struct iasubopt *beta);
! 143:
! 144: /*
! 145: * This function returns the time since DUID time start for the
! 146: * given time_t value.
! 147: */
! 148: static u_int32_t
! 149: duid_time(time_t when) {
! 150: /*
! 151: * This time is modulo 2^32.
! 152: */
! 153: while ((when - DUID_TIME_EPOCH) > 4294967295u) {
! 154: /* use 2^31 to avoid spurious compiler warnings */
! 155: when -= 2147483648u;
! 156: when -= 2147483648u;
! 157: }
! 158:
! 159: return when - DUID_TIME_EPOCH;
! 160: }
! 161:
! 162:
! 163: /*
! 164: * Server DUID.
! 165: *
! 166: * This must remain the same for the lifetime of this server, because
! 167: * clients return the server DUID that we sent them in Request packets.
! 168: *
! 169: * We pick the server DUID like this:
! 170: *
! 171: * 1. Check dhcpd.conf - any value the administrator has configured
! 172: * overrides any possible values.
! 173: * 2. Check the leases.txt - we want to use the previous value if
! 174: * possible.
! 175: * 3. Check if dhcpd.conf specifies a type of server DUID to use,
! 176: * and generate that type.
! 177: * 4. Generate a type 1 (time + hardware address) DUID.
! 178: */
! 179: static struct data_string server_duid;
! 180:
! 181: /*
! 182: * Check if the server_duid has been set.
! 183: */
! 184: isc_boolean_t
! 185: server_duid_isset(void) {
! 186: return (server_duid.data != NULL);
! 187: }
! 188:
! 189: /*
! 190: * Return the server_duid.
! 191: */
! 192: void
! 193: copy_server_duid(struct data_string *ds, const char *file, int line) {
! 194: data_string_copy(ds, &server_duid, file, line);
! 195: }
! 196:
! 197: /*
! 198: * Set the server DUID to a specified value. This is used when
! 199: * the server DUID is stored in persistent memory (basically the
! 200: * leases.txt file).
! 201: */
! 202: void
! 203: set_server_duid(struct data_string *new_duid) {
! 204: /* INSIST(new_duid != NULL); */
! 205: /* INSIST(new_duid->data != NULL); */
! 206:
! 207: if (server_duid_isset()) {
! 208: data_string_forget(&server_duid, MDL);
! 209: }
! 210: data_string_copy(&server_duid, new_duid, MDL);
! 211: }
! 212:
! 213:
! 214: /*
! 215: * Set the server DUID based on the D6O_SERVERID option. This handles
! 216: * the case where the administrator explicitly put it in the dhcpd.conf
! 217: * file.
! 218: */
! 219: isc_result_t
! 220: set_server_duid_from_option(void) {
! 221: struct option_state *opt_state;
! 222: struct option_cache *oc;
! 223: struct data_string option_duid;
! 224: isc_result_t ret_val;
! 225:
! 226: opt_state = NULL;
! 227: if (!option_state_allocate(&opt_state, MDL)) {
! 228: log_fatal("No memory for server DUID.");
! 229: }
! 230:
! 231: execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL,
! 232: opt_state, &global_scope, root_group, NULL);
! 233:
! 234: oc = lookup_option(&dhcpv6_universe, opt_state, D6O_SERVERID);
! 235: if (oc == NULL) {
! 236: ret_val = ISC_R_NOTFOUND;
! 237: } else {
! 238: memset(&option_duid, 0, sizeof(option_duid));
! 239: if (!evaluate_option_cache(&option_duid, NULL, NULL, NULL,
! 240: opt_state, NULL, &global_scope,
! 241: oc, MDL)) {
! 242: ret_val = ISC_R_UNEXPECTED;
! 243: } else {
! 244: set_server_duid(&option_duid);
! 245: data_string_forget(&option_duid, MDL);
! 246: ret_val = ISC_R_SUCCESS;
! 247: }
! 248: }
! 249:
! 250: option_state_dereference(&opt_state, MDL);
! 251:
! 252: return ret_val;
! 253: }
! 254:
! 255: /*
! 256: * DUID layout, as defined in RFC 3315, section 9.
! 257: *
! 258: * We support type 1 (hardware address plus time) and type 3 (hardware
! 259: * address).
! 260: *
! 261: * We can support type 2 for specific vendors in the future, if they
! 262: * publish the specification. And of course there may be additional
! 263: * types later.
! 264: */
! 265: static int server_duid_type = DUID_LLT;
! 266:
! 267: /*
! 268: * Set the DUID type.
! 269: */
! 270: void
! 271: set_server_duid_type(int type) {
! 272: server_duid_type = type;
! 273: }
! 274:
! 275: /*
! 276: * Generate a new server DUID. This is done if there was no DUID in
! 277: * the leases.txt or in the dhcpd.conf file.
! 278: */
! 279: isc_result_t
! 280: generate_new_server_duid(void) {
! 281: struct interface_info *p;
! 282: u_int32_t time_val;
! 283: struct data_string generated_duid;
! 284:
! 285: /*
! 286: * Verify we have a type that we support.
! 287: */
! 288: if ((server_duid_type != DUID_LL) && (server_duid_type != DUID_LLT)) {
! 289: log_error("Invalid DUID type %d specified, "
! 290: "only LL and LLT types supported", server_duid_type);
! 291: return ISC_R_INVALIDARG;
! 292: }
! 293:
! 294: /*
! 295: * Find an interface with a hardware address.
! 296: * Any will do. :)
! 297: */
! 298: for (p = interfaces; p != NULL; p = p->next) {
! 299: if (p->hw_address.hlen > 0) {
! 300: break;
! 301: }
! 302: }
! 303: if (p == NULL) {
! 304: return ISC_R_UNEXPECTED;
! 305: }
! 306:
! 307: /*
! 308: * Build our DUID.
! 309: */
! 310: memset(&generated_duid, 0, sizeof(generated_duid));
! 311: if (server_duid_type == DUID_LLT) {
! 312: time_val = duid_time(time(NULL));
! 313: generated_duid.len = 8 + p->hw_address.hlen - 1;
! 314: if (!buffer_allocate(&generated_duid.buffer,
! 315: generated_duid.len, MDL)) {
! 316: log_fatal("No memory for server DUID.");
! 317: }
! 318: generated_duid.data = generated_duid.buffer->data;
! 319: putUShort(generated_duid.buffer->data, DUID_LLT);
! 320: putUShort(generated_duid.buffer->data + 2,
! 321: p->hw_address.hbuf[0]);
! 322: putULong(generated_duid.buffer->data + 4, time_val);
! 323: memcpy(generated_duid.buffer->data + 8,
! 324: p->hw_address.hbuf+1, p->hw_address.hlen-1);
! 325: } else if (server_duid_type == DUID_LL) {
! 326: generated_duid.len = 4 + p->hw_address.hlen - 1;
! 327: if (!buffer_allocate(&generated_duid.buffer,
! 328: generated_duid.len, MDL)) {
! 329: log_fatal("No memory for server DUID.");
! 330: }
! 331: generated_duid.data = generated_duid.buffer->data;
! 332: putUShort(generated_duid.buffer->data, DUID_LL);
! 333: putUShort(generated_duid.buffer->data + 2,
! 334: p->hw_address.hbuf[0]);
! 335: memcpy(generated_duid.buffer->data + 4,
! 336: p->hw_address.hbuf+1, p->hw_address.hlen-1);
! 337: } else {
! 338: log_fatal("Unsupported server DUID type %d.", server_duid_type);
! 339: }
! 340:
! 341: set_server_duid(&generated_duid);
! 342: data_string_forget(&generated_duid, MDL);
! 343:
! 344: return ISC_R_SUCCESS;
! 345: }
! 346:
! 347: /*
! 348: * Get the client identifier from the packet.
! 349: */
! 350: isc_result_t
! 351: get_client_id(struct packet *packet, struct data_string *client_id) {
! 352: struct option_cache *oc;
! 353:
! 354: /*
! 355: * Verify our client_id structure is empty.
! 356: */
! 357: if ((client_id->data != NULL) || (client_id->len != 0)) {
! 358: return ISC_R_INVALIDARG;
! 359: }
! 360:
! 361: oc = lookup_option(&dhcpv6_universe, packet->options, D6O_CLIENTID);
! 362: if (oc == NULL) {
! 363: return ISC_R_NOTFOUND;
! 364: }
! 365:
! 366: if (!evaluate_option_cache(client_id, packet, NULL, NULL,
! 367: packet->options, NULL,
! 368: &global_scope, oc, MDL)) {
! 369: return ISC_R_FAILURE;
! 370: }
! 371:
! 372: return ISC_R_SUCCESS;
! 373: }
! 374:
! 375: /*
! 376: * Message validation, defined in RFC 3315, sections 15.2, 15.5, 15.7:
! 377: *
! 378: * Servers MUST discard any Solicit messages that do not include a
! 379: * Client Identifier option or that do include a Server Identifier
! 380: * option.
! 381: */
! 382: int
! 383: valid_client_msg(struct packet *packet, struct data_string *client_id) {
! 384: int ret_val;
! 385: struct option_cache *oc;
! 386: struct data_string data;
! 387:
! 388: ret_val = 0;
! 389: memset(client_id, 0, sizeof(*client_id));
! 390: memset(&data, 0, sizeof(data));
! 391:
! 392: switch (get_client_id(packet, client_id)) {
! 393: case ISC_R_SUCCESS:
! 394: break;
! 395: case ISC_R_NOTFOUND:
! 396: log_debug("Discarding %s from %s; "
! 397: "client identifier missing",
! 398: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 399: piaddr(packet->client_addr));
! 400: goto exit;
! 401: default:
! 402: log_error("Error processing %s from %s; "
! 403: "unable to evaluate Client Identifier",
! 404: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 405: piaddr(packet->client_addr));
! 406: goto exit;
! 407: }
! 408:
! 409: /*
! 410: * Required by RFC 3315, section 15.
! 411: */
! 412: if (packet->unicast) {
! 413: log_debug("Discarding %s from %s; packet sent unicast "
! 414: "(CLIENTID %s)",
! 415: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 416: piaddr(packet->client_addr),
! 417: print_hex_1(client_id->len, client_id->data, 60));
! 418: goto exit;
! 419: }
! 420:
! 421:
! 422: oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID);
! 423: if (oc != NULL) {
! 424: if (evaluate_option_cache(&data, packet, NULL, NULL,
! 425: packet->options, NULL,
! 426: &global_scope, oc, MDL)) {
! 427: log_debug("Discarding %s from %s; "
! 428: "server identifier found "
! 429: "(CLIENTID %s, SERVERID %s)",
! 430: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 431: piaddr(packet->client_addr),
! 432: print_hex_1(client_id->len,
! 433: client_id->data, 60),
! 434: print_hex_2(data.len,
! 435: data.data, 60));
! 436: } else {
! 437: log_debug("Discarding %s from %s; "
! 438: "server identifier found "
! 439: "(CLIENTID %s)",
! 440: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 441: print_hex_1(client_id->len,
! 442: client_id->data, 60),
! 443: piaddr(packet->client_addr));
! 444: }
! 445: goto exit;
! 446: }
! 447:
! 448: /* looks good */
! 449: ret_val = 1;
! 450:
! 451: exit:
! 452: if (data.len > 0) {
! 453: data_string_forget(&data, MDL);
! 454: }
! 455: if (!ret_val) {
! 456: if (client_id->len > 0) {
! 457: data_string_forget(client_id, MDL);
! 458: }
! 459: }
! 460: return ret_val;
! 461: }
! 462:
! 463: /*
! 464: * Response validation, defined in RFC 3315, sections 15.4, 15.6, 15.8,
! 465: * 15.9 (slightly different wording, but same meaning):
! 466: *
! 467: * Servers MUST discard any received Request message that meet any of
! 468: * the following conditions:
! 469: *
! 470: * - the message does not include a Server Identifier option.
! 471: * - the contents of the Server Identifier option do not match the
! 472: * server's DUID.
! 473: * - the message does not include a Client Identifier option.
! 474: */
! 475: int
! 476: valid_client_resp(struct packet *packet,
! 477: struct data_string *client_id,
! 478: struct data_string *server_id)
! 479: {
! 480: int ret_val;
! 481: struct option_cache *oc;
! 482:
! 483: /* INSIST((duid.data != NULL) && (duid.len > 0)); */
! 484:
! 485: ret_val = 0;
! 486: memset(client_id, 0, sizeof(*client_id));
! 487: memset(server_id, 0, sizeof(*server_id));
! 488:
! 489: switch (get_client_id(packet, client_id)) {
! 490: case ISC_R_SUCCESS:
! 491: break;
! 492: case ISC_R_NOTFOUND:
! 493: log_debug("Discarding %s from %s; "
! 494: "client identifier missing",
! 495: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 496: piaddr(packet->client_addr));
! 497: goto exit;
! 498: default:
! 499: log_error("Error processing %s from %s; "
! 500: "unable to evaluate Client Identifier",
! 501: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 502: piaddr(packet->client_addr));
! 503: goto exit;
! 504: }
! 505:
! 506: oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID);
! 507: if (oc == NULL) {
! 508: log_debug("Discarding %s from %s: "
! 509: "server identifier missing (CLIENTID %s)",
! 510: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 511: piaddr(packet->client_addr),
! 512: print_hex_1(client_id->len, client_id->data, 60));
! 513: goto exit;
! 514: }
! 515: if (!evaluate_option_cache(server_id, packet, NULL, NULL,
! 516: packet->options, NULL,
! 517: &global_scope, oc, MDL)) {
! 518: log_error("Error processing %s from %s; "
! 519: "unable to evaluate Server Identifier (CLIENTID %s)",
! 520: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 521: piaddr(packet->client_addr),
! 522: print_hex_1(client_id->len, client_id->data, 60));
! 523: goto exit;
! 524: }
! 525: if ((server_duid.len != server_id->len) ||
! 526: (memcmp(server_duid.data, server_id->data, server_duid.len) != 0)) {
! 527: log_debug("Discarding %s from %s; "
! 528: "not our server identifier "
! 529: "(CLIENTID %s, SERVERID %s, server DUID %s)",
! 530: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 531: piaddr(packet->client_addr),
! 532: print_hex_1(client_id->len, client_id->data, 60),
! 533: print_hex_2(server_id->len, server_id->data, 60),
! 534: print_hex_3(server_duid.len, server_duid.data, 60));
! 535: goto exit;
! 536: }
! 537:
! 538: /* looks good */
! 539: ret_val = 1;
! 540:
! 541: exit:
! 542: if (!ret_val) {
! 543: if (server_id->len > 0) {
! 544: data_string_forget(server_id, MDL);
! 545: }
! 546: if (client_id->len > 0) {
! 547: data_string_forget(client_id, MDL);
! 548: }
! 549: }
! 550: return ret_val;
! 551: }
! 552:
! 553: /*
! 554: * Information request validation, defined in RFC 3315, section 15.12:
! 555: *
! 556: * Servers MUST discard any received Information-request message that
! 557: * meets any of the following conditions:
! 558: *
! 559: * - The message includes a Server Identifier option and the DUID in
! 560: * the option does not match the server's DUID.
! 561: *
! 562: * - The message includes an IA option.
! 563: */
! 564: int
! 565: valid_client_info_req(struct packet *packet, struct data_string *server_id) {
! 566: int ret_val;
! 567: struct option_cache *oc;
! 568: struct data_string client_id;
! 569: char client_id_str[80]; /* print_hex_1() uses maximum 60 characters,
! 570: plus a few more for extra information */
! 571:
! 572: ret_val = 0;
! 573: memset(server_id, 0, sizeof(*server_id));
! 574:
! 575: /*
! 576: * Make a string that we can print out to give more
! 577: * information about the client if we need to.
! 578: *
! 579: * By RFC 3315, Section 18.1.5 clients SHOULD have a
! 580: * client-id on an Information-request packet, but it
! 581: * is not strictly necessary.
! 582: */
! 583: if (get_client_id(packet, &client_id) == ISC_R_SUCCESS) {
! 584: snprintf(client_id_str, sizeof(client_id_str), " (CLIENTID %s)",
! 585: print_hex_1(client_id.len, client_id.data, 60));
! 586: data_string_forget(&client_id, MDL);
! 587: } else {
! 588: client_id_str[0] = '\0';
! 589: }
! 590:
! 591: /*
! 592: * Required by RFC 3315, section 15.
! 593: */
! 594: if (packet->unicast) {
! 595: log_debug("Discarding %s from %s; packet sent unicast%s",
! 596: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 597: piaddr(packet->client_addr), client_id_str);
! 598: goto exit;
! 599: }
! 600:
! 601: oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA);
! 602: if (oc != NULL) {
! 603: log_debug("Discarding %s from %s; "
! 604: "IA_NA option present%s",
! 605: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 606: piaddr(packet->client_addr), client_id_str);
! 607: goto exit;
! 608: }
! 609: oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_TA);
! 610: if (oc != NULL) {
! 611: log_debug("Discarding %s from %s; "
! 612: "IA_TA option present%s",
! 613: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 614: piaddr(packet->client_addr), client_id_str);
! 615: goto exit;
! 616: }
! 617: oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_PD);
! 618: if (oc != NULL) {
! 619: log_debug("Discarding %s from %s; "
! 620: "IA_PD option present%s",
! 621: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 622: piaddr(packet->client_addr), client_id_str);
! 623: goto exit;
! 624: }
! 625:
! 626: oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID);
! 627: if (oc != NULL) {
! 628: if (!evaluate_option_cache(server_id, packet, NULL, NULL,
! 629: packet->options, NULL,
! 630: &global_scope, oc, MDL)) {
! 631: log_error("Error processing %s from %s; "
! 632: "unable to evaluate Server Identifier%s",
! 633: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 634: piaddr(packet->client_addr), client_id_str);
! 635: goto exit;
! 636: }
! 637: if ((server_duid.len != server_id->len) ||
! 638: (memcmp(server_duid.data, server_id->data,
! 639: server_duid.len) != 0)) {
! 640: log_debug("Discarding %s from %s; "
! 641: "not our server identifier "
! 642: "(SERVERID %s, server DUID %s)%s",
! 643: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 644: piaddr(packet->client_addr),
! 645: print_hex_1(server_id->len,
! 646: server_id->data, 60),
! 647: print_hex_2(server_duid.len,
! 648: server_duid.data, 60),
! 649: client_id_str);
! 650: goto exit;
! 651: }
! 652: }
! 653:
! 654: /* looks good */
! 655: ret_val = 1;
! 656:
! 657: exit:
! 658: if (!ret_val) {
! 659: if (server_id->len > 0) {
! 660: data_string_forget(server_id, MDL);
! 661: }
! 662: }
! 663: return ret_val;
! 664: }
! 665:
! 666: /*
! 667: * Options that we want to send, in addition to what was requested
! 668: * via the ORO.
! 669: */
! 670: static const int required_opts[] = {
! 671: D6O_CLIENTID,
! 672: D6O_SERVERID,
! 673: D6O_STATUS_CODE,
! 674: D6O_PREFERENCE,
! 675: 0
! 676: };
! 677: static const int required_opts_NAA[] = {
! 678: D6O_CLIENTID,
! 679: D6O_SERVERID,
! 680: D6O_STATUS_CODE,
! 681: 0
! 682: };
! 683: static const int required_opts_solicit[] = {
! 684: D6O_CLIENTID,
! 685: D6O_SERVERID,
! 686: D6O_IA_NA,
! 687: D6O_IA_TA,
! 688: D6O_IA_PD,
! 689: D6O_RAPID_COMMIT,
! 690: D6O_STATUS_CODE,
! 691: D6O_RECONF_ACCEPT,
! 692: D6O_PREFERENCE,
! 693: 0
! 694: };
! 695: static const int required_opts_agent[] = {
! 696: D6O_INTERFACE_ID,
! 697: D6O_RELAY_MSG,
! 698: 0
! 699: };
! 700: static const int required_opts_IA[] = {
! 701: D6O_IAADDR,
! 702: D6O_STATUS_CODE,
! 703: 0
! 704: };
! 705: static const int required_opts_IA_PD[] = {
! 706: D6O_IAPREFIX,
! 707: D6O_STATUS_CODE,
! 708: 0
! 709: };
! 710: static const int required_opts_STATUS_CODE[] = {
! 711: D6O_STATUS_CODE,
! 712: 0
! 713: };
! 714:
! 715: /*
! 716: * Extracts from packet contents an IA_* option, storing the IA structure
! 717: * in its entirety in enc_opt_data, and storing any decoded DHCPv6 options
! 718: * in enc_opt_state for later lookup and evaluation. The 'offset' indicates
! 719: * where in the IA_* the DHCPv6 options commence.
! 720: */
! 721: static int
! 722: get_encapsulated_IA_state(struct option_state **enc_opt_state,
! 723: struct data_string *enc_opt_data,
! 724: struct packet *packet,
! 725: struct option_cache *oc,
! 726: int offset)
! 727: {
! 728: /*
! 729: * Get the raw data for the encapsulated options.
! 730: */
! 731: memset(enc_opt_data, 0, sizeof(*enc_opt_data));
! 732: if (!evaluate_option_cache(enc_opt_data, packet,
! 733: NULL, NULL, packet->options, NULL,
! 734: &global_scope, oc, MDL)) {
! 735: log_error("get_encapsulated_IA_state: "
! 736: "error evaluating raw option.");
! 737: return 0;
! 738: }
! 739: if (enc_opt_data->len < offset) {
! 740: log_error("get_encapsulated_IA_state: raw option too small.");
! 741: data_string_forget(enc_opt_data, MDL);
! 742: return 0;
! 743: }
! 744:
! 745: /*
! 746: * Now create the option state structure, and pass it to the
! 747: * function that parses options.
! 748: */
! 749: *enc_opt_state = NULL;
! 750: if (!option_state_allocate(enc_opt_state, MDL)) {
! 751: log_error("get_encapsulated_IA_state: no memory for options.");
! 752: data_string_forget(enc_opt_data, MDL);
! 753: return 0;
! 754: }
! 755: if (!parse_option_buffer(*enc_opt_state,
! 756: enc_opt_data->data + offset,
! 757: enc_opt_data->len - offset,
! 758: &dhcpv6_universe)) {
! 759: log_error("get_encapsulated_IA_state: error parsing options.");
! 760: option_state_dereference(enc_opt_state, MDL);
! 761: data_string_forget(enc_opt_data, MDL);
! 762: return 0;
! 763: }
! 764:
! 765: return 1;
! 766: }
! 767:
! 768: static int
! 769: set_status_code(u_int16_t status_code, const char *status_message,
! 770: struct option_state *opt_state)
! 771: {
! 772: struct data_string d;
! 773: int ret_val;
! 774:
! 775: memset(&d, 0, sizeof(d));
! 776: d.len = sizeof(status_code) + strlen(status_message);
! 777: if (!buffer_allocate(&d.buffer, d.len, MDL)) {
! 778: log_fatal("set_status_code: no memory for status code.");
! 779: }
! 780: d.data = d.buffer->data;
! 781: putUShort(d.buffer->data, status_code);
! 782: memcpy(d.buffer->data + sizeof(status_code),
! 783: status_message, d.len - sizeof(status_code));
! 784: if (!save_option_buffer(&dhcpv6_universe, opt_state,
! 785: d.buffer, (unsigned char *)d.data, d.len,
! 786: D6O_STATUS_CODE, 0)) {
! 787: log_error("set_status_code: error saving status code.");
! 788: ret_val = 0;
! 789: } else {
! 790: ret_val = 1;
! 791: }
! 792: data_string_forget(&d, MDL);
! 793: return ret_val;
! 794: }
! 795:
! 796: /*
! 797: * We have a set of operations we do to set up the reply packet, which
! 798: * is the same for many message types.
! 799: */
! 800: static int
! 801: start_reply(struct packet *packet,
! 802: const struct data_string *client_id,
! 803: const struct data_string *server_id,
! 804: struct option_state **opt_state,
! 805: struct dhcpv6_packet *reply)
! 806: {
! 807: struct option_cache *oc;
! 808: const unsigned char *server_id_data;
! 809: int server_id_len;
! 810:
! 811: /*
! 812: * Build our option state for reply.
! 813: */
! 814: *opt_state = NULL;
! 815: if (!option_state_allocate(opt_state, MDL)) {
! 816: log_error("start_reply: no memory for option_state.");
! 817: return 0;
! 818: }
! 819: execute_statements_in_scope(NULL, packet, NULL, NULL,
! 820: packet->options, *opt_state,
! 821: &global_scope, root_group, NULL);
! 822:
! 823: /*
! 824: * A small bit of special handling for Solicit messages.
! 825: *
! 826: * We could move the logic into a flag, but for now just check
! 827: * explicitly.
! 828: */
! 829: if (packet->dhcpv6_msg_type == DHCPV6_SOLICIT) {
! 830: reply->msg_type = DHCPV6_ADVERTISE;
! 831:
! 832: /*
! 833: * If:
! 834: * - this message type supports rapid commit (Solicit), and
! 835: * - the server is configured to supply a rapid commit, and
! 836: * - the client requests a rapid commit,
! 837: * Then we add a rapid commit option, and send Reply (instead
! 838: * of an Advertise).
! 839: */
! 840: oc = lookup_option(&dhcpv6_universe,
! 841: *opt_state, D6O_RAPID_COMMIT);
! 842: if (oc != NULL) {
! 843: oc = lookup_option(&dhcpv6_universe,
! 844: packet->options, D6O_RAPID_COMMIT);
! 845: if (oc != NULL) {
! 846: /* Rapid-commit in action. */
! 847: reply->msg_type = DHCPV6_REPLY;
! 848: } else {
! 849: /* Don't want a rapid-commit in advertise. */
! 850: delete_option(&dhcpv6_universe,
! 851: *opt_state, D6O_RAPID_COMMIT);
! 852: }
! 853: }
! 854: } else {
! 855: reply->msg_type = DHCPV6_REPLY;
! 856: /* Delete the rapid-commit from the sent options. */
! 857: oc = lookup_option(&dhcpv6_universe,
! 858: *opt_state, D6O_RAPID_COMMIT);
! 859: if (oc != NULL) {
! 860: delete_option(&dhcpv6_universe,
! 861: *opt_state, D6O_RAPID_COMMIT);
! 862: }
! 863: }
! 864:
! 865: /*
! 866: * Use the client's transaction identifier for the reply.
! 867: */
! 868: memcpy(reply->transaction_id, packet->dhcpv6_transaction_id,
! 869: sizeof(reply->transaction_id));
! 870:
! 871: /*
! 872: * RFC 3315, section 18.2 says we need server identifier and
! 873: * client identifier.
! 874: *
! 875: * If the server ID is defined via the configuration file, then
! 876: * it will already be present in the option state at this point,
! 877: * so we don't need to set it.
! 878: *
! 879: * If we have a server ID passed in from the caller,
! 880: * use that, otherwise use the global DUID.
! 881: */
! 882: oc = lookup_option(&dhcpv6_universe, *opt_state, D6O_SERVERID);
! 883: if (oc == NULL) {
! 884: if (server_id == NULL) {
! 885: server_id_data = server_duid.data;
! 886: server_id_len = server_duid.len;
! 887: } else {
! 888: server_id_data = server_id->data;
! 889: server_id_len = server_id->len;
! 890: }
! 891: if (!save_option_buffer(&dhcpv6_universe, *opt_state,
! 892: NULL, (unsigned char *)server_id_data,
! 893: server_id_len, D6O_SERVERID, 0)) {
! 894: log_error("start_reply: "
! 895: "error saving server identifier.");
! 896: return 0;
! 897: }
! 898: }
! 899:
! 900: if (client_id->buffer != NULL) {
! 901: if (!save_option_buffer(&dhcpv6_universe, *opt_state,
! 902: client_id->buffer,
! 903: (unsigned char *)client_id->data,
! 904: client_id->len,
! 905: D6O_CLIENTID, 0)) {
! 906: log_error("start_reply: error saving "
! 907: "client identifier.");
! 908: return 0;
! 909: }
! 910: }
! 911:
! 912: /*
! 913: * If the client accepts reconfiguration, let it know that we
! 914: * will send them.
! 915: *
! 916: * Note: we don't actually do this yet, but DOCSIS requires we
! 917: * claim to.
! 918: */
! 919: oc = lookup_option(&dhcpv6_universe, packet->options,
! 920: D6O_RECONF_ACCEPT);
! 921: if (oc != NULL) {
! 922: if (!save_option_buffer(&dhcpv6_universe, *opt_state,
! 923: NULL, (unsigned char *)"", 0,
! 924: D6O_RECONF_ACCEPT, 0)) {
! 925: log_error("start_reply: "
! 926: "error saving RECONF_ACCEPT option.");
! 927: option_state_dereference(opt_state, MDL);
! 928: return 0;
! 929: }
! 930: }
! 931:
! 932: return 1;
! 933: }
! 934:
! 935: /*
! 936: * Try to get the IPv6 address the client asked for from the
! 937: * pool.
! 938: *
! 939: * addr is the result (should be a pointer to NULL on entry)
! 940: * pool is the pool to search in
! 941: * requested_addr is the address the client wants
! 942: */
! 943: static isc_result_t
! 944: try_client_v6_address(struct iasubopt **addr,
! 945: struct ipv6_pool *pool,
! 946: const struct data_string *requested_addr)
! 947: {
! 948: struct in6_addr tmp_addr;
! 949: isc_result_t result;
! 950:
! 951: if (requested_addr->len < sizeof(tmp_addr)) {
! 952: return ISC_R_INVALIDARG;
! 953: }
! 954: memcpy(&tmp_addr, requested_addr->data, sizeof(tmp_addr));
! 955: if (IN6_IS_ADDR_UNSPECIFIED(&tmp_addr)) {
! 956: return ISC_R_FAILURE;
! 957: }
! 958:
! 959: /*
! 960: * The address is not covered by this (or possibly any) dynamic
! 961: * range.
! 962: */
! 963: if (!ipv6_in_pool(&tmp_addr, pool)) {
! 964: return ISC_R_ADDRNOTAVAIL;
! 965: }
! 966:
! 967: if (lease6_exists(pool, &tmp_addr)) {
! 968: return ISC_R_ADDRINUSE;
! 969: }
! 970:
! 971: result = iasubopt_allocate(addr, MDL);
! 972: if (result != ISC_R_SUCCESS) {
! 973: return result;
! 974: }
! 975: (*addr)->addr = tmp_addr;
! 976: (*addr)->plen = 0;
! 977:
! 978: /* Default is soft binding for 2 minutes. */
! 979: result = add_lease6(pool, *addr, cur_time + 120);
! 980: if (result != ISC_R_SUCCESS) {
! 981: iasubopt_dereference(addr, MDL);
! 982: }
! 983: return result;
! 984: }
! 985:
! 986: /*
! 987: * Get an IPv6 address for the client.
! 988: *
! 989: * addr is the result (should be a pointer to NULL on entry)
! 990: * packet is the information about the packet from the client
! 991: * requested_iaaddr is a hint from the client
! 992: * client_id is the DUID for the client
! 993: */
! 994: static isc_result_t
! 995: pick_v6_address(struct iasubopt **addr, struct shared_network *shared_network,
! 996: const struct data_string *client_id)
! 997: {
! 998: struct ipv6_pool *p;
! 999: int i;
! 1000: int start_pool;
! 1001: unsigned int attempts;
! 1002: char tmp_buf[INET6_ADDRSTRLEN];
! 1003:
! 1004: /*
! 1005: * No address pools, we're done.
! 1006: */
! 1007: if (shared_network->ipv6_pools == NULL) {
! 1008: log_debug("Unable to pick client address: "
! 1009: "no IPv6 pools on this shared network");
! 1010: return ISC_R_NORESOURCES;
! 1011: }
! 1012: for (i = 0;; i++) {
! 1013: p = shared_network->ipv6_pools[i];
! 1014: if (p == NULL) {
! 1015: log_debug("Unable to pick client address: "
! 1016: "no IPv6 address pools "
! 1017: "on this shared network");
! 1018: return ISC_R_NORESOURCES;
! 1019: }
! 1020: if (p->pool_type == D6O_IA_NA) {
! 1021: break;
! 1022: }
! 1023: }
! 1024:
! 1025: /*
! 1026: * Otherwise try to get a lease from the first subnet possible.
! 1027: *
! 1028: * We start looking at the last pool we allocated from, unless
! 1029: * it had a collision trying to allocate an address. This will
! 1030: * tend to move us into less-filled pools.
! 1031: */
! 1032: start_pool = shared_network->last_ipv6_pool;
! 1033: i = start_pool;
! 1034: do {
! 1035:
! 1036: p = shared_network->ipv6_pools[i];
! 1037: if ((p->pool_type == D6O_IA_NA) &&
! 1038: (create_lease6(p, addr, &attempts, client_id,
! 1039: cur_time + 120) == ISC_R_SUCCESS)) {
! 1040: /*
! 1041: * Record the pool used (or next one if there
! 1042: * was a collision).
! 1043: */
! 1044: if (attempts > 1) {
! 1045: i++;
! 1046: if (shared_network->ipv6_pools[i] == NULL) {
! 1047: i = 0;
! 1048: }
! 1049: }
! 1050: shared_network->last_ipv6_pool = i;
! 1051:
! 1052: log_debug("Picking pool address %s",
! 1053: inet_ntop(AF_INET6, &((*addr)->addr),
! 1054: tmp_buf, sizeof(tmp_buf)));
! 1055: return ISC_R_SUCCESS;
! 1056: }
! 1057:
! 1058: i++;
! 1059: if (shared_network->ipv6_pools[i] == NULL) {
! 1060: i = 0;
! 1061: }
! 1062: } while (i != start_pool);
! 1063:
! 1064: /*
! 1065: * If we failed to pick an IPv6 address from any of the subnets.
! 1066: * Presumably that means we have no addresses for the client.
! 1067: */
! 1068: log_debug("Unable to pick client address: no addresses available");
! 1069: return ISC_R_NORESOURCES;
! 1070: }
! 1071:
! 1072: /*
! 1073: * Try to get the IPv6 prefix the client asked for from the
! 1074: * prefix pool.
! 1075: *
! 1076: * pref is the result (should be a pointer to NULL on entry)
! 1077: * pool is the prefix pool to search in
! 1078: * requested_pref is the address the client wants
! 1079: */
! 1080: static isc_result_t
! 1081: try_client_v6_prefix(struct iasubopt **pref,
! 1082: struct ipv6_pool *pool,
! 1083: const struct data_string *requested_pref)
! 1084: {
! 1085: u_int8_t tmp_plen;
! 1086: struct in6_addr tmp_pref;
! 1087: struct iaddr ia;
! 1088: isc_result_t result;
! 1089:
! 1090: if (requested_pref->len < sizeof(tmp_plen) + sizeof(tmp_pref)) {
! 1091: return ISC_R_INVALIDARG;
! 1092: }
! 1093: tmp_plen = (int) requested_pref->data[0];
! 1094: if ((tmp_plen < 3) || (tmp_plen > 128)) {
! 1095: return ISC_R_FAILURE;
! 1096: }
! 1097: memcpy(&tmp_pref, requested_pref->data + 1, sizeof(tmp_pref));
! 1098: if (IN6_IS_ADDR_UNSPECIFIED(&tmp_pref)) {
! 1099: return ISC_R_FAILURE;
! 1100: }
! 1101: ia.len = 16;
! 1102: memcpy(&ia.iabuf, &tmp_pref, 16);
! 1103: if (!is_cidr_mask_valid(&ia, (int) tmp_plen)) {
! 1104: return ISC_R_FAILURE;
! 1105: }
! 1106:
! 1107: if (((int)tmp_plen != pool->units) ||
! 1108: !ipv6_in_pool(&tmp_pref, pool)) {
! 1109: return ISC_R_FAILURE;
! 1110: }
! 1111:
! 1112: if (prefix6_exists(pool, &tmp_pref, tmp_plen)) {
! 1113: return ISC_R_ADDRINUSE;
! 1114: }
! 1115:
! 1116: result = iasubopt_allocate(pref, MDL);
! 1117: if (result != ISC_R_SUCCESS) {
! 1118: return result;
! 1119: }
! 1120: (*pref)->addr = tmp_pref;
! 1121: (*pref)->plen = tmp_plen;
! 1122:
! 1123: /* Default is soft binding for 2 minutes. */
! 1124: result = add_lease6(pool, *pref, cur_time + 120);
! 1125: if (result != ISC_R_SUCCESS) {
! 1126: iasubopt_dereference(pref, MDL);
! 1127: }
! 1128: return result;
! 1129: }
! 1130:
! 1131: /*
! 1132: * Get an IPv6 prefix for the client.
! 1133: *
! 1134: * pref is the result (should be a pointer to NULL on entry)
! 1135: * packet is the information about the packet from the client
! 1136: * requested_iaprefix is a hint from the client
! 1137: * plen is -1 or the requested prefix length
! 1138: * client_id is the DUID for the client
! 1139: */
! 1140: static isc_result_t
! 1141: pick_v6_prefix(struct iasubopt **pref, int plen,
! 1142: struct shared_network *shared_network,
! 1143: const struct data_string *client_id)
! 1144: {
! 1145: struct ipv6_pool *p;
! 1146: int i;
! 1147: unsigned int attempts;
! 1148: char tmp_buf[INET6_ADDRSTRLEN];
! 1149:
! 1150: /*
! 1151: * No prefix pools, we're done.
! 1152: */
! 1153: if (shared_network->ipv6_pools == NULL) {
! 1154: log_debug("Unable to pick client prefix: "
! 1155: "no IPv6 pools on this shared network");
! 1156: return ISC_R_NORESOURCES;
! 1157: }
! 1158: for (i = 0;; i++) {
! 1159: p = shared_network->ipv6_pools[i];
! 1160: if (p == NULL) {
! 1161: log_debug("Unable to pick client prefix: "
! 1162: "no IPv6 prefix pools "
! 1163: "on this shared network");
! 1164: return ISC_R_NORESOURCES;
! 1165: }
! 1166: if (p->pool_type == D6O_IA_PD) {
! 1167: break;
! 1168: }
! 1169: }
! 1170:
! 1171: /*
! 1172: * Otherwise try to get a prefix.
! 1173: */
! 1174: for (i = 0;; i++) {
! 1175: p = shared_network->ipv6_pools[i];
! 1176: if (p == NULL) {
! 1177: break;
! 1178: }
! 1179: if (p->pool_type != D6O_IA_PD) {
! 1180: continue;
! 1181: }
! 1182:
! 1183: /*
! 1184: * Try only pools with the requested prefix length if any.
! 1185: */
! 1186: if ((plen >= 0) && (p->units != plen)) {
! 1187: continue;
! 1188: }
! 1189:
! 1190: if (create_prefix6(p, pref, &attempts, client_id,
! 1191: cur_time + 120) == ISC_R_SUCCESS) {
! 1192: log_debug("Picking pool prefix %s/%u",
! 1193: inet_ntop(AF_INET6, &((*pref)->addr),
! 1194: tmp_buf, sizeof(tmp_buf)),
! 1195: (unsigned) (*pref)->plen);
! 1196: return ISC_R_SUCCESS;
! 1197: }
! 1198: }
! 1199:
! 1200: /*
! 1201: * If we failed to pick an IPv6 prefix
! 1202: * Presumably that means we have no prefixes for the client.
! 1203: */
! 1204: log_debug("Unable to pick client prefix: no prefixes available");
! 1205: return ISC_R_NORESOURCES;
! 1206: }
! 1207:
! 1208: /*
! 1209: * lease_to_client() is called from several messages to construct a
! 1210: * reply that contains all that we know about the client's correct lease
! 1211: * (or projected lease).
! 1212: *
! 1213: * Solicit - "Soft" binding, ignore unknown addresses or bindings, just
! 1214: * send what we "may" give them on a request.
! 1215: *
! 1216: * Request - "Hard" binding, but ignore supplied addresses (just provide what
! 1217: * the client should really use).
! 1218: *
! 1219: * Renew - "Hard" binding, but client-supplied addresses are 'real'. Error
! 1220: * Rebind out any "wrong" addresses the client sends. This means we send
! 1221: * an empty IA_NA with a status code of NoBinding or NotOnLink or
! 1222: * possibly send the address with zeroed lifetimes.
! 1223: *
! 1224: * Information-Request - No binding.
! 1225: *
! 1226: * The basic structure is to traverse the client-supplied data first, and
! 1227: * validate and echo back any contents that can be. If the client-supplied
! 1228: * data does not error out (on renew/rebind as above), but we did not send
! 1229: * any addresses, attempt to allocate one.
! 1230: */
! 1231: /* TODO: look at client hints for lease times */
! 1232: static void
! 1233: lease_to_client(struct data_string *reply_ret,
! 1234: struct packet *packet,
! 1235: const struct data_string *client_id,
! 1236: const struct data_string *server_id)
! 1237: {
! 1238: static struct reply_state reply;
! 1239: struct option_cache *oc;
! 1240: struct data_string packet_oro;
! 1241: isc_boolean_t no_resources_avail;
! 1242:
! 1243: /* Locate the client. */
! 1244: if (shared_network_from_packet6(&reply.shared,
! 1245: packet) != ISC_R_SUCCESS)
! 1246: goto exit;
! 1247:
! 1248: /*
! 1249: * Initialize the reply.
! 1250: */
! 1251: packet_reference(&reply.packet, packet, MDL);
! 1252: data_string_copy(&reply.client_id, client_id, MDL);
! 1253:
! 1254: if (!start_reply(packet, client_id, server_id, &reply.opt_state,
! 1255: &reply.buf.reply))
! 1256: goto exit;
! 1257:
! 1258: /* Set the write cursor to just past the reply header. */
! 1259: reply.cursor = REPLY_OPTIONS_INDEX;
! 1260:
! 1261: /*
! 1262: * Get the ORO from the packet, if any.
! 1263: */
! 1264: oc = lookup_option(&dhcpv6_universe, packet->options, D6O_ORO);
! 1265: memset(&packet_oro, 0, sizeof(packet_oro));
! 1266: if (oc != NULL) {
! 1267: if (!evaluate_option_cache(&packet_oro, packet,
! 1268: NULL, NULL,
! 1269: packet->options, NULL,
! 1270: &global_scope, oc, MDL)) {
! 1271: log_error("lease_to_client: error evaluating ORO.");
! 1272: goto exit;
! 1273: }
! 1274: }
! 1275:
! 1276: /*
! 1277: * Find a host record that matches from the packet, if any, and is
! 1278: * valid for the shared network the client is on.
! 1279: */
! 1280: if (find_hosts_by_option(&reply.host, packet, packet->options, MDL)) {
! 1281: seek_shared_host(&reply.host, reply.shared);
! 1282: }
! 1283:
! 1284: if ((reply.host == NULL) &&
! 1285: find_hosts_by_uid(&reply.host, client_id->data, client_id->len,
! 1286: MDL)) {
! 1287: seek_shared_host(&reply.host, reply.shared);
! 1288: }
! 1289:
! 1290: /* Process the client supplied IA's onto the reply buffer. */
! 1291: reply.ia_count = 0;
! 1292: oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA);
! 1293: no_resources_avail = ISC_FALSE;
! 1294: for (; oc != NULL ; oc = oc->next) {
! 1295: isc_result_t status;
! 1296:
! 1297: /* Start counting resources (addresses) offered. */
! 1298: reply.client_resources = 0;
! 1299: reply.resources_included = ISC_FALSE;
! 1300:
! 1301: status = reply_process_ia_na(&reply, oc);
! 1302:
! 1303: /*
! 1304: * We continue to try other IA's whether we can address
! 1305: * this one or not. Any other result is an immediate fail.
! 1306: */
! 1307: if ((status != ISC_R_SUCCESS) &&
! 1308: (status != ISC_R_NORESOURCES))
! 1309: goto exit;
! 1310:
! 1311: /*
! 1312: * If any address cannot be given to any IA, then set the
! 1313: * NoAddrsAvail status code.
! 1314: */
! 1315: if (reply.client_resources == 0)
! 1316: no_resources_avail = ISC_TRUE;
! 1317: }
! 1318: oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_TA);
! 1319: for (; oc != NULL ; oc = oc->next) {
! 1320: isc_result_t status;
! 1321:
! 1322: /* Start counting resources (addresses) offered. */
! 1323: reply.client_resources = 0;
! 1324: reply.resources_included = ISC_FALSE;
! 1325:
! 1326: status = reply_process_ia_ta(&reply, oc);
! 1327:
! 1328: /*
! 1329: * We continue to try other IA's whether we can address
! 1330: * this one or not. Any other result is an immediate fail.
! 1331: */
! 1332: if ((status != ISC_R_SUCCESS) &&
! 1333: (status != ISC_R_NORESOURCES))
! 1334: goto exit;
! 1335:
! 1336: /*
! 1337: * If any address cannot be given to any IA, then set the
! 1338: * NoAddrsAvail status code.
! 1339: */
! 1340: if (reply.client_resources == 0)
! 1341: no_resources_avail = ISC_TRUE;
! 1342: }
! 1343:
! 1344: /* Same for IA_PD's. */
! 1345: reply.pd_count = 0;
! 1346: oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_PD);
! 1347: for (; oc != NULL ; oc = oc->next) {
! 1348: isc_result_t status;
! 1349:
! 1350: /* Start counting resources (prefixes) offered. */
! 1351: reply.client_resources = 0;
! 1352: reply.resources_included = ISC_FALSE;
! 1353:
! 1354: status = reply_process_ia_pd(&reply, oc);
! 1355:
! 1356: /*
! 1357: * We continue to try other IA_PD's whether we can address
! 1358: * this one or not. Any other result is an immediate fail.
! 1359: */
! 1360: if ((status != ISC_R_SUCCESS) &&
! 1361: (status != ISC_R_NORESOURCES))
! 1362: goto exit;
! 1363:
! 1364: /*
! 1365: * If any prefix cannot be given to any IA_PD, then
! 1366: * set the NoPrefixAvail status code.
! 1367: */
! 1368: if (reply.client_resources == 0)
! 1369: no_resources_avail = ISC_TRUE;
! 1370: }
! 1371:
! 1372: /*
! 1373: * Make no reply if we gave no resources and is not
! 1374: * for Information-Request.
! 1375: */
! 1376: if ((reply.ia_count == 0) && (reply.pd_count == 0)) {
! 1377: if (reply.packet->dhcpv6_msg_type !=
! 1378: DHCPV6_INFORMATION_REQUEST)
! 1379: goto exit;
! 1380:
! 1381: /*
! 1382: * Because we only execute statements on a per-IA basis,
! 1383: * we need to execute statements in any non-IA reply to
! 1384: * source configuration.
! 1385: */
! 1386: execute_statements_in_scope(NULL, reply.packet, NULL, NULL,
! 1387: reply.packet->options,
! 1388: reply.opt_state, &global_scope,
! 1389: reply.shared->group, root_group);
! 1390:
! 1391: /* Bring in any configuration from a host record. */
! 1392: if (reply.host != NULL)
! 1393: execute_statements_in_scope(NULL, reply.packet, NULL,
! 1394: NULL, reply.packet->options,
! 1395: reply.opt_state,
! 1396: &global_scope,
! 1397: reply.host->group,
! 1398: reply.shared->group);
! 1399: }
! 1400:
! 1401: /*
! 1402: * RFC3315 section 17.2.2 (Solicit):
! 1403: *
! 1404: * If the server will not assign any addresses to any IAs in a
! 1405: * subsequent Request from the client, the server MUST send an
! 1406: * Advertise message to the client that includes only a Status
! 1407: * Code option with code NoAddrsAvail and a status message for
! 1408: * the user, a Server Identifier option with the server's DUID,
! 1409: * and a Client Identifier option with the client's DUID.
! 1410: *
! 1411: * Section 18.2.1 (Request):
! 1412: *
! 1413: * If the server cannot assign any addresses to an IA in the
! 1414: * message from the client, the server MUST include the IA in
! 1415: * the Reply message with no addresses in the IA and a Status
! 1416: * Code option in the IA containing status code NoAddrsAvail.
! 1417: *
! 1418: * Section 18.1.8 (Client Behavior):
! 1419: *
! 1420: * Leave unchanged any information about addresses the client has
! 1421: * recorded in the IA but that were not included in the IA from
! 1422: * the server.
! 1423: * Sends a Renew/Rebind if the IA is not in the Reply message.
! 1424: */
! 1425: if (no_resources_avail && (reply.ia_count != 0) &&
! 1426: (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
! 1427: {
! 1428: /* Set the NoAddrsAvail status code. */
! 1429: if (!set_status_code(STATUS_NoAddrsAvail,
! 1430: "No addresses available for this "
! 1431: "interface.", reply.opt_state)) {
! 1432: log_error("lease_to_client: Unable to set "
! 1433: "NoAddrsAvail status code.");
! 1434: goto exit;
! 1435: }
! 1436:
! 1437: /* Rewind the cursor to the start. */
! 1438: reply.cursor = REPLY_OPTIONS_INDEX;
! 1439:
! 1440: /*
! 1441: * Produce an advertise that includes only:
! 1442: *
! 1443: * Status code.
! 1444: * Server DUID.
! 1445: * Client DUID.
! 1446: */
! 1447: reply.buf.reply.msg_type = DHCPV6_ADVERTISE;
! 1448: reply.cursor += store_options6((char *)reply.buf.data +
! 1449: reply.cursor,
! 1450: sizeof(reply.buf) -
! 1451: reply.cursor,
! 1452: reply.opt_state, reply.packet,
! 1453: required_opts_NAA,
! 1454: NULL);
! 1455: } else if (no_resources_avail && (reply.ia_count == 0) &&
! 1456: (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
! 1457: {
! 1458: /* Set the NoPrefixAvail status code. */
! 1459: if (!set_status_code(STATUS_NoPrefixAvail,
! 1460: "No prefixes available for this "
! 1461: "interface.", reply.opt_state)) {
! 1462: log_error("lease_to_client: Unable to set "
! 1463: "NoPrefixAvail status code.");
! 1464: goto exit;
! 1465: }
! 1466:
! 1467: /* Rewind the cursor to the start. */
! 1468: reply.cursor = REPLY_OPTIONS_INDEX;
! 1469:
! 1470: /*
! 1471: * Produce an advertise that includes only:
! 1472: *
! 1473: * Status code.
! 1474: * Server DUID.
! 1475: * Client DUID.
! 1476: */
! 1477: reply.buf.reply.msg_type = DHCPV6_ADVERTISE;
! 1478: reply.cursor += store_options6((char *)reply.buf.data +
! 1479: reply.cursor,
! 1480: sizeof(reply.buf) -
! 1481: reply.cursor,
! 1482: reply.opt_state, reply.packet,
! 1483: required_opts_NAA,
! 1484: NULL);
! 1485: } else {
! 1486: /*
! 1487: * Having stored the client's IA's, store any options that
! 1488: * will fit in the remaining space.
! 1489: */
! 1490: reply.cursor += store_options6((char *)reply.buf.data +
! 1491: reply.cursor,
! 1492: sizeof(reply.buf) -
! 1493: reply.cursor,
! 1494: reply.opt_state, reply.packet,
! 1495: required_opts_solicit,
! 1496: &packet_oro);
! 1497: }
! 1498:
! 1499: /* Return our reply to the caller. */
! 1500: reply_ret->len = reply.cursor;
! 1501: reply_ret->buffer = NULL;
! 1502: if (!buffer_allocate(&reply_ret->buffer, reply.cursor, MDL)) {
! 1503: log_fatal("No memory to store Reply.");
! 1504: }
! 1505: memcpy(reply_ret->buffer->data, reply.buf.data, reply.cursor);
! 1506: reply_ret->data = reply_ret->buffer->data;
! 1507:
! 1508: exit:
! 1509: /* Cleanup. */
! 1510: if (reply.shared != NULL)
! 1511: shared_network_dereference(&reply.shared, MDL);
! 1512: if (reply.host != NULL)
! 1513: host_dereference(&reply.host, MDL);
! 1514: if (reply.opt_state != NULL)
! 1515: option_state_dereference(&reply.opt_state, MDL);
! 1516: if (reply.packet != NULL)
! 1517: packet_dereference(&reply.packet, MDL);
! 1518: if (reply.client_id.data != NULL)
! 1519: data_string_forget(&reply.client_id, MDL);
! 1520: reply.renew = reply.rebind = reply.prefer = reply.valid = 0;
! 1521: reply.cursor = 0;
! 1522: }
! 1523:
! 1524: /* Process a client-supplied IA_NA. This may append options to the tail of
! 1525: * the reply packet being built in the reply_state structure.
! 1526: */
! 1527: static isc_result_t
! 1528: reply_process_ia_na(struct reply_state *reply, struct option_cache *ia) {
! 1529: isc_result_t status = ISC_R_SUCCESS;
! 1530: u_int32_t iaid;
! 1531: unsigned ia_cursor;
! 1532: struct option_state *packet_ia;
! 1533: struct option_cache *oc;
! 1534: struct data_string ia_data, data;
! 1535:
! 1536: /* Initialize values that will get cleaned up on return. */
! 1537: packet_ia = NULL;
! 1538: memset(&ia_data, 0, sizeof(ia_data));
! 1539: memset(&data, 0, sizeof(data));
! 1540: /*
! 1541: * Note that find_client_address() may set reply->lease.
! 1542: */
! 1543:
! 1544: /* Make sure there is at least room for the header. */
! 1545: if ((reply->cursor + IA_NA_OFFSET + 4) > sizeof(reply->buf)) {
! 1546: log_error("reply_process_ia_na: Reply too long for IA.");
! 1547: return ISC_R_NOSPACE;
! 1548: }
! 1549:
! 1550:
! 1551: /* Fetch the IA_NA contents. */
! 1552: if (!get_encapsulated_IA_state(&packet_ia, &ia_data, reply->packet,
! 1553: ia, IA_NA_OFFSET)) {
! 1554: log_error("reply_process_ia_na: error evaluating ia");
! 1555: status = ISC_R_FAILURE;
! 1556: goto cleanup;
! 1557: }
! 1558:
! 1559: /* Extract IA_NA header contents. */
! 1560: iaid = getULong(ia_data.data);
! 1561: reply->renew = getULong(ia_data.data + 4);
! 1562: reply->rebind = getULong(ia_data.data + 8);
! 1563:
! 1564: /* Create an IA_NA structure. */
! 1565: if (ia_allocate(&reply->ia, iaid, (char *)reply->client_id.data,
! 1566: reply->client_id.len, MDL) != ISC_R_SUCCESS) {
! 1567: log_error("reply_process_ia_na: no memory for ia.");
! 1568: status = ISC_R_NOMEMORY;
! 1569: goto cleanup;
! 1570: }
! 1571: reply->ia->ia_type = D6O_IA_NA;
! 1572:
! 1573: /* Cache pre-existing IA, if any. */
! 1574: ia_hash_lookup(&reply->old_ia, ia_na_active,
! 1575: (unsigned char *)reply->ia->iaid_duid.data,
! 1576: reply->ia->iaid_duid.len, MDL);
! 1577:
! 1578: /*
! 1579: * Create an option cache to carry the IA_NA option contents, and
! 1580: * execute any user-supplied values into it.
! 1581: */
! 1582: if (!option_state_allocate(&reply->reply_ia, MDL)) {
! 1583: status = ISC_R_NOMEMORY;
! 1584: goto cleanup;
! 1585: }
! 1586:
! 1587: /* Check & cache the fixed host record. */
! 1588: if ((reply->host != NULL) && (reply->host->fixed_addr != NULL)) {
! 1589: struct iaddr tmp_addr;
! 1590:
! 1591: if (!evaluate_option_cache(&reply->fixed, NULL, NULL, NULL,
! 1592: NULL, NULL, &global_scope,
! 1593: reply->host->fixed_addr, MDL)) {
! 1594: log_error("reply_process_ia_na: unable to evaluate "
! 1595: "fixed address.");
! 1596: status = ISC_R_FAILURE;
! 1597: goto cleanup;
! 1598: }
! 1599:
! 1600: if (reply->fixed.len < 16) {
! 1601: log_error("reply_process_ia_na: invalid fixed address.");
! 1602: status = ISC_R_INVALIDARG;
! 1603: goto cleanup;
! 1604: }
! 1605:
! 1606: /* Find the static lease's subnet. */
! 1607: tmp_addr.len = 16;
! 1608: memcpy(tmp_addr.iabuf, reply->fixed.data, 16);
! 1609:
! 1610: if (find_grouped_subnet(&reply->subnet, reply->shared,
! 1611: tmp_addr, MDL) == 0)
! 1612: log_fatal("Impossible condition at %s:%d.", MDL);
! 1613:
! 1614: reply->static_lease = ISC_TRUE;
! 1615: } else
! 1616: reply->static_lease = ISC_FALSE;
! 1617:
! 1618: /*
! 1619: * Save the cursor position at the start of the IA, so we can
! 1620: * set length and adjust t1/t2 values later. We write a temporary
! 1621: * header out now just in case we decide to adjust the packet
! 1622: * within sub-process functions.
! 1623: */
! 1624: ia_cursor = reply->cursor;
! 1625:
! 1626: /* Initialize the IA_NA header. First the code. */
! 1627: putUShort(reply->buf.data + reply->cursor, (unsigned)D6O_IA_NA);
! 1628: reply->cursor += 2;
! 1629:
! 1630: /* Then option length. */
! 1631: putUShort(reply->buf.data + reply->cursor, 0x0Cu);
! 1632: reply->cursor += 2;
! 1633:
! 1634: /* Then IA_NA header contents; IAID. */
! 1635: putULong(reply->buf.data + reply->cursor, iaid);
! 1636: reply->cursor += 4;
! 1637:
! 1638: /* We store the client's t1 for now, and may over-ride it later. */
! 1639: putULong(reply->buf.data + reply->cursor, reply->renew);
! 1640: reply->cursor += 4;
! 1641:
! 1642: /* We store the client's t2 for now, and may over-ride it later. */
! 1643: putULong(reply->buf.data + reply->cursor, reply->rebind);
! 1644: reply->cursor += 4;
! 1645:
! 1646: /*
! 1647: * For each address in this IA_NA, decide what to do about it.
! 1648: *
! 1649: * Guidelines:
! 1650: *
! 1651: * The client leaves unchanged any infomation about addresses
! 1652: * it has recorded but are not included ("cancel/break" below).
! 1653: * A not included IA ("cleanup" below) could give a Renew/Rebind.
! 1654: */
! 1655: oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAADDR);
! 1656: reply->valid = reply->prefer = 0xffffffff;
! 1657: reply->client_valid = reply->client_prefer = 0;
! 1658: for (; oc != NULL ; oc = oc->next) {
! 1659: status = reply_process_addr(reply, oc);
! 1660:
! 1661: /*
! 1662: * Canceled means we did not allocate addresses to the
! 1663: * client, but we're "done" with this IA - we set a status
! 1664: * code. So transmit this reply, e.g., move on to the next
! 1665: * IA.
! 1666: */
! 1667: if (status == ISC_R_CANCELED)
! 1668: break;
! 1669:
! 1670: if ((status != ISC_R_SUCCESS) &&
! 1671: (status != ISC_R_ADDRINUSE) &&
! 1672: (status != ISC_R_ADDRNOTAVAIL))
! 1673: goto cleanup;
! 1674: }
! 1675:
! 1676: reply->ia_count++;
! 1677:
! 1678: /*
! 1679: * If we fell through the above and never gave the client
! 1680: * an address, give it one now.
! 1681: */
! 1682: if ((status != ISC_R_CANCELED) && (reply->client_resources == 0)) {
! 1683: status = find_client_address(reply);
! 1684:
! 1685: if (status == ISC_R_NORESOURCES) {
! 1686: switch (reply->packet->dhcpv6_msg_type) {
! 1687: case DHCPV6_SOLICIT:
! 1688: /*
! 1689: * No address for any IA is handled
! 1690: * by the caller.
! 1691: */
! 1692: /* FALL THROUGH */
! 1693:
! 1694: case DHCPV6_REQUEST:
! 1695: /* Section 18.2.1 (Request):
! 1696: *
! 1697: * If the server cannot assign any addresses to
! 1698: * an IA in the message from the client, the
! 1699: * server MUST include the IA in the Reply
! 1700: * message with no addresses in the IA and a
! 1701: * Status Code option in the IA containing
! 1702: * status code NoAddrsAvail.
! 1703: */
! 1704: option_state_dereference(&reply->reply_ia, MDL);
! 1705: if (!option_state_allocate(&reply->reply_ia,
! 1706: MDL))
! 1707: {
! 1708: log_error("reply_process_ia_na: No "
! 1709: "memory for option state "
! 1710: "wipe.");
! 1711: status = ISC_R_NOMEMORY;
! 1712: goto cleanup;
! 1713: }
! 1714:
! 1715: if (!set_status_code(STATUS_NoAddrsAvail,
! 1716: "No addresses available "
! 1717: "for this interface.",
! 1718: reply->reply_ia)) {
! 1719: log_error("reply_process_ia_na: Unable "
! 1720: "to set NoAddrsAvail status "
! 1721: "code.");
! 1722: status = ISC_R_FAILURE;
! 1723: goto cleanup;
! 1724: }
! 1725:
! 1726: status = ISC_R_SUCCESS;
! 1727: break;
! 1728:
! 1729: default:
! 1730: /*
! 1731: * RFC 3315 does not tell us to emit a status
! 1732: * code in this condition, or anything else.
! 1733: *
! 1734: * If we included non-allocated addresses
! 1735: * (zeroed lifetimes) in an IA, then the client
! 1736: * will deconfigure them.
! 1737: *
! 1738: * So we want to include the IA even if we
! 1739: * can't give it a new address if it includes
! 1740: * zeroed lifetime addresses.
! 1741: *
! 1742: * We don't want to include the IA if we
! 1743: * provide zero addresses including zeroed
! 1744: * lifetimes.
! 1745: */
! 1746: if (reply->resources_included)
! 1747: status = ISC_R_SUCCESS;
! 1748: else
! 1749: goto cleanup;
! 1750: break;
! 1751: }
! 1752: }
! 1753:
! 1754: if (status != ISC_R_SUCCESS)
! 1755: goto cleanup;
! 1756: }
! 1757:
! 1758: reply->cursor += store_options6((char *)reply->buf.data + reply->cursor,
! 1759: sizeof(reply->buf) - reply->cursor,
! 1760: reply->reply_ia, reply->packet,
! 1761: required_opts_IA, NULL);
! 1762:
! 1763: /* Reset the length of this IA to match what was just written. */
! 1764: putUShort(reply->buf.data + ia_cursor + 2,
! 1765: reply->cursor - (ia_cursor + 4));
! 1766:
! 1767: /*
! 1768: * T1/T2 time selection is kind of weird. We actually use DHCP
! 1769: * (v4) scoped options as handy existing places where these might
! 1770: * be configured by an administrator. A value of zero tells the
! 1771: * client it may choose its own renewal time.
! 1772: */
! 1773: reply->renew = 0;
! 1774: oc = lookup_option(&dhcp_universe, reply->opt_state,
! 1775: DHO_DHCP_RENEWAL_TIME);
! 1776: if (oc != NULL) {
! 1777: if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
! 1778: reply->packet->options,
! 1779: reply->opt_state, &global_scope,
! 1780: oc, MDL) ||
! 1781: (data.len != 4)) {
! 1782: log_error("Invalid renewal time.");
! 1783: } else {
! 1784: reply->renew = getULong(data.data);
! 1785: }
! 1786:
! 1787: if (data.data != NULL)
! 1788: data_string_forget(&data, MDL);
! 1789: }
! 1790: putULong(reply->buf.data + ia_cursor + 8, reply->renew);
! 1791:
! 1792: /* Now T2. */
! 1793: reply->rebind = 0;
! 1794: oc = lookup_option(&dhcp_universe, reply->opt_state,
! 1795: DHO_DHCP_REBINDING_TIME);
! 1796: if (oc != NULL) {
! 1797: if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
! 1798: reply->packet->options,
! 1799: reply->opt_state, &global_scope,
! 1800: oc, MDL) ||
! 1801: (data.len != 4)) {
! 1802: log_error("Invalid rebinding time.");
! 1803: } else {
! 1804: reply->rebind = getULong(data.data);
! 1805: }
! 1806:
! 1807: if (data.data != NULL)
! 1808: data_string_forget(&data, MDL);
! 1809: }
! 1810: putULong(reply->buf.data + ia_cursor + 12, reply->rebind);
! 1811:
! 1812: /*
! 1813: * If this is not a 'soft' binding, consume the new changes into
! 1814: * the database (if any have been attached to the ia_na).
! 1815: *
! 1816: * Loop through the assigned dynamic addresses, referencing the
! 1817: * leases onto this IA_NA rather than any old ones, and updating
! 1818: * pool timers for each (if any).
! 1819: */
! 1820: if ((status != ISC_R_CANCELED) && !reply->static_lease &&
! 1821: (reply->buf.reply.msg_type == DHCPV6_REPLY) &&
! 1822: (reply->ia->num_iasubopt != 0)) {
! 1823: struct iasubopt *tmp;
! 1824: struct data_string *ia_id;
! 1825: int i;
! 1826:
! 1827: for (i = 0 ; i < reply->ia->num_iasubopt ; i++) {
! 1828: tmp = reply->ia->iasubopt[i];
! 1829:
! 1830: if (tmp->ia != NULL)
! 1831: ia_dereference(&tmp->ia, MDL);
! 1832: ia_reference(&tmp->ia, reply->ia, MDL);
! 1833:
! 1834: /* Commit 'hard' bindings. */
! 1835: tmp->hard_lifetime_end_time =
! 1836: tmp->soft_lifetime_end_time;
! 1837: tmp->soft_lifetime_end_time = 0;
! 1838: renew_lease6(tmp->ipv6_pool, tmp);
! 1839: schedule_lease_timeout(tmp->ipv6_pool);
! 1840:
! 1841: /*
! 1842: * Perform ddns updates.
! 1843: */
! 1844: oc = lookup_option(&server_universe, reply->opt_state,
! 1845: SV_DDNS_UPDATES);
! 1846: if ((oc == NULL) ||
! 1847: evaluate_boolean_option_cache(NULL, reply->packet,
! 1848: NULL, NULL,
! 1849: reply->packet->options,
! 1850: reply->opt_state,
! 1851: &tmp->scope,
! 1852: oc, MDL)) {
! 1853: ddns_updates(reply->packet, NULL, NULL,
! 1854: tmp, NULL, reply->opt_state);
! 1855: }
! 1856: }
! 1857:
! 1858: /* Remove any old ia from the hash. */
! 1859: if (reply->old_ia != NULL) {
! 1860: ia_id = &reply->old_ia->iaid_duid;
! 1861: ia_hash_delete(ia_na_active,
! 1862: (unsigned char *)ia_id->data,
! 1863: ia_id->len, MDL);
! 1864: ia_dereference(&reply->old_ia, MDL);
! 1865: }
! 1866:
! 1867: /* Put new ia into the hash. */
! 1868: reply->ia->cltt = cur_time;
! 1869: ia_id = &reply->ia->iaid_duid;
! 1870: ia_hash_add(ia_na_active, (unsigned char *)ia_id->data,
! 1871: ia_id->len, reply->ia, MDL);
! 1872:
! 1873: write_ia(reply->ia);
! 1874: }
! 1875:
! 1876: cleanup:
! 1877: if (packet_ia != NULL)
! 1878: option_state_dereference(&packet_ia, MDL);
! 1879: if (reply->reply_ia != NULL)
! 1880: option_state_dereference(&reply->reply_ia, MDL);
! 1881: if (ia_data.data != NULL)
! 1882: data_string_forget(&ia_data, MDL);
! 1883: if (data.data != NULL)
! 1884: data_string_forget(&data, MDL);
! 1885: if (reply->ia != NULL)
! 1886: ia_dereference(&reply->ia, MDL);
! 1887: if (reply->old_ia != NULL)
! 1888: ia_dereference(&reply->old_ia, MDL);
! 1889: if (reply->lease != NULL)
! 1890: iasubopt_dereference(&reply->lease, MDL);
! 1891: if (reply->fixed.data != NULL)
! 1892: data_string_forget(&reply->fixed, MDL);
! 1893: if (reply->subnet != NULL)
! 1894: subnet_dereference(&reply->subnet, MDL);
! 1895:
! 1896: /*
! 1897: * ISC_R_CANCELED is a status code used by the addr processing to
! 1898: * indicate we're replying with a status code. This is still a
! 1899: * success at higher layers.
! 1900: */
! 1901: return((status == ISC_R_CANCELED) ? ISC_R_SUCCESS : status);
! 1902: }
! 1903:
! 1904: /*
! 1905: * Process an IAADDR within a given IA_xA, storing any IAADDR reply contents
! 1906: * into the reply's current ia-scoped option cache. Returns ISC_R_CANCELED
! 1907: * in the event we are replying with a status code and do not wish to process
! 1908: * more IAADDRs within this IA.
! 1909: */
! 1910: static isc_result_t
! 1911: reply_process_addr(struct reply_state *reply, struct option_cache *addr) {
! 1912: u_int32_t pref_life, valid_life;
! 1913: struct binding_scope **scope;
! 1914: struct group *group;
! 1915: struct subnet *subnet;
! 1916: struct iaddr tmp_addr;
! 1917: struct option_cache *oc;
! 1918: struct data_string iaaddr, data;
! 1919: isc_result_t status = ISC_R_SUCCESS;
! 1920:
! 1921: /* Initializes values that will be cleaned up. */
! 1922: memset(&iaaddr, 0, sizeof(iaaddr));
! 1923: memset(&data, 0, sizeof(data));
! 1924: /* Note that reply->lease may be set by address_is_owned() */
! 1925:
! 1926: /*
! 1927: * There is no point trying to process an incoming address if there
! 1928: * is no room for an outgoing address.
! 1929: */
! 1930: if ((reply->cursor + 28) > sizeof(reply->buf)) {
! 1931: log_error("reply_process_addr: Out of room for address.");
! 1932: return ISC_R_NOSPACE;
! 1933: }
! 1934:
! 1935: /* Extract this IAADDR option. */
! 1936: if (!evaluate_option_cache(&iaaddr, reply->packet, NULL, NULL,
! 1937: reply->packet->options, NULL, &global_scope,
! 1938: addr, MDL) ||
! 1939: (iaaddr.len < IAADDR_OFFSET)) {
! 1940: log_error("reply_process_addr: error evaluating IAADDR.");
! 1941: status = ISC_R_FAILURE;
! 1942: goto cleanup;
! 1943: }
! 1944:
! 1945: /* The first 16 bytes are the IPv6 address. */
! 1946: pref_life = getULong(iaaddr.data + 16);
! 1947: valid_life = getULong(iaaddr.data + 20);
! 1948:
! 1949: if ((reply->client_valid == 0) ||
! 1950: (reply->client_valid > valid_life))
! 1951: reply->client_valid = valid_life;
! 1952:
! 1953: if ((reply->client_prefer == 0) ||
! 1954: (reply->client_prefer > pref_life))
! 1955: reply->client_prefer = pref_life;
! 1956:
! 1957: /*
! 1958: * Clients may choose to send :: as an address, with the idea to give
! 1959: * hints about preferred-lifetime or valid-lifetime.
! 1960: */
! 1961: tmp_addr.len = 16;
! 1962: memset(tmp_addr.iabuf, 0, 16);
! 1963: if (!memcmp(iaaddr.data, tmp_addr.iabuf, 16)) {
! 1964: /* Status remains success; we just ignore this one. */
! 1965: goto cleanup;
! 1966: }
! 1967:
! 1968: /* tmp_addr len remains 16 */
! 1969: memcpy(tmp_addr.iabuf, iaaddr.data, 16);
! 1970:
! 1971: /*
! 1972: * Verify that this address is on the client's network.
! 1973: */
! 1974: for (subnet = reply->shared->subnets ; subnet != NULL ;
! 1975: subnet = subnet->next_sibling) {
! 1976: if (addr_eq(subnet_number(tmp_addr, subnet->netmask),
! 1977: subnet->net))
! 1978: break;
! 1979: }
! 1980:
! 1981: /* Address not found on shared network. */
! 1982: if (subnet == NULL) {
! 1983: /* Ignore this address on 'soft' bindings. */
! 1984: if (reply->packet->dhcpv6_msg_type == DHCPV6_SOLICIT) {
! 1985: /* disable rapid commit */
! 1986: reply->buf.reply.msg_type = DHCPV6_ADVERTISE;
! 1987: delete_option(&dhcpv6_universe,
! 1988: reply->opt_state,
! 1989: D6O_RAPID_COMMIT);
! 1990: /* status remains success */
! 1991: goto cleanup;
! 1992: }
! 1993:
! 1994: /*
! 1995: * RFC3315 section 18.2.1:
! 1996: *
! 1997: * If the server finds that the prefix on one or more IP
! 1998: * addresses in any IA in the message from the client is not
! 1999: * appropriate for the link to which the client is connected,
! 2000: * the server MUST return the IA to the client with a Status
! 2001: * Code option with the value NotOnLink.
! 2002: */
! 2003: if (reply->packet->dhcpv6_msg_type == DHCPV6_REQUEST) {
! 2004: /* Rewind the IA_NA to empty. */
! 2005: option_state_dereference(&reply->reply_ia, MDL);
! 2006: if (!option_state_allocate(&reply->reply_ia, MDL)) {
! 2007: log_error("reply_process_addr: No memory for "
! 2008: "option state wipe.");
! 2009: status = ISC_R_NOMEMORY;
! 2010: goto cleanup;
! 2011: }
! 2012:
! 2013: /* Append a NotOnLink status code. */
! 2014: if (!set_status_code(STATUS_NotOnLink,
! 2015: "Address not for use on this "
! 2016: "link.", reply->reply_ia)) {
! 2017: log_error("reply_process_addr: Failure "
! 2018: "setting status code.");
! 2019: status = ISC_R_FAILURE;
! 2020: goto cleanup;
! 2021: }
! 2022:
! 2023: /* Fin (no more IAADDRs). */
! 2024: status = ISC_R_CANCELED;
! 2025: goto cleanup;
! 2026: }
! 2027:
! 2028: /*
! 2029: * RFC3315 sections 18.2.3 and 18.2.4 have identical language:
! 2030: *
! 2031: * If the server finds that any of the addresses are not
! 2032: * appropriate for the link to which the client is attached,
! 2033: * the server returns the address to the client with lifetimes
! 2034: * of 0.
! 2035: */
! 2036: if ((reply->packet->dhcpv6_msg_type != DHCPV6_RENEW) &&
! 2037: (reply->packet->dhcpv6_msg_type != DHCPV6_REBIND)) {
! 2038: log_error("It is impossible to lease a client that is "
! 2039: "not sending a solicit, request, renew, or "
! 2040: "rebind.");
! 2041: status = ISC_R_FAILURE;
! 2042: goto cleanup;
! 2043: }
! 2044:
! 2045: reply->send_prefer = reply->send_valid = 0;
! 2046: goto send_addr;
! 2047: }
! 2048:
! 2049: /* Verify the address belongs to the client. */
! 2050: if (!address_is_owned(reply, &tmp_addr)) {
! 2051: /*
! 2052: * For solicit and request, any addresses included are
! 2053: * 'requested' addresses. For rebind, we actually have
! 2054: * no direction on what to do from 3315 section 18.2.4!
! 2055: * So I think the best bet is to try and give it out, and if
! 2056: * we can't, zero lifetimes.
! 2057: */
! 2058: if ((reply->packet->dhcpv6_msg_type == DHCPV6_SOLICIT) ||
! 2059: (reply->packet->dhcpv6_msg_type == DHCPV6_REQUEST) ||
! 2060: (reply->packet->dhcpv6_msg_type == DHCPV6_REBIND)) {
! 2061: status = reply_process_try_addr(reply, &tmp_addr);
! 2062:
! 2063: /*
! 2064: * If the address is in use, or isn't in any dynamic
! 2065: * range, continue as normal. If any other error was
! 2066: * found, error out.
! 2067: */
! 2068: if ((status != ISC_R_SUCCESS) &&
! 2069: (status != ISC_R_ADDRINUSE) &&
! 2070: (status != ISC_R_ADDRNOTAVAIL))
! 2071: goto cleanup;
! 2072:
! 2073: /*
! 2074: * If we didn't honor this lease, for solicit and
! 2075: * request we simply omit it from our answer. For
! 2076: * rebind, we send it with zeroed lifetimes.
! 2077: */
! 2078: if (reply->lease == NULL) {
! 2079: if (reply->packet->dhcpv6_msg_type ==
! 2080: DHCPV6_REBIND) {
! 2081: reply->send_prefer = 0;
! 2082: reply->send_valid = 0;
! 2083: goto send_addr;
! 2084: }
! 2085:
! 2086: /* status remains success - ignore */
! 2087: goto cleanup;
! 2088: }
! 2089: /*
! 2090: * RFC3315 section 18.2.3:
! 2091: *
! 2092: * If the server cannot find a client entry for the IA the
! 2093: * server returns the IA containing no addresses with a Status
! 2094: * Code option set to NoBinding in the Reply message.
! 2095: *
! 2096: * On mismatch we (ab)use this pretending we have not the IA
! 2097: * as soon as we have not an address.
! 2098: */
! 2099: } else if (reply->packet->dhcpv6_msg_type == DHCPV6_RENEW) {
! 2100: /* Rewind the IA_NA to empty. */
! 2101: option_state_dereference(&reply->reply_ia, MDL);
! 2102: if (!option_state_allocate(&reply->reply_ia, MDL)) {
! 2103: log_error("reply_process_addr: No memory for "
! 2104: "option state wipe.");
! 2105: status = ISC_R_NOMEMORY;
! 2106: goto cleanup;
! 2107: }
! 2108:
! 2109: /* Append a NoBinding status code. */
! 2110: if (!set_status_code(STATUS_NoBinding,
! 2111: "Address not bound to this "
! 2112: "interface.", reply->reply_ia)) {
! 2113: log_error("reply_process_addr: Unable to "
! 2114: "attach status code.");
! 2115: status = ISC_R_FAILURE;
! 2116: goto cleanup;
! 2117: }
! 2118:
! 2119: /* Fin (no more IAADDRs). */
! 2120: status = ISC_R_CANCELED;
! 2121: goto cleanup;
! 2122: } else {
! 2123: log_error("It is impossible to lease a client that is "
! 2124: "not sending a solicit, request, renew, or "
! 2125: "rebind message.");
! 2126: status = ISC_R_FAILURE;
! 2127: goto cleanup;
! 2128: }
! 2129: }
! 2130:
! 2131: if (reply->static_lease) {
! 2132: if (reply->host == NULL)
! 2133: log_fatal("Impossible condition at %s:%d.", MDL);
! 2134:
! 2135: scope = &global_scope;
! 2136: group = reply->subnet->group;
! 2137: } else {
! 2138: if (reply->lease == NULL)
! 2139: log_fatal("Impossible condition at %s:%d.", MDL);
! 2140:
! 2141: scope = &reply->lease->scope;
! 2142: group = reply->lease->ipv6_pool->subnet->group;
! 2143: }
! 2144:
! 2145: /*
! 2146: * If client_resources is nonzero, then the reply_process_is_addressed
! 2147: * function has executed configuration state into the reply option
! 2148: * cache. We will use that valid cache to derive configuration for
! 2149: * whether or not to engage in additional addresses, and similar.
! 2150: */
! 2151: if (reply->client_resources != 0) {
! 2152: unsigned limit = 1;
! 2153:
! 2154: /*
! 2155: * Does this client have "enough" addresses already? Default
! 2156: * to one. Everybody gets one, and one should be enough for
! 2157: * anybody.
! 2158: */
! 2159: oc = lookup_option(&server_universe, reply->opt_state,
! 2160: SV_LIMIT_ADDRS_PER_IA);
! 2161: if (oc != NULL) {
! 2162: if (!evaluate_option_cache(&data, reply->packet,
! 2163: NULL, NULL,
! 2164: reply->packet->options,
! 2165: reply->opt_state,
! 2166: scope, oc, MDL) ||
! 2167: (data.len != 4)) {
! 2168: log_error("reply_process_addr: unable to "
! 2169: "evaluate addrs-per-ia value.");
! 2170: status = ISC_R_FAILURE;
! 2171: goto cleanup;
! 2172: }
! 2173:
! 2174: limit = getULong(data.data);
! 2175: data_string_forget(&data, MDL);
! 2176: }
! 2177:
! 2178: /*
! 2179: * If we wish to limit the client to a certain number of
! 2180: * addresses, then omit the address from the reply.
! 2181: */
! 2182: if (reply->client_resources >= limit)
! 2183: goto cleanup;
! 2184: }
! 2185:
! 2186: status = reply_process_is_addressed(reply, scope, group);
! 2187: if (status != ISC_R_SUCCESS)
! 2188: goto cleanup;
! 2189:
! 2190: send_addr:
! 2191: status = reply_process_send_addr(reply, &tmp_addr);
! 2192:
! 2193: cleanup:
! 2194: if (iaaddr.data != NULL)
! 2195: data_string_forget(&iaaddr, MDL);
! 2196: if (data.data != NULL)
! 2197: data_string_forget(&data, MDL);
! 2198: if (reply->lease != NULL)
! 2199: iasubopt_dereference(&reply->lease, MDL);
! 2200:
! 2201: return status;
! 2202: }
! 2203:
! 2204: /*
! 2205: * Verify the address belongs to the client. If we've got a host
! 2206: * record with a fixed address, it has to be the assigned address
! 2207: * (fault out all else). Otherwise it's a dynamic address, so lookup
! 2208: * that address and make sure it belongs to this DUID:IAID pair.
! 2209: */
! 2210: static isc_boolean_t
! 2211: address_is_owned(struct reply_state *reply, struct iaddr *addr) {
! 2212: int i;
! 2213:
! 2214: /*
! 2215: * This faults out addresses that don't match fixed addresses.
! 2216: */
! 2217: if (reply->static_lease) {
! 2218: if (reply->fixed.data == NULL)
! 2219: log_fatal("Impossible condition at %s:%d.", MDL);
! 2220:
! 2221: if (memcmp(addr->iabuf, reply->fixed.data, 16) == 0)
! 2222: return ISC_TRUE;
! 2223:
! 2224: return ISC_FALSE;
! 2225: }
! 2226:
! 2227: if ((reply->old_ia == NULL) || (reply->old_ia->num_iasubopt == 0))
! 2228: return ISC_FALSE;
! 2229:
! 2230: for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
! 2231: struct iasubopt *tmp;
! 2232:
! 2233: tmp = reply->old_ia->iasubopt[i];
! 2234:
! 2235: if (memcmp(addr->iabuf, &tmp->addr, 16) == 0) {
! 2236: iasubopt_reference(&reply->lease, tmp, MDL);
! 2237: return ISC_TRUE;
! 2238: }
! 2239: }
! 2240:
! 2241: return ISC_FALSE;
! 2242: }
! 2243:
! 2244: /* Process a client-supplied IA_TA. This may append options to the tail of
! 2245: * the reply packet being built in the reply_state structure.
! 2246: */
! 2247: static isc_result_t
! 2248: reply_process_ia_ta(struct reply_state *reply, struct option_cache *ia) {
! 2249: isc_result_t status = ISC_R_SUCCESS;
! 2250: u_int32_t iaid;
! 2251: unsigned ia_cursor;
! 2252: struct option_state *packet_ia;
! 2253: struct option_cache *oc;
! 2254: struct data_string ia_data, data;
! 2255: struct data_string iaaddr;
! 2256: u_int32_t pref_life, valid_life;
! 2257: struct iaddr tmp_addr;
! 2258:
! 2259: /* Initialize values that will get cleaned up on return. */
! 2260: packet_ia = NULL;
! 2261: memset(&ia_data, 0, sizeof(ia_data));
! 2262: memset(&data, 0, sizeof(data));
! 2263: memset(&iaaddr, 0, sizeof(iaaddr));
! 2264:
! 2265: /* Make sure there is at least room for the header. */
! 2266: if ((reply->cursor + IA_TA_OFFSET + 4) > sizeof(reply->buf)) {
! 2267: log_error("reply_process_ia_ta: Reply too long for IA.");
! 2268: return ISC_R_NOSPACE;
! 2269: }
! 2270:
! 2271:
! 2272: /* Fetch the IA_TA contents. */
! 2273: if (!get_encapsulated_IA_state(&packet_ia, &ia_data, reply->packet,
! 2274: ia, IA_TA_OFFSET)) {
! 2275: log_error("reply_process_ia_ta: error evaluating ia");
! 2276: status = ISC_R_FAILURE;
! 2277: goto cleanup;
! 2278: }
! 2279:
! 2280: /* Extract IA_TA header contents. */
! 2281: iaid = getULong(ia_data.data);
! 2282:
! 2283: /* Create an IA_TA structure. */
! 2284: if (ia_allocate(&reply->ia, iaid, (char *)reply->client_id.data,
! 2285: reply->client_id.len, MDL) != ISC_R_SUCCESS) {
! 2286: log_error("reply_process_ia_ta: no memory for ia.");
! 2287: status = ISC_R_NOMEMORY;
! 2288: goto cleanup;
! 2289: }
! 2290: reply->ia->ia_type = D6O_IA_TA;
! 2291:
! 2292: /* Cache pre-existing IA, if any. */
! 2293: ia_hash_lookup(&reply->old_ia, ia_ta_active,
! 2294: (unsigned char *)reply->ia->iaid_duid.data,
! 2295: reply->ia->iaid_duid.len, MDL);
! 2296:
! 2297: /*
! 2298: * Create an option cache to carry the IA_TA option contents, and
! 2299: * execute any user-supplied values into it.
! 2300: */
! 2301: if (!option_state_allocate(&reply->reply_ia, MDL)) {
! 2302: status = ISC_R_NOMEMORY;
! 2303: goto cleanup;
! 2304: }
! 2305:
! 2306: /*
! 2307: * Temporary leases are dynamic by definition.
! 2308: */
! 2309: reply->static_lease = ISC_FALSE;
! 2310:
! 2311: /*
! 2312: * Save the cursor position at the start of the IA, so we can
! 2313: * set length later. We write a temporary
! 2314: * header out now just in case we decide to adjust the packet
! 2315: * within sub-process functions.
! 2316: */
! 2317: ia_cursor = reply->cursor;
! 2318:
! 2319: /* Initialize the IA_TA header. First the code. */
! 2320: putUShort(reply->buf.data + reply->cursor, (unsigned)D6O_IA_TA);
! 2321: reply->cursor += 2;
! 2322:
! 2323: /* Then option length. */
! 2324: putUShort(reply->buf.data + reply->cursor, 0x04u);
! 2325: reply->cursor += 2;
! 2326:
! 2327: /* Then IA_TA header contents; IAID. */
! 2328: putULong(reply->buf.data + reply->cursor, iaid);
! 2329: reply->cursor += 4;
! 2330:
! 2331: /*
! 2332: * Deal with an IAADDR for lifetimes.
! 2333: * For all or none, process IAADDRs as hints.
! 2334: */
! 2335: reply->valid = reply->prefer = 0xffffffff;
! 2336: reply->client_valid = reply->client_prefer = 0;
! 2337: oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAADDR);
! 2338: for (; oc != NULL; oc = oc->next) {
! 2339: memset(&iaaddr, 0, sizeof(iaaddr));
! 2340: if (!evaluate_option_cache(&iaaddr, reply->packet,
! 2341: NULL, NULL,
! 2342: reply->packet->options, NULL,
! 2343: &global_scope, oc, MDL) ||
! 2344: (iaaddr.len < IAADDR_OFFSET)) {
! 2345: log_error("reply_process_ia_ta: error "
! 2346: "evaluating IAADDR.");
! 2347: status = ISC_R_FAILURE;
! 2348: goto cleanup;
! 2349: }
! 2350: /* The first 16 bytes are the IPv6 address. */
! 2351: pref_life = getULong(iaaddr.data + 16);
! 2352: valid_life = getULong(iaaddr.data + 20);
! 2353:
! 2354: if ((reply->client_valid == 0) ||
! 2355: (reply->client_valid > valid_life))
! 2356: reply->client_valid = valid_life;
! 2357:
! 2358: if ((reply->client_prefer == 0) ||
! 2359: (reply->client_prefer > pref_life))
! 2360: reply->client_prefer = pref_life;
! 2361:
! 2362: /* Nothing more if something has failed. */
! 2363: if (status == ISC_R_CANCELED)
! 2364: continue;
! 2365:
! 2366: tmp_addr.len = 16;
! 2367: memcpy(tmp_addr.iabuf, iaaddr.data, 16);
! 2368: if (!temporary_is_available(reply, &tmp_addr))
! 2369: goto bad_temp;
! 2370: status = reply_process_is_addressed(reply,
! 2371: &reply->lease->scope,
! 2372: reply->shared->group);
! 2373: if (status != ISC_R_SUCCESS)
! 2374: goto bad_temp;
! 2375: status = reply_process_send_addr(reply, &tmp_addr);
! 2376: if (status != ISC_R_SUCCESS)
! 2377: goto bad_temp;
! 2378: if (reply->lease != NULL)
! 2379: iasubopt_dereference(&reply->lease, MDL);
! 2380: continue;
! 2381:
! 2382: bad_temp:
! 2383: /* Rewind the IA_TA to empty. */
! 2384: option_state_dereference(&reply->reply_ia, MDL);
! 2385: if (!option_state_allocate(&reply->reply_ia, MDL)) {
! 2386: status = ISC_R_NOMEMORY;
! 2387: goto cleanup;
! 2388: }
! 2389: status = ISC_R_CANCELED;
! 2390: reply->client_resources = 0;
! 2391: reply->resources_included = ISC_FALSE;
! 2392: if (reply->lease != NULL)
! 2393: iasubopt_dereference(&reply->lease, MDL);
! 2394: }
! 2395: reply->ia_count++;
! 2396:
! 2397: /*
! 2398: * Give the client temporary addresses.
! 2399: */
! 2400: if (reply->client_resources != 0)
! 2401: goto store;
! 2402: status = find_client_temporaries(reply);
! 2403: if (status == ISC_R_NORESOURCES) {
! 2404: switch (reply->packet->dhcpv6_msg_type) {
! 2405: case DHCPV6_SOLICIT:
! 2406: /*
! 2407: * No address for any IA is handled
! 2408: * by the caller.
! 2409: */
! 2410: /* FALL THROUGH */
! 2411:
! 2412: case DHCPV6_REQUEST:
! 2413: /* Section 18.2.1 (Request):
! 2414: *
! 2415: * If the server cannot assign any addresses to
! 2416: * an IA in the message from the client, the
! 2417: * server MUST include the IA in the Reply
! 2418: * message with no addresses in the IA and a
! 2419: * Status Code option in the IA containing
! 2420: * status code NoAddrsAvail.
! 2421: */
! 2422: option_state_dereference(&reply->reply_ia, MDL);
! 2423: if (!option_state_allocate(&reply->reply_ia, MDL)) {
! 2424: log_error("reply_process_ia_ta: No "
! 2425: "memory for option state wipe.");
! 2426: status = ISC_R_NOMEMORY;
! 2427: goto cleanup;
! 2428: }
! 2429:
! 2430: if (!set_status_code(STATUS_NoAddrsAvail,
! 2431: "No addresses available "
! 2432: "for this interface.",
! 2433: reply->reply_ia)) {
! 2434: log_error("reply_process_ia_ta: Unable "
! 2435: "to set NoAddrsAvail status code.");
! 2436: status = ISC_R_FAILURE;
! 2437: goto cleanup;
! 2438: }
! 2439:
! 2440: status = ISC_R_SUCCESS;
! 2441: break;
! 2442:
! 2443: default:
! 2444: /*
! 2445: * We don't want to include the IA if we
! 2446: * provide zero addresses including zeroed
! 2447: * lifetimes.
! 2448: */
! 2449: if (reply->resources_included)
! 2450: status = ISC_R_SUCCESS;
! 2451: else
! 2452: goto cleanup;
! 2453: break;
! 2454: }
! 2455: } else if (status != ISC_R_SUCCESS)
! 2456: goto cleanup;
! 2457:
! 2458: store:
! 2459: reply->cursor += store_options6((char *)reply->buf.data + reply->cursor,
! 2460: sizeof(reply->buf) - reply->cursor,
! 2461: reply->reply_ia, reply->packet,
! 2462: required_opts_IA, NULL);
! 2463:
! 2464: /* Reset the length of this IA to match what was just written. */
! 2465: putUShort(reply->buf.data + ia_cursor + 2,
! 2466: reply->cursor - (ia_cursor + 4));
! 2467:
! 2468: /*
! 2469: * Consume the new changes into the database (if any have been
! 2470: * attached to the ia_ta).
! 2471: *
! 2472: * Loop through the assigned dynamic addresses, referencing the
! 2473: * leases onto this IA_TA rather than any old ones, and updating
! 2474: * pool timers for each (if any).
! 2475: */
! 2476: if ((status != ISC_R_CANCELED) &&
! 2477: (reply->buf.reply.msg_type == DHCPV6_REPLY) &&
! 2478: (reply->ia->num_iasubopt != 0)) {
! 2479: struct iasubopt *tmp;
! 2480: struct data_string *ia_id;
! 2481: int i;
! 2482:
! 2483: for (i = 0 ; i < reply->ia->num_iasubopt ; i++) {
! 2484: tmp = reply->ia->iasubopt[i];
! 2485:
! 2486: if (tmp->ia != NULL)
! 2487: ia_dereference(&tmp->ia, MDL);
! 2488: ia_reference(&tmp->ia, reply->ia, MDL);
! 2489:
! 2490: /* Commit 'hard' bindings. */
! 2491: tmp->hard_lifetime_end_time =
! 2492: tmp->soft_lifetime_end_time;
! 2493: tmp->soft_lifetime_end_time = 0;
! 2494: renew_lease6(tmp->ipv6_pool, tmp);
! 2495: schedule_lease_timeout(tmp->ipv6_pool);
! 2496:
! 2497: /*
! 2498: * Perform ddns updates.
! 2499: */
! 2500: oc = lookup_option(&server_universe, reply->opt_state,
! 2501: SV_DDNS_UPDATES);
! 2502: if ((oc == NULL) ||
! 2503: evaluate_boolean_option_cache(NULL, reply->packet,
! 2504: NULL, NULL,
! 2505: reply->packet->options,
! 2506: reply->opt_state,
! 2507: &tmp->scope,
! 2508: oc, MDL)) {
! 2509: ddns_updates(reply->packet, NULL, NULL,
! 2510: tmp, NULL, reply->opt_state);
! 2511: }
! 2512: }
! 2513:
! 2514: /* Remove any old ia from the hash. */
! 2515: if (reply->old_ia != NULL) {
! 2516: ia_id = &reply->old_ia->iaid_duid;
! 2517: ia_hash_delete(ia_ta_active,
! 2518: (unsigned char *)ia_id->data,
! 2519: ia_id->len, MDL);
! 2520: ia_dereference(&reply->old_ia, MDL);
! 2521: }
! 2522:
! 2523: /* Put new ia into the hash. */
! 2524: reply->ia->cltt = cur_time;
! 2525: ia_id = &reply->ia->iaid_duid;
! 2526: ia_hash_add(ia_ta_active, (unsigned char *)ia_id->data,
! 2527: ia_id->len, reply->ia, MDL);
! 2528:
! 2529: write_ia(reply->ia);
! 2530: }
! 2531:
! 2532: cleanup:
! 2533: if (packet_ia != NULL)
! 2534: option_state_dereference(&packet_ia, MDL);
! 2535: if (iaaddr.data != NULL)
! 2536: data_string_forget(&iaaddr, MDL);
! 2537: if (reply->reply_ia != NULL)
! 2538: option_state_dereference(&reply->reply_ia, MDL);
! 2539: if (ia_data.data != NULL)
! 2540: data_string_forget(&ia_data, MDL);
! 2541: if (data.data != NULL)
! 2542: data_string_forget(&data, MDL);
! 2543: if (reply->ia != NULL)
! 2544: ia_dereference(&reply->ia, MDL);
! 2545: if (reply->old_ia != NULL)
! 2546: ia_dereference(&reply->old_ia, MDL);
! 2547: if (reply->lease != NULL)
! 2548: iasubopt_dereference(&reply->lease, MDL);
! 2549:
! 2550: /*
! 2551: * ISC_R_CANCELED is a status code used by the addr processing to
! 2552: * indicate we're replying with other addresses. This is still a
! 2553: * success at higher layers.
! 2554: */
! 2555: return((status == ISC_R_CANCELED) ? ISC_R_SUCCESS : status);
! 2556: }
! 2557:
! 2558: /*
! 2559: * Verify the temporary address is available.
! 2560: */
! 2561: static isc_boolean_t
! 2562: temporary_is_available(struct reply_state *reply, struct iaddr *addr) {
! 2563: struct in6_addr tmp_addr;
! 2564: struct subnet *subnet;
! 2565: struct ipv6_pool *pool;
! 2566: int i;
! 2567:
! 2568: memcpy(&tmp_addr, addr->iabuf, sizeof(tmp_addr));
! 2569: /*
! 2570: * Clients may choose to send :: as an address, with the idea to give
! 2571: * hints about preferred-lifetime or valid-lifetime.
! 2572: * So this is not a request for this address.
! 2573: */
! 2574: if (IN6_IS_ADDR_UNSPECIFIED(&tmp_addr))
! 2575: return ISC_FALSE;
! 2576:
! 2577: /*
! 2578: * Verify that this address is on the client's network.
! 2579: */
! 2580: for (subnet = reply->shared->subnets ; subnet != NULL ;
! 2581: subnet = subnet->next_sibling) {
! 2582: if (addr_eq(subnet_number(*addr, subnet->netmask),
! 2583: subnet->net))
! 2584: break;
! 2585: }
! 2586:
! 2587: /* Address not found on shared network. */
! 2588: if (subnet == NULL)
! 2589: return ISC_FALSE;
! 2590:
! 2591: /*
! 2592: * Check if this address is owned (must be before next step).
! 2593: */
! 2594: if (address_is_owned(reply, addr))
! 2595: return ISC_TRUE;
! 2596:
! 2597: /*
! 2598: * Verify that this address is in a temporary pool and try to get it.
! 2599: */
! 2600: if (reply->shared->ipv6_pools == NULL)
! 2601: return ISC_FALSE;
! 2602: for (i = 0 ; (pool = reply->shared->ipv6_pools[i]) != NULL ; i++) {
! 2603: if (pool->pool_type != D6O_IA_TA)
! 2604: continue;
! 2605: if (ipv6_in_pool(&tmp_addr, pool))
! 2606: break;
! 2607: }
! 2608: if (pool == NULL)
! 2609: return ISC_FALSE;
! 2610: if (lease6_exists(pool, &tmp_addr))
! 2611: return ISC_FALSE;
! 2612: if (iasubopt_allocate(&reply->lease, MDL) != ISC_R_SUCCESS)
! 2613: return ISC_FALSE;
! 2614: reply->lease->addr = tmp_addr;
! 2615: reply->lease->plen = 0;
! 2616: /* Default is soft binding for 2 minutes. */
! 2617: if (add_lease6(pool, reply->lease, cur_time + 120) != ISC_R_SUCCESS)
! 2618: return ISC_FALSE;
! 2619:
! 2620: return ISC_TRUE;
! 2621: }
! 2622:
! 2623: /*
! 2624: * Get a temporary address per prefix.
! 2625: */
! 2626: static isc_result_t
! 2627: find_client_temporaries(struct reply_state *reply) {
! 2628: struct shared_network *shared;
! 2629: int i;
! 2630: struct ipv6_pool *p;
! 2631: isc_result_t status;
! 2632: unsigned int attempts;
! 2633: struct iaddr send_addr;
! 2634:
! 2635: /*
! 2636: * No pools, we're done.
! 2637: */
! 2638: shared = reply->shared;
! 2639: if (shared->ipv6_pools == NULL) {
! 2640: log_debug("Unable to get client addresses: "
! 2641: "no IPv6 pools on this shared network");
! 2642: return ISC_R_NORESOURCES;
! 2643: }
! 2644:
! 2645: status = ISC_R_NORESOURCES;
! 2646: for (i = 0;; i++) {
! 2647: p = shared->ipv6_pools[i];
! 2648: if (p == NULL) {
! 2649: break;
! 2650: }
! 2651: if (p->pool_type != D6O_IA_TA) {
! 2652: continue;
! 2653: }
! 2654:
! 2655: /*
! 2656: * Get an address in this temporary pool.
! 2657: */
! 2658: status = create_lease6(p, &reply->lease, &attempts,
! 2659: &reply->client_id, cur_time + 120);
! 2660: if (status != ISC_R_SUCCESS) {
! 2661: log_debug("Unable to get a temporary address.");
! 2662: goto cleanup;
! 2663: }
! 2664:
! 2665: status = reply_process_is_addressed(reply,
! 2666: &reply->lease->scope,
! 2667: reply->lease->ipv6_pool->subnet->group);
! 2668: if (status != ISC_R_SUCCESS) {
! 2669: goto cleanup;
! 2670: }
! 2671: send_addr.len = 16;
! 2672: memcpy(send_addr.iabuf, &reply->lease->addr, 16);
! 2673: status = reply_process_send_addr(reply, &send_addr);
! 2674: if (status != ISC_R_SUCCESS) {
! 2675: goto cleanup;
! 2676: }
! 2677: if (reply->lease != NULL) {
! 2678: iasubopt_dereference(&reply->lease, MDL);
! 2679: }
! 2680: }
! 2681:
! 2682: cleanup:
! 2683: if (reply->lease != NULL) {
! 2684: iasubopt_dereference(&reply->lease, MDL);
! 2685: }
! 2686: return status;
! 2687: }
! 2688:
! 2689: /*
! 2690: * This function only returns failure on 'hard' failures. If it succeeds,
! 2691: * it will leave a lease structure behind.
! 2692: */
! 2693: static isc_result_t
! 2694: reply_process_try_addr(struct reply_state *reply, struct iaddr *addr) {
! 2695: isc_result_t status = ISC_R_NORESOURCES;
! 2696: struct ipv6_pool *pool;
! 2697: int i;
! 2698: struct data_string data_addr;
! 2699:
! 2700: if ((reply == NULL) || (reply->shared == NULL) ||
! 2701: (reply->shared->ipv6_pools == NULL) || (addr == NULL) ||
! 2702: (reply->lease != NULL))
! 2703: return ISC_R_INVALIDARG;
! 2704:
! 2705: memset(&data_addr, 0, sizeof(data_addr));
! 2706: data_addr.len = addr->len;
! 2707: data_addr.data = addr->iabuf;
! 2708:
! 2709: for (i = 0 ; (pool = reply->shared->ipv6_pools[i]) != NULL ; i++) {
! 2710: if (pool->pool_type != D6O_IA_NA)
! 2711: continue;
! 2712: status = try_client_v6_address(&reply->lease, pool,
! 2713: &data_addr);
! 2714: if (status == ISC_R_SUCCESS)
! 2715: break;
! 2716: }
! 2717:
! 2718: /* Note that this is just pedantry. There is no allocation to free. */
! 2719: data_string_forget(&data_addr, MDL);
! 2720: /* Return just the most recent status... */
! 2721: return status;
! 2722: }
! 2723:
! 2724: /* Look around for an address to give the client. First, look through the
! 2725: * old IA for addresses we can extend. Second, try to allocate a new address.
! 2726: * Finally, actually add that address into the current reply IA.
! 2727: */
! 2728: static isc_result_t
! 2729: find_client_address(struct reply_state *reply) {
! 2730: struct iaddr send_addr;
! 2731: isc_result_t status = ISC_R_NORESOURCES;
! 2732: struct iasubopt *lease, *best_lease = NULL;
! 2733: struct binding_scope **scope;
! 2734: struct group *group;
! 2735: int i;
! 2736:
! 2737: if (reply->static_lease) {
! 2738: if (reply->host == NULL)
! 2739: return ISC_R_INVALIDARG;
! 2740:
! 2741: send_addr.len = 16;
! 2742: memcpy(send_addr.iabuf, reply->fixed.data, 16);
! 2743:
! 2744: status = ISC_R_SUCCESS;
! 2745: scope = &global_scope;
! 2746: group = reply->subnet->group;
! 2747: goto send_addr;
! 2748: }
! 2749:
! 2750: if (reply->old_ia != NULL) {
! 2751: for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
! 2752: struct shared_network *candidate_shared;
! 2753:
! 2754: lease = reply->old_ia->iasubopt[i];
! 2755: candidate_shared = lease->ipv6_pool->shared_network;
! 2756:
! 2757: /*
! 2758: * Look for the best lease on the client's shared
! 2759: * network.
! 2760: */
! 2761: if (candidate_shared == reply->shared) {
! 2762: best_lease = lease_compare(lease, best_lease);
! 2763: }
! 2764: }
! 2765: }
! 2766:
! 2767: /* Try to pick a new address if we didn't find one, or if we found an
! 2768: * abandoned lease.
! 2769: */
! 2770: if ((best_lease == NULL) || (best_lease->state == FTS_ABANDONED)) {
! 2771: status = pick_v6_address(&reply->lease, reply->shared,
! 2772: &reply->client_id);
! 2773: } else if (best_lease != NULL) {
! 2774: iasubopt_reference(&reply->lease, best_lease, MDL);
! 2775: status = ISC_R_SUCCESS;
! 2776: }
! 2777:
! 2778: /* Pick the abandoned lease as a last resort. */
! 2779: if ((status == ISC_R_NORESOURCES) && (best_lease != NULL)) {
! 2780: /* I don't see how this is supposed to be done right now. */
! 2781: log_error("Reclaiming abandoned addresses is not yet "
! 2782: "supported. Treating this as an out of space "
! 2783: "condition.");
! 2784: /* iasubopt_reference(&reply->lease, best_lease, MDL); */
! 2785: }
! 2786:
! 2787: /* Give up now if we didn't find a lease. */
! 2788: if (status != ISC_R_SUCCESS)
! 2789: return status;
! 2790:
! 2791: if (reply->lease == NULL)
! 2792: log_fatal("Impossible condition at %s:%d.", MDL);
! 2793:
! 2794: /* Draw binding scopes from the lease's binding scope, and config
! 2795: * from the lease's containing subnet and higher. Note that it may
! 2796: * be desirable to place the group attachment directly in the pool.
! 2797: */
! 2798: scope = &reply->lease->scope;
! 2799: group = reply->lease->ipv6_pool->subnet->group;
! 2800:
! 2801: send_addr.len = 16;
! 2802: memcpy(send_addr.iabuf, &reply->lease->addr, 16);
! 2803:
! 2804: send_addr:
! 2805: status = reply_process_is_addressed(reply, scope, group);
! 2806: if (status != ISC_R_SUCCESS)
! 2807: return status;
! 2808:
! 2809: status = reply_process_send_addr(reply, &send_addr);
! 2810: return status;
! 2811: }
! 2812:
! 2813: /* Once an address is found for a client, perform several common functions;
! 2814: * Calculate and store valid and preferred lease times, draw client options
! 2815: * into the option state.
! 2816: */
! 2817: static isc_result_t
! 2818: reply_process_is_addressed(struct reply_state *reply,
! 2819: struct binding_scope **scope, struct group *group)
! 2820: {
! 2821: isc_result_t status = ISC_R_SUCCESS;
! 2822: struct data_string data;
! 2823: struct option_cache *oc;
! 2824:
! 2825: /* Initialize values we will cleanup. */
! 2826: memset(&data, 0, sizeof(data));
! 2827:
! 2828: /*
! 2829: * Bring configured options into the root packet level cache - start
! 2830: * with the lease's closest enclosing group (passed in by the caller
! 2831: * as 'group').
! 2832: */
! 2833: execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
! 2834: reply->packet->options, reply->opt_state,
! 2835: scope, group, root_group);
! 2836:
! 2837: /*
! 2838: * If there is a host record, over-ride with values configured there,
! 2839: * without re-evaluating configuration from the previously executed
! 2840: * group or its common enclosers.
! 2841: */
! 2842: if (reply->host != NULL)
! 2843: execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
! 2844: reply->packet->options,
! 2845: reply->opt_state, scope,
! 2846: reply->host->group, group);
! 2847:
! 2848: /* Determine valid lifetime. */
! 2849: if (reply->client_valid == 0)
! 2850: reply->send_valid = DEFAULT_DEFAULT_LEASE_TIME;
! 2851: else
! 2852: reply->send_valid = reply->client_valid;
! 2853:
! 2854: oc = lookup_option(&server_universe, reply->opt_state,
! 2855: SV_DEFAULT_LEASE_TIME);
! 2856: if (oc != NULL) {
! 2857: if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
! 2858: reply->packet->options,
! 2859: reply->opt_state,
! 2860: scope, oc, MDL) ||
! 2861: (data.len != 4)) {
! 2862: log_error("reply_process_is_addressed: unable to "
! 2863: "evaluate default lease time");
! 2864: status = ISC_R_FAILURE;
! 2865: goto cleanup;
! 2866: }
! 2867:
! 2868: reply->send_valid = getULong(data.data);
! 2869: data_string_forget(&data, MDL);
! 2870: }
! 2871:
! 2872: if (reply->client_prefer == 0)
! 2873: reply->send_prefer = reply->send_valid;
! 2874: else
! 2875: reply->send_prefer = reply->client_prefer;
! 2876:
! 2877: if (reply->send_prefer >= reply->send_valid)
! 2878: reply->send_prefer = (reply->send_valid / 2) +
! 2879: (reply->send_valid / 8);
! 2880:
! 2881: oc = lookup_option(&server_universe, reply->opt_state,
! 2882: SV_PREFER_LIFETIME);
! 2883: if (oc != NULL) {
! 2884: if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
! 2885: reply->packet->options,
! 2886: reply->opt_state,
! 2887: scope, oc, MDL) ||
! 2888: (data.len != 4)) {
! 2889: log_error("reply_process_is_addressed: unable to "
! 2890: "evaluate preferred lease time");
! 2891: status = ISC_R_FAILURE;
! 2892: goto cleanup;
! 2893: }
! 2894:
! 2895: reply->send_prefer = getULong(data.data);
! 2896: data_string_forget(&data, MDL);
! 2897: }
! 2898:
! 2899: /* Note lowest values for later calculation of renew/rebind times. */
! 2900: if (reply->prefer > reply->send_prefer)
! 2901: reply->prefer = reply->send_prefer;
! 2902:
! 2903: if (reply->valid > reply->send_valid)
! 2904: reply->valid = reply->send_valid;
! 2905:
! 2906: #if 0
! 2907: /*
! 2908: * XXX: Old 4.0.0 alpha code would change the host {} record
! 2909: * XXX: uid upon lease assignment. This was intended to cover the
! 2910: * XXX: case where a client first identifies itself using vendor
! 2911: * XXX: options in a solicit, or request, but later neglects to include
! 2912: * XXX: these options in a Renew or Rebind. It is not clear that this
! 2913: * XXX: is required, and has some startling ramifications (such as
! 2914: * XXX: how to recover this dynamic host {} state across restarts).
! 2915: */
! 2916: if (reply->host != NULL)
! 2917: change_host_uid(host, reply->client_id->data,
! 2918: reply->client_id->len);
! 2919: #endif /* 0 */
! 2920:
! 2921: /* Perform dynamic lease related update work. */
! 2922: if (reply->lease != NULL) {
! 2923: /* Cached lifetimes */
! 2924: reply->lease->prefer = reply->send_prefer;
! 2925: reply->lease->valid = reply->send_valid;
! 2926:
! 2927: /* Advance (or rewind) the valid lifetime. */
! 2928: if (reply->buf.reply.msg_type == DHCPV6_REPLY) {
! 2929: reply->lease->soft_lifetime_end_time =
! 2930: cur_time + reply->send_valid;
! 2931: /* Wait before renew! */
! 2932: }
! 2933:
! 2934: status = ia_add_iasubopt(reply->ia, reply->lease, MDL);
! 2935: if (status != ISC_R_SUCCESS) {
! 2936: log_fatal("reply_process_is_addressed: Unable to "
! 2937: "attach lease to new IA: %s",
! 2938: isc_result_totext(status));
! 2939: }
! 2940:
! 2941: /*
! 2942: * If this is a new lease, make sure it is attached somewhere.
! 2943: */
! 2944: if (reply->lease->ia == NULL) {
! 2945: ia_reference(&reply->lease->ia, reply->ia, MDL);
! 2946: }
! 2947: }
! 2948:
! 2949: /* Bring a copy of the relevant options into the IA scope. */
! 2950: execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
! 2951: reply->packet->options, reply->reply_ia,
! 2952: scope, group, root_group);
! 2953:
! 2954: /*
! 2955: * And bring in host record configuration, if any, but not to overlap
! 2956: * the previous group or its common enclosers.
! 2957: */
! 2958: if (reply->host != NULL)
! 2959: execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
! 2960: reply->packet->options,
! 2961: reply->reply_ia, scope,
! 2962: reply->host->group, group);
! 2963:
! 2964: cleanup:
! 2965: if (data.data != NULL)
! 2966: data_string_forget(&data, MDL);
! 2967:
! 2968: if (status == ISC_R_SUCCESS)
! 2969: reply->client_resources++;
! 2970:
! 2971: return status;
! 2972: }
! 2973:
! 2974: /* Simply send an IAADDR within the IA scope as described. */
! 2975: static isc_result_t
! 2976: reply_process_send_addr(struct reply_state *reply, struct iaddr *addr) {
! 2977: isc_result_t status = ISC_R_SUCCESS;
! 2978: struct data_string data;
! 2979:
! 2980: memset(&data, 0, sizeof(data));
! 2981:
! 2982: /* Now append the lease. */
! 2983: data.len = IAADDR_OFFSET;
! 2984: if (!buffer_allocate(&data.buffer, data.len, MDL)) {
! 2985: log_error("reply_process_send_addr: out of memory"
! 2986: "allocating new IAADDR buffer.");
! 2987: status = ISC_R_NOMEMORY;
! 2988: goto cleanup;
! 2989: }
! 2990: data.data = data.buffer->data;
! 2991:
! 2992: memcpy(data.buffer->data, addr->iabuf, 16);
! 2993: putULong(data.buffer->data + 16, reply->send_prefer);
! 2994: putULong(data.buffer->data + 20, reply->send_valid);
! 2995:
! 2996: if (!append_option_buffer(&dhcpv6_universe, reply->reply_ia,
! 2997: data.buffer, data.buffer->data,
! 2998: data.len, D6O_IAADDR, 0)) {
! 2999: log_error("reply_process_send_addr: unable "
! 3000: "to save IAADDR option");
! 3001: status = ISC_R_FAILURE;
! 3002: goto cleanup;
! 3003: }
! 3004:
! 3005: reply->resources_included = ISC_TRUE;
! 3006:
! 3007: cleanup:
! 3008: if (data.data != NULL)
! 3009: data_string_forget(&data, MDL);
! 3010:
! 3011: return status;
! 3012: }
! 3013:
! 3014: /* Choose the better of two leases. */
! 3015: static struct iasubopt *
! 3016: lease_compare(struct iasubopt *alpha, struct iasubopt *beta) {
! 3017: if (alpha == NULL)
! 3018: return beta;
! 3019: if (beta == NULL)
! 3020: return alpha;
! 3021:
! 3022: switch(alpha->state) {
! 3023: case FTS_ACTIVE:
! 3024: switch(beta->state) {
! 3025: case FTS_ACTIVE:
! 3026: /* Choose the lease with the longest lifetime (most
! 3027: * likely the most recently allocated).
! 3028: */
! 3029: if (alpha->hard_lifetime_end_time <
! 3030: beta->hard_lifetime_end_time)
! 3031: return beta;
! 3032: else
! 3033: return alpha;
! 3034:
! 3035: case FTS_EXPIRED:
! 3036: case FTS_ABANDONED:
! 3037: return alpha;
! 3038:
! 3039: default:
! 3040: log_fatal("Impossible condition at %s:%d.", MDL);
! 3041: }
! 3042: break;
! 3043:
! 3044: case FTS_EXPIRED:
! 3045: switch (beta->state) {
! 3046: case FTS_ACTIVE:
! 3047: return beta;
! 3048:
! 3049: case FTS_EXPIRED:
! 3050: /* Choose the most recently expired lease. */
! 3051: if (alpha->hard_lifetime_end_time <
! 3052: beta->hard_lifetime_end_time)
! 3053: return beta;
! 3054: else if ((alpha->hard_lifetime_end_time ==
! 3055: beta->hard_lifetime_end_time) &&
! 3056: (alpha->soft_lifetime_end_time <
! 3057: beta->soft_lifetime_end_time))
! 3058: return beta;
! 3059: else
! 3060: return alpha;
! 3061:
! 3062: case FTS_ABANDONED:
! 3063: return alpha;
! 3064:
! 3065: default:
! 3066: log_fatal("Impossible condition at %s:%d.", MDL);
! 3067: }
! 3068: break;
! 3069:
! 3070: case FTS_ABANDONED:
! 3071: switch (beta->state) {
! 3072: case FTS_ACTIVE:
! 3073: case FTS_EXPIRED:
! 3074: return alpha;
! 3075:
! 3076: case FTS_ABANDONED:
! 3077: /* Choose the lease that was abandoned longest ago. */
! 3078: if (alpha->hard_lifetime_end_time <
! 3079: beta->hard_lifetime_end_time)
! 3080: return alpha;
! 3081:
! 3082: default:
! 3083: log_fatal("Impossible condition at %s:%d.", MDL);
! 3084: }
! 3085: break;
! 3086:
! 3087: default:
! 3088: log_fatal("Impossible condition at %s:%d.", MDL);
! 3089: }
! 3090:
! 3091: log_fatal("Triple impossible condition at %s:%d.", MDL);
! 3092: return NULL;
! 3093: }
! 3094:
! 3095: /* Process a client-supplied IA_PD. This may append options to the tail of
! 3096: * the reply packet being built in the reply_state structure.
! 3097: */
! 3098: static isc_result_t
! 3099: reply_process_ia_pd(struct reply_state *reply, struct option_cache *ia) {
! 3100: isc_result_t status = ISC_R_SUCCESS;
! 3101: u_int32_t iaid;
! 3102: unsigned ia_cursor;
! 3103: struct option_state *packet_ia;
! 3104: struct option_cache *oc;
! 3105: struct data_string ia_data, data;
! 3106:
! 3107: /* Initialize values that will get cleaned up on return. */
! 3108: packet_ia = NULL;
! 3109: memset(&ia_data, 0, sizeof(ia_data));
! 3110: memset(&data, 0, sizeof(data));
! 3111: /*
! 3112: * Note that find_client_prefix() may set reply->lease.
! 3113: */
! 3114:
! 3115: /* Make sure there is at least room for the header. */
! 3116: if ((reply->cursor + IA_PD_OFFSET + 4) > sizeof(reply->buf)) {
! 3117: log_error("reply_process_ia_pd: Reply too long for IA.");
! 3118: return ISC_R_NOSPACE;
! 3119: }
! 3120:
! 3121:
! 3122: /* Fetch the IA_PD contents. */
! 3123: if (!get_encapsulated_IA_state(&packet_ia, &ia_data, reply->packet,
! 3124: ia, IA_PD_OFFSET)) {
! 3125: log_error("reply_process_ia_pd: error evaluating ia");
! 3126: status = ISC_R_FAILURE;
! 3127: goto cleanup;
! 3128: }
! 3129:
! 3130: /* Extract IA_PD header contents. */
! 3131: iaid = getULong(ia_data.data);
! 3132: reply->renew = getULong(ia_data.data + 4);
! 3133: reply->rebind = getULong(ia_data.data + 8);
! 3134:
! 3135: /* Create an IA_PD structure. */
! 3136: if (ia_allocate(&reply->ia, iaid, (char *)reply->client_id.data,
! 3137: reply->client_id.len, MDL) != ISC_R_SUCCESS) {
! 3138: log_error("reply_process_ia_pd: no memory for ia.");
! 3139: status = ISC_R_NOMEMORY;
! 3140: goto cleanup;
! 3141: }
! 3142: reply->ia->ia_type = D6O_IA_PD;
! 3143:
! 3144: /* Cache pre-existing IA_PD, if any. */
! 3145: ia_hash_lookup(&reply->old_ia, ia_pd_active,
! 3146: (unsigned char *)reply->ia->iaid_duid.data,
! 3147: reply->ia->iaid_duid.len, MDL);
! 3148:
! 3149: /*
! 3150: * Create an option cache to carry the IA_PD option contents, and
! 3151: * execute any user-supplied values into it.
! 3152: */
! 3153: if (!option_state_allocate(&reply->reply_ia, MDL)) {
! 3154: status = ISC_R_NOMEMORY;
! 3155: goto cleanup;
! 3156: }
! 3157:
! 3158: /* Check & count the fixed prefix host records. */
! 3159: reply->static_prefixes = 0;
! 3160: if ((reply->host != NULL) && (reply->host->fixed_prefix != NULL)) {
! 3161: struct iaddrcidrnetlist *fp;
! 3162:
! 3163: for (fp = reply->host->fixed_prefix; fp != NULL;
! 3164: fp = fp->next) {
! 3165: reply->static_prefixes += 1;
! 3166: }
! 3167: }
! 3168:
! 3169: /*
! 3170: * Save the cursor position at the start of the IA_PD, so we can
! 3171: * set length and adjust t1/t2 values later. We write a temporary
! 3172: * header out now just in case we decide to adjust the packet
! 3173: * within sub-process functions.
! 3174: */
! 3175: ia_cursor = reply->cursor;
! 3176:
! 3177: /* Initialize the IA_PD header. First the code. */
! 3178: putUShort(reply->buf.data + reply->cursor, (unsigned)D6O_IA_PD);
! 3179: reply->cursor += 2;
! 3180:
! 3181: /* Then option length. */
! 3182: putUShort(reply->buf.data + reply->cursor, 0x0Cu);
! 3183: reply->cursor += 2;
! 3184:
! 3185: /* Then IA_PD header contents; IAID. */
! 3186: putULong(reply->buf.data + reply->cursor, iaid);
! 3187: reply->cursor += 4;
! 3188:
! 3189: /* We store the client's t1 for now, and may over-ride it later. */
! 3190: putULong(reply->buf.data + reply->cursor, reply->renew);
! 3191: reply->cursor += 4;
! 3192:
! 3193: /* We store the client's t2 for now, and may over-ride it later. */
! 3194: putULong(reply->buf.data + reply->cursor, reply->rebind);
! 3195: reply->cursor += 4;
! 3196:
! 3197: /*
! 3198: * For each prefix in this IA_PD, decide what to do about it.
! 3199: */
! 3200: oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAPREFIX);
! 3201: reply->valid = reply->prefer = 0xffffffff;
! 3202: reply->client_valid = reply->client_prefer = 0;
! 3203: reply->preflen = -1;
! 3204: for (; oc != NULL ; oc = oc->next) {
! 3205: status = reply_process_prefix(reply, oc);
! 3206:
! 3207: /*
! 3208: * Canceled means we did not allocate prefixes to the
! 3209: * client, but we're "done" with this IA - we set a status
! 3210: * code. So transmit this reply, e.g., move on to the next
! 3211: * IA.
! 3212: */
! 3213: if (status == ISC_R_CANCELED)
! 3214: break;
! 3215:
! 3216: if ((status != ISC_R_SUCCESS) && (status != ISC_R_ADDRINUSE))
! 3217: goto cleanup;
! 3218: }
! 3219:
! 3220: reply->pd_count++;
! 3221:
! 3222: /*
! 3223: * If we fell through the above and never gave the client
! 3224: * a prefix, give it one now.
! 3225: */
! 3226: if ((status != ISC_R_CANCELED) && (reply->client_resources == 0)) {
! 3227: status = find_client_prefix(reply);
! 3228:
! 3229: if (status == ISC_R_NORESOURCES) {
! 3230: switch (reply->packet->dhcpv6_msg_type) {
! 3231: case DHCPV6_SOLICIT:
! 3232: /*
! 3233: * No prefix for any IA is handled
! 3234: * by the caller.
! 3235: */
! 3236: /* FALL THROUGH */
! 3237:
! 3238: case DHCPV6_REQUEST:
! 3239: /* Same than for addresses. */
! 3240: option_state_dereference(&reply->reply_ia, MDL);
! 3241: if (!option_state_allocate(&reply->reply_ia,
! 3242: MDL))
! 3243: {
! 3244: log_error("reply_process_ia_pd: No "
! 3245: "memory for option state "
! 3246: "wipe.");
! 3247: status = ISC_R_NOMEMORY;
! 3248: goto cleanup;
! 3249: }
! 3250:
! 3251: if (!set_status_code(STATUS_NoPrefixAvail,
! 3252: "No prefixes available "
! 3253: "for this interface.",
! 3254: reply->reply_ia)) {
! 3255: log_error("reply_process_ia_pd: "
! 3256: "Unable to set "
! 3257: "NoPrefixAvail status "
! 3258: "code.");
! 3259: status = ISC_R_FAILURE;
! 3260: goto cleanup;
! 3261: }
! 3262:
! 3263: status = ISC_R_SUCCESS;
! 3264: break;
! 3265:
! 3266: default:
! 3267: if (reply->resources_included)
! 3268: status = ISC_R_SUCCESS;
! 3269: else
! 3270: goto cleanup;
! 3271: break;
! 3272: }
! 3273: }
! 3274:
! 3275: if (status != ISC_R_SUCCESS)
! 3276: goto cleanup;
! 3277: }
! 3278:
! 3279: reply->cursor += store_options6((char *)reply->buf.data + reply->cursor,
! 3280: sizeof(reply->buf) - reply->cursor,
! 3281: reply->reply_ia, reply->packet,
! 3282: required_opts_IA_PD, NULL);
! 3283:
! 3284: /* Reset the length of this IA_PD to match what was just written. */
! 3285: putUShort(reply->buf.data + ia_cursor + 2,
! 3286: reply->cursor - (ia_cursor + 4));
! 3287:
! 3288: /*
! 3289: * T1/T2 time selection is kind of weird. We actually use DHCP
! 3290: * (v4) scoped options as handy existing places where these might
! 3291: * be configured by an administrator. A value of zero tells the
! 3292: * client it may choose its own renewal time.
! 3293: */
! 3294: reply->renew = 0;
! 3295: oc = lookup_option(&dhcp_universe, reply->opt_state,
! 3296: DHO_DHCP_RENEWAL_TIME);
! 3297: if (oc != NULL) {
! 3298: if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
! 3299: reply->packet->options,
! 3300: reply->opt_state, &global_scope,
! 3301: oc, MDL) ||
! 3302: (data.len != 4)) {
! 3303: log_error("Invalid renewal time.");
! 3304: } else {
! 3305: reply->renew = getULong(data.data);
! 3306: }
! 3307:
! 3308: if (data.data != NULL)
! 3309: data_string_forget(&data, MDL);
! 3310: }
! 3311: putULong(reply->buf.data + ia_cursor + 8, reply->renew);
! 3312:
! 3313: /* Now T2. */
! 3314: reply->rebind = 0;
! 3315: oc = lookup_option(&dhcp_universe, reply->opt_state,
! 3316: DHO_DHCP_REBINDING_TIME);
! 3317: if (oc != NULL) {
! 3318: if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
! 3319: reply->packet->options,
! 3320: reply->opt_state, &global_scope,
! 3321: oc, MDL) ||
! 3322: (data.len != 4)) {
! 3323: log_error("Invalid rebinding time.");
! 3324: } else {
! 3325: reply->rebind = getULong(data.data);
! 3326: }
! 3327:
! 3328: if (data.data != NULL)
! 3329: data_string_forget(&data, MDL);
! 3330: }
! 3331: putULong(reply->buf.data + ia_cursor + 12, reply->rebind);
! 3332:
! 3333: /*
! 3334: * If this is not a 'soft' binding, consume the new changes into
! 3335: * the database (if any have been attached to the ia_pd).
! 3336: *
! 3337: * Loop through the assigned dynamic prefixes, referencing the
! 3338: * prefixes onto this IA_PD rather than any old ones, and updating
! 3339: * prefix pool timers for each (if any).
! 3340: */
! 3341: if ((status != ISC_R_CANCELED) && (reply->static_prefixes == 0) &&
! 3342: (reply->buf.reply.msg_type == DHCPV6_REPLY) &&
! 3343: (reply->ia->num_iasubopt != 0)) {
! 3344: struct iasubopt *tmp;
! 3345: struct data_string *ia_id;
! 3346: int i;
! 3347:
! 3348: for (i = 0 ; i < reply->ia->num_iasubopt ; i++) {
! 3349: tmp = reply->ia->iasubopt[i];
! 3350:
! 3351: if (tmp->ia != NULL)
! 3352: ia_dereference(&tmp->ia, MDL);
! 3353: ia_reference(&tmp->ia, reply->ia, MDL);
! 3354:
! 3355: /* Commit 'hard' bindings. */
! 3356: tmp->hard_lifetime_end_time =
! 3357: tmp->soft_lifetime_end_time;
! 3358: tmp->soft_lifetime_end_time = 0;
! 3359: renew_lease6(tmp->ipv6_pool, tmp);
! 3360: schedule_lease_timeout(tmp->ipv6_pool);
! 3361: }
! 3362:
! 3363: /* Remove any old ia from the hash. */
! 3364: if (reply->old_ia != NULL) {
! 3365: ia_id = &reply->old_ia->iaid_duid;
! 3366: ia_hash_delete(ia_pd_active,
! 3367: (unsigned char *)ia_id->data,
! 3368: ia_id->len, MDL);
! 3369: ia_dereference(&reply->old_ia, MDL);
! 3370: }
! 3371:
! 3372: /* Put new ia into the hash. */
! 3373: reply->ia->cltt = cur_time;
! 3374: ia_id = &reply->ia->iaid_duid;
! 3375: ia_hash_add(ia_pd_active, (unsigned char *)ia_id->data,
! 3376: ia_id->len, reply->ia, MDL);
! 3377:
! 3378: write_ia(reply->ia);
! 3379: }
! 3380:
! 3381: cleanup:
! 3382: if (packet_ia != NULL)
! 3383: option_state_dereference(&packet_ia, MDL);
! 3384: if (reply->reply_ia != NULL)
! 3385: option_state_dereference(&reply->reply_ia, MDL);
! 3386: if (ia_data.data != NULL)
! 3387: data_string_forget(&ia_data, MDL);
! 3388: if (data.data != NULL)
! 3389: data_string_forget(&data, MDL);
! 3390: if (reply->ia != NULL)
! 3391: ia_dereference(&reply->ia, MDL);
! 3392: if (reply->old_ia != NULL)
! 3393: ia_dereference(&reply->old_ia, MDL);
! 3394: if (reply->lease != NULL)
! 3395: iasubopt_dereference(&reply->lease, MDL);
! 3396:
! 3397: /*
! 3398: * ISC_R_CANCELED is a status code used by the prefix processing to
! 3399: * indicate we're replying with a status code. This is still a
! 3400: * success at higher layers.
! 3401: */
! 3402: return((status == ISC_R_CANCELED) ? ISC_R_SUCCESS : status);
! 3403: }
! 3404:
! 3405: /*
! 3406: * Process an IAPREFIX within a given IA_PD, storing any IAPREFIX reply
! 3407: * contents into the reply's current ia_pd-scoped option cache. Returns
! 3408: * ISC_R_CANCELED in the event we are replying with a status code and do
! 3409: * not wish to process more IAPREFIXes within this IA_PD.
! 3410: */
! 3411: static isc_result_t
! 3412: reply_process_prefix(struct reply_state *reply, struct option_cache *pref) {
! 3413: u_int32_t pref_life, valid_life;
! 3414: struct binding_scope **scope;
! 3415: struct iaddrcidrnet tmp_pref;
! 3416: struct option_cache *oc;
! 3417: struct data_string iapref, data;
! 3418: isc_result_t status = ISC_R_SUCCESS;
! 3419:
! 3420: /* Initializes values that will be cleaned up. */
! 3421: memset(&iapref, 0, sizeof(iapref));
! 3422: memset(&data, 0, sizeof(data));
! 3423: /* Note that reply->lease may be set by prefix_is_owned() */
! 3424:
! 3425: /*
! 3426: * There is no point trying to process an incoming prefix if there
! 3427: * is no room for an outgoing prefix.
! 3428: */
! 3429: if ((reply->cursor + 29) > sizeof(reply->buf)) {
! 3430: log_error("reply_process_prefix: Out of room for prefix.");
! 3431: return ISC_R_NOSPACE;
! 3432: }
! 3433:
! 3434: /* Extract this IAPREFIX option. */
! 3435: if (!evaluate_option_cache(&iapref, reply->packet, NULL, NULL,
! 3436: reply->packet->options, NULL, &global_scope,
! 3437: pref, MDL) ||
! 3438: (iapref.len < IAPREFIX_OFFSET)) {
! 3439: log_error("reply_process_prefix: error evaluating IAPREFIX.");
! 3440: status = ISC_R_FAILURE;
! 3441: goto cleanup;
! 3442: }
! 3443:
! 3444: /*
! 3445: * Layout: preferred and valid lifetimes followed by the prefix
! 3446: * length and the IPv6 address.
! 3447: */
! 3448: pref_life = getULong(iapref.data);
! 3449: valid_life = getULong(iapref.data + 4);
! 3450:
! 3451: if ((reply->client_valid == 0) ||
! 3452: (reply->client_valid > valid_life))
! 3453: reply->client_valid = valid_life;
! 3454:
! 3455: if ((reply->client_prefer == 0) ||
! 3456: (reply->client_prefer > pref_life))
! 3457: reply->client_prefer = pref_life;
! 3458:
! 3459: /*
! 3460: * Clients may choose to send ::/0 as a prefix, with the idea to give
! 3461: * hints about preferred-lifetime or valid-lifetime.
! 3462: */
! 3463: tmp_pref.lo_addr.len = 16;
! 3464: memset(tmp_pref.lo_addr.iabuf, 0, 16);
! 3465: if ((iapref.data[8] == 0) &&
! 3466: (memcmp(iapref.data + 9, tmp_pref.lo_addr.iabuf, 16) == 0)) {
! 3467: /* Status remains success; we just ignore this one. */
! 3468: goto cleanup;
! 3469: }
! 3470:
! 3471: /*
! 3472: * Clients may choose to send ::/X as a prefix to specify a
! 3473: * preferred/requested prefix length. Note X is never zero here.
! 3474: */
! 3475: tmp_pref.bits = (int) iapref.data[8];
! 3476: if (reply->preflen < 0) {
! 3477: /* Cache the first preferred prefix length. */
! 3478: reply->preflen = tmp_pref.bits;
! 3479: }
! 3480: if (memcmp(iapref.data + 9, tmp_pref.lo_addr.iabuf, 16) == 0) {
! 3481: goto cleanup;
! 3482: }
! 3483:
! 3484: memcpy(tmp_pref.lo_addr.iabuf, iapref.data + 9, 16);
! 3485:
! 3486: /* Verify the prefix belongs to the client. */
! 3487: if (!prefix_is_owned(reply, &tmp_pref)) {
! 3488: /* Same than for addresses. */
! 3489: if ((reply->packet->dhcpv6_msg_type == DHCPV6_SOLICIT) ||
! 3490: (reply->packet->dhcpv6_msg_type == DHCPV6_REQUEST) ||
! 3491: (reply->packet->dhcpv6_msg_type == DHCPV6_REBIND)) {
! 3492: status = reply_process_try_prefix(reply, &tmp_pref);
! 3493:
! 3494: /* Either error out or skip this prefix. */
! 3495: if ((status != ISC_R_SUCCESS) &&
! 3496: (status != ISC_R_ADDRINUSE))
! 3497: goto cleanup;
! 3498:
! 3499: if (reply->lease == NULL) {
! 3500: if (reply->packet->dhcpv6_msg_type ==
! 3501: DHCPV6_REBIND) {
! 3502: reply->send_prefer = 0;
! 3503: reply->send_valid = 0;
! 3504: goto send_pref;
! 3505: }
! 3506:
! 3507: /* status remains success - ignore */
! 3508: goto cleanup;
! 3509: }
! 3510: /*
! 3511: * RFC3633 section 18.2.3:
! 3512: *
! 3513: * If the delegating router cannot find a binding
! 3514: * for the requesting router's IA_PD the delegating
! 3515: * router returns the IA_PD containing no prefixes
! 3516: * with a Status Code option set to NoBinding in the
! 3517: * Reply message.
! 3518: *
! 3519: * On mismatch we (ab)use this pretending we have not the IA
! 3520: * as soon as we have not a prefix.
! 3521: */
! 3522: } else if (reply->packet->dhcpv6_msg_type == DHCPV6_RENEW) {
! 3523: /* Rewind the IA_PD to empty. */
! 3524: option_state_dereference(&reply->reply_ia, MDL);
! 3525: if (!option_state_allocate(&reply->reply_ia, MDL)) {
! 3526: log_error("reply_process_prefix: No memory "
! 3527: "for option state wipe.");
! 3528: status = ISC_R_NOMEMORY;
! 3529: goto cleanup;
! 3530: }
! 3531:
! 3532: /* Append a NoBinding status code. */
! 3533: if (!set_status_code(STATUS_NoBinding,
! 3534: "Prefix not bound to this "
! 3535: "interface.", reply->reply_ia)) {
! 3536: log_error("reply_process_prefix: Unable to "
! 3537: "attach status code.");
! 3538: status = ISC_R_FAILURE;
! 3539: goto cleanup;
! 3540: }
! 3541:
! 3542: /* Fin (no more IAPREFIXes). */
! 3543: status = ISC_R_CANCELED;
! 3544: goto cleanup;
! 3545: } else {
! 3546: log_error("It is impossible to lease a client that is "
! 3547: "not sending a solicit, request, renew, or "
! 3548: "rebind message.");
! 3549: status = ISC_R_FAILURE;
! 3550: goto cleanup;
! 3551: }
! 3552: }
! 3553:
! 3554: if (reply->static_prefixes > 0) {
! 3555: if (reply->host == NULL)
! 3556: log_fatal("Impossible condition at %s:%d.", MDL);
! 3557:
! 3558: scope = &global_scope;
! 3559: } else {
! 3560: if (reply->lease == NULL)
! 3561: log_fatal("Impossible condition at %s:%d.", MDL);
! 3562:
! 3563: scope = &reply->lease->scope;
! 3564: }
! 3565:
! 3566: /*
! 3567: * If client_resources is nonzero, then the reply_process_is_prefixed
! 3568: * function has executed configuration state into the reply option
! 3569: * cache. We will use that valid cache to derive configuration for
! 3570: * whether or not to engage in additional prefixes, and similar.
! 3571: */
! 3572: if (reply->client_resources != 0) {
! 3573: unsigned limit = 1;
! 3574:
! 3575: /*
! 3576: * Does this client have "enough" prefixes already? Default
! 3577: * to one. Everybody gets one, and one should be enough for
! 3578: * anybody.
! 3579: */
! 3580: oc = lookup_option(&server_universe, reply->opt_state,
! 3581: SV_LIMIT_PREFS_PER_IA);
! 3582: if (oc != NULL) {
! 3583: if (!evaluate_option_cache(&data, reply->packet,
! 3584: NULL, NULL,
! 3585: reply->packet->options,
! 3586: reply->opt_state,
! 3587: scope, oc, MDL) ||
! 3588: (data.len != 4)) {
! 3589: log_error("reply_process_prefix: unable to "
! 3590: "evaluate prefs-per-ia value.");
! 3591: status = ISC_R_FAILURE;
! 3592: goto cleanup;
! 3593: }
! 3594:
! 3595: limit = getULong(data.data);
! 3596: data_string_forget(&data, MDL);
! 3597: }
! 3598:
! 3599: /*
! 3600: * If we wish to limit the client to a certain number of
! 3601: * prefixes, then omit the prefix from the reply.
! 3602: */
! 3603: if (reply->client_resources >= limit)
! 3604: goto cleanup;
! 3605: }
! 3606:
! 3607: status = reply_process_is_prefixed(reply, scope, reply->shared->group);
! 3608: if (status != ISC_R_SUCCESS)
! 3609: goto cleanup;
! 3610:
! 3611: send_pref:
! 3612: status = reply_process_send_prefix(reply, &tmp_pref);
! 3613:
! 3614: cleanup:
! 3615: if (iapref.data != NULL)
! 3616: data_string_forget(&iapref, MDL);
! 3617: if (data.data != NULL)
! 3618: data_string_forget(&data, MDL);
! 3619: if (reply->lease != NULL)
! 3620: iasubopt_dereference(&reply->lease, MDL);
! 3621:
! 3622: return status;
! 3623: }
! 3624:
! 3625: /*
! 3626: * Verify the prefix belongs to the client. If we've got a host
! 3627: * record with fixed prefixes, it has to be an assigned prefix
! 3628: * (fault out all else). Otherwise it's a dynamic prefix, so lookup
! 3629: * that prefix and make sure it belongs to this DUID:IAID pair.
! 3630: */
! 3631: static isc_boolean_t
! 3632: prefix_is_owned(struct reply_state *reply, struct iaddrcidrnet *pref) {
! 3633: struct iaddrcidrnetlist *l;
! 3634: int i;
! 3635:
! 3636: /*
! 3637: * This faults out prefixes that don't match fixed prefixes.
! 3638: */
! 3639: if (reply->static_prefixes > 0) {
! 3640: for (l = reply->host->fixed_prefix; l != NULL; l = l->next) {
! 3641: if ((pref->bits == l->cidrnet.bits) &&
! 3642: (memcmp(pref->lo_addr.iabuf,
! 3643: l->cidrnet.lo_addr.iabuf, 16) == 0))
! 3644: return ISC_TRUE;
! 3645: }
! 3646: return ISC_FALSE;
! 3647: }
! 3648:
! 3649: if ((reply->old_ia == NULL) ||
! 3650: (reply->old_ia->num_iasubopt == 0))
! 3651: return ISC_FALSE;
! 3652:
! 3653: for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
! 3654: struct iasubopt *tmp;
! 3655:
! 3656: tmp = reply->old_ia->iasubopt[i];
! 3657:
! 3658: if ((pref->bits == (int) tmp->plen) &&
! 3659: memcmp(pref->lo_addr.iabuf, &tmp->addr, 16) == 0) {
! 3660: iasubopt_reference(&reply->lease, tmp, MDL);
! 3661: return ISC_TRUE;
! 3662: }
! 3663: }
! 3664:
! 3665: return ISC_FALSE;
! 3666: }
! 3667:
! 3668: /*
! 3669: * This function only returns failure on 'hard' failures. If it succeeds,
! 3670: * it will leave a prefix structure behind.
! 3671: */
! 3672: static isc_result_t
! 3673: reply_process_try_prefix(struct reply_state *reply,
! 3674: struct iaddrcidrnet *pref) {
! 3675: isc_result_t status = ISC_R_NORESOURCES;
! 3676: struct ipv6_pool *pool;
! 3677: int i;
! 3678: struct data_string data_pref;
! 3679:
! 3680: if ((reply == NULL) || (reply->shared == NULL) ||
! 3681: (reply->shared->ipv6_pools == NULL) || (pref == NULL) ||
! 3682: (reply->lease != NULL))
! 3683: return ISC_R_INVALIDARG;
! 3684:
! 3685: memset(&data_pref, 0, sizeof(data_pref));
! 3686: data_pref.len = 17;
! 3687: if (!buffer_allocate(&data_pref.buffer, data_pref.len, MDL)) {
! 3688: log_error("reply_process_try_prefix: out of memory.");
! 3689: return ISC_R_NOMEMORY;
! 3690: }
! 3691: data_pref.data = data_pref.buffer->data;
! 3692: data_pref.buffer->data[0] = (u_int8_t) pref->bits;
! 3693: memcpy(data_pref.buffer->data + 1, pref->lo_addr.iabuf, 16);
! 3694:
! 3695: for (i = 0 ; (pool = reply->shared->ipv6_pools[i]) != NULL ; i++) {
! 3696: if (pool->pool_type != D6O_IA_PD)
! 3697: continue;
! 3698: status = try_client_v6_prefix(&reply->lease, pool,
! 3699: &data_pref);
! 3700: /* If we found it in this pool (either in use or available),
! 3701: there is no need to look further. */
! 3702: if ( (status == ISC_R_SUCCESS) || (status == ISC_R_ADDRINUSE) )
! 3703: break;
! 3704: }
! 3705:
! 3706: data_string_forget(&data_pref, MDL);
! 3707: /* Return just the most recent status... */
! 3708: return status;
! 3709: }
! 3710:
! 3711: /* Look around for a prefix to give the client. First, look through the old
! 3712: * IA_PD for prefixes we can extend. Second, try to allocate a new prefix.
! 3713: * Finally, actually add that prefix into the current reply IA_PD.
! 3714: */
! 3715: static isc_result_t
! 3716: find_client_prefix(struct reply_state *reply) {
! 3717: struct iaddrcidrnet send_pref;
! 3718: isc_result_t status = ISC_R_NORESOURCES;
! 3719: struct iasubopt *prefix, *best_prefix = NULL;
! 3720: struct binding_scope **scope;
! 3721: int i;
! 3722:
! 3723: if (reply->static_prefixes > 0) {
! 3724: struct iaddrcidrnetlist *l;
! 3725:
! 3726: if (reply->host == NULL)
! 3727: return ISC_R_INVALIDARG;
! 3728:
! 3729: for (l = reply->host->fixed_prefix; l != NULL; l = l->next) {
! 3730: if (l->cidrnet.bits == reply->preflen)
! 3731: break;
! 3732: }
! 3733: if (l == NULL) {
! 3734: /*
! 3735: * If no fixed prefix has the preferred length,
! 3736: * get the first one.
! 3737: */
! 3738: l = reply->host->fixed_prefix;
! 3739: }
! 3740: memcpy(&send_pref, &l->cidrnet, sizeof(send_pref));
! 3741:
! 3742: status = ISC_R_SUCCESS;
! 3743: scope = &global_scope;
! 3744: goto send_pref;
! 3745: }
! 3746:
! 3747: if (reply->old_ia != NULL) {
! 3748: for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
! 3749: struct shared_network *candidate_shared;
! 3750:
! 3751: prefix = reply->old_ia->iasubopt[i];
! 3752: candidate_shared = prefix->ipv6_pool->shared_network;
! 3753:
! 3754: /*
! 3755: * Consider this prefix if it is in a global pool or
! 3756: * if it is scoped in a pool under the client's shared
! 3757: * network.
! 3758: */
! 3759: if (candidate_shared == NULL ||
! 3760: candidate_shared == reply->shared) {
! 3761: best_prefix = prefix_compare(reply, prefix,
! 3762: best_prefix);
! 3763: }
! 3764: }
! 3765: }
! 3766:
! 3767: /* Try to pick a new prefix if we didn't find one, or if we found an
! 3768: * abandoned prefix.
! 3769: */
! 3770: if ((best_prefix == NULL) || (best_prefix->state == FTS_ABANDONED)) {
! 3771: status = pick_v6_prefix(&reply->lease, reply->preflen,
! 3772: reply->shared, &reply->client_id);
! 3773: } else if (best_prefix != NULL) {
! 3774: iasubopt_reference(&reply->lease, best_prefix, MDL);
! 3775: status = ISC_R_SUCCESS;
! 3776: }
! 3777:
! 3778: /* Pick the abandoned prefix as a last resort. */
! 3779: if ((status == ISC_R_NORESOURCES) && (best_prefix != NULL)) {
! 3780: /* I don't see how this is supposed to be done right now. */
! 3781: log_error("Reclaiming abandoned prefixes is not yet "
! 3782: "supported. Treating this as an out of space "
! 3783: "condition.");
! 3784: /* iasubopt_reference(&reply->lease, best_prefix, MDL); */
! 3785: }
! 3786:
! 3787: /* Give up now if we didn't find a prefix. */
! 3788: if (status != ISC_R_SUCCESS)
! 3789: return status;
! 3790:
! 3791: if (reply->lease == NULL)
! 3792: log_fatal("Impossible condition at %s:%d.", MDL);
! 3793:
! 3794: scope = &reply->lease->scope;
! 3795:
! 3796: send_pref.lo_addr.len = 16;
! 3797: memcpy(send_pref.lo_addr.iabuf, &reply->lease->addr, 16);
! 3798: send_pref.bits = (int) reply->lease->plen;
! 3799:
! 3800: send_pref:
! 3801: status = reply_process_is_prefixed(reply, scope, reply->shared->group);
! 3802: if (status != ISC_R_SUCCESS)
! 3803: return status;
! 3804:
! 3805: status = reply_process_send_prefix(reply, &send_pref);
! 3806: return status;
! 3807: }
! 3808:
! 3809: /* Once a prefix is found for a client, perform several common functions;
! 3810: * Calculate and store valid and preferred prefix times, draw client options
! 3811: * into the option state.
! 3812: */
! 3813: static isc_result_t
! 3814: reply_process_is_prefixed(struct reply_state *reply,
! 3815: struct binding_scope **scope, struct group *group)
! 3816: {
! 3817: isc_result_t status = ISC_R_SUCCESS;
! 3818: struct data_string data;
! 3819: struct option_cache *oc;
! 3820:
! 3821: /* Initialize values we will cleanup. */
! 3822: memset(&data, 0, sizeof(data));
! 3823:
! 3824: /*
! 3825: * Bring configured options into the root packet level cache - start
! 3826: * with the lease's closest enclosing group (passed in by the caller
! 3827: * as 'group').
! 3828: */
! 3829: execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
! 3830: reply->packet->options, reply->opt_state,
! 3831: scope, group, root_group);
! 3832:
! 3833: /*
! 3834: * If there is a host record, over-ride with values configured there,
! 3835: * without re-evaluating configuration from the previously executed
! 3836: * group or its common enclosers.
! 3837: */
! 3838: if (reply->host != NULL)
! 3839: execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
! 3840: reply->packet->options,
! 3841: reply->opt_state, scope,
! 3842: reply->host->group, group);
! 3843:
! 3844: /* Determine valid lifetime. */
! 3845: if (reply->client_valid == 0)
! 3846: reply->send_valid = DEFAULT_DEFAULT_LEASE_TIME;
! 3847: else
! 3848: reply->send_valid = reply->client_valid;
! 3849:
! 3850: oc = lookup_option(&server_universe, reply->opt_state,
! 3851: SV_DEFAULT_LEASE_TIME);
! 3852: if (oc != NULL) {
! 3853: if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
! 3854: reply->packet->options,
! 3855: reply->opt_state,
! 3856: scope, oc, MDL) ||
! 3857: (data.len != 4)) {
! 3858: log_error("reply_process_is_prefixed: unable to "
! 3859: "evaluate default prefix time");
! 3860: status = ISC_R_FAILURE;
! 3861: goto cleanup;
! 3862: }
! 3863:
! 3864: reply->send_valid = getULong(data.data);
! 3865: data_string_forget(&data, MDL);
! 3866: }
! 3867:
! 3868: if (reply->client_prefer == 0)
! 3869: reply->send_prefer = reply->send_valid;
! 3870: else
! 3871: reply->send_prefer = reply->client_prefer;
! 3872:
! 3873: if (reply->send_prefer >= reply->send_valid)
! 3874: reply->send_prefer = (reply->send_valid / 2) +
! 3875: (reply->send_valid / 8);
! 3876:
! 3877: oc = lookup_option(&server_universe, reply->opt_state,
! 3878: SV_PREFER_LIFETIME);
! 3879: if (oc != NULL) {
! 3880: if (!evaluate_option_cache(&data, reply->packet, NULL, NULL,
! 3881: reply->packet->options,
! 3882: reply->opt_state,
! 3883: scope, oc, MDL) ||
! 3884: (data.len != 4)) {
! 3885: log_error("reply_process_is_prefixed: unable to "
! 3886: "evaluate preferred prefix time");
! 3887: status = ISC_R_FAILURE;
! 3888: goto cleanup;
! 3889: }
! 3890:
! 3891: reply->send_prefer = getULong(data.data);
! 3892: data_string_forget(&data, MDL);
! 3893: }
! 3894:
! 3895: /* Note lowest values for later calculation of renew/rebind times. */
! 3896: if (reply->prefer > reply->send_prefer)
! 3897: reply->prefer = reply->send_prefer;
! 3898:
! 3899: if (reply->valid > reply->send_valid)
! 3900: reply->valid = reply->send_valid;
! 3901:
! 3902: /* Perform dynamic prefix related update work. */
! 3903: if (reply->lease != NULL) {
! 3904: /* Cached lifetimes */
! 3905: reply->lease->prefer = reply->send_prefer;
! 3906: reply->lease->valid = reply->send_valid;
! 3907:
! 3908: /* Advance (or rewind) the valid lifetime. */
! 3909: if (reply->buf.reply.msg_type == DHCPV6_REPLY) {
! 3910: reply->lease->soft_lifetime_end_time =
! 3911: cur_time + reply->send_valid;
! 3912: /* Wait before renew! */
! 3913: }
! 3914:
! 3915: status = ia_add_iasubopt(reply->ia, reply->lease, MDL);
! 3916: if (status != ISC_R_SUCCESS) {
! 3917: log_fatal("reply_process_is_prefixed: Unable to "
! 3918: "attach prefix to new IA_PD: %s",
! 3919: isc_result_totext(status));
! 3920: }
! 3921:
! 3922: /*
! 3923: * If this is a new prefix, make sure it is attached somewhere.
! 3924: */
! 3925: if (reply->lease->ia == NULL) {
! 3926: ia_reference(&reply->lease->ia, reply->ia, MDL);
! 3927: }
! 3928: }
! 3929:
! 3930: /* Bring a copy of the relevant options into the IA_PD scope. */
! 3931: execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
! 3932: reply->packet->options, reply->reply_ia,
! 3933: scope, group, root_group);
! 3934:
! 3935: /*
! 3936: * And bring in host record configuration, if any, but not to overlap
! 3937: * the previous group or its common enclosers.
! 3938: */
! 3939: if (reply->host != NULL)
! 3940: execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
! 3941: reply->packet->options,
! 3942: reply->reply_ia, scope,
! 3943: reply->host->group, group);
! 3944:
! 3945: cleanup:
! 3946: if (data.data != NULL)
! 3947: data_string_forget(&data, MDL);
! 3948:
! 3949: if (status == ISC_R_SUCCESS)
! 3950: reply->client_resources++;
! 3951:
! 3952: return status;
! 3953: }
! 3954:
! 3955: /* Simply send an IAPREFIX within the IA_PD scope as described. */
! 3956: static isc_result_t
! 3957: reply_process_send_prefix(struct reply_state *reply,
! 3958: struct iaddrcidrnet *pref) {
! 3959: isc_result_t status = ISC_R_SUCCESS;
! 3960: struct data_string data;
! 3961:
! 3962: memset(&data, 0, sizeof(data));
! 3963:
! 3964: /* Now append the prefix. */
! 3965: data.len = IAPREFIX_OFFSET;
! 3966: if (!buffer_allocate(&data.buffer, data.len, MDL)) {
! 3967: log_error("reply_process_send_prefix: out of memory"
! 3968: "allocating new IAPREFIX buffer.");
! 3969: status = ISC_R_NOMEMORY;
! 3970: goto cleanup;
! 3971: }
! 3972: data.data = data.buffer->data;
! 3973:
! 3974: putULong(data.buffer->data, reply->send_prefer);
! 3975: putULong(data.buffer->data + 4, reply->send_valid);
! 3976: data.buffer->data[8] = pref->bits;
! 3977: memcpy(data.buffer->data + 9, pref->lo_addr.iabuf, 16);
! 3978:
! 3979: if (!append_option_buffer(&dhcpv6_universe, reply->reply_ia,
! 3980: data.buffer, data.buffer->data,
! 3981: data.len, D6O_IAPREFIX, 0)) {
! 3982: log_error("reply_process_send_prefix: unable "
! 3983: "to save IAPREFIX option");
! 3984: status = ISC_R_FAILURE;
! 3985: goto cleanup;
! 3986: }
! 3987:
! 3988: reply->resources_included = ISC_TRUE;
! 3989:
! 3990: cleanup:
! 3991: if (data.data != NULL)
! 3992: data_string_forget(&data, MDL);
! 3993:
! 3994: return status;
! 3995: }
! 3996:
! 3997: /* Choose the better of two prefixes. */
! 3998: static struct iasubopt *
! 3999: prefix_compare(struct reply_state *reply,
! 4000: struct iasubopt *alpha, struct iasubopt *beta) {
! 4001: if (alpha == NULL)
! 4002: return beta;
! 4003: if (beta == NULL)
! 4004: return alpha;
! 4005:
! 4006: if (reply->preflen >= 0) {
! 4007: if ((alpha->plen == reply->preflen) &&
! 4008: (beta->plen != reply->preflen))
! 4009: return alpha;
! 4010: if ((beta->plen == reply->preflen) &&
! 4011: (alpha->plen != reply->preflen))
! 4012: return beta;
! 4013: }
! 4014:
! 4015: switch(alpha->state) {
! 4016: case FTS_ACTIVE:
! 4017: switch(beta->state) {
! 4018: case FTS_ACTIVE:
! 4019: /* Choose the prefix with the longest lifetime (most
! 4020: * likely the most recently allocated).
! 4021: */
! 4022: if (alpha->hard_lifetime_end_time <
! 4023: beta->hard_lifetime_end_time)
! 4024: return beta;
! 4025: else
! 4026: return alpha;
! 4027:
! 4028: case FTS_EXPIRED:
! 4029: case FTS_ABANDONED:
! 4030: return alpha;
! 4031:
! 4032: default:
! 4033: log_fatal("Impossible condition at %s:%d.", MDL);
! 4034: }
! 4035: break;
! 4036:
! 4037: case FTS_EXPIRED:
! 4038: switch (beta->state) {
! 4039: case FTS_ACTIVE:
! 4040: return beta;
! 4041:
! 4042: case FTS_EXPIRED:
! 4043: /* Choose the most recently expired prefix. */
! 4044: if (alpha->hard_lifetime_end_time <
! 4045: beta->hard_lifetime_end_time)
! 4046: return beta;
! 4047: else if ((alpha->hard_lifetime_end_time ==
! 4048: beta->hard_lifetime_end_time) &&
! 4049: (alpha->soft_lifetime_end_time <
! 4050: beta->soft_lifetime_end_time))
! 4051: return beta;
! 4052: else
! 4053: return alpha;
! 4054:
! 4055: case FTS_ABANDONED:
! 4056: return alpha;
! 4057:
! 4058: default:
! 4059: log_fatal("Impossible condition at %s:%d.", MDL);
! 4060: }
! 4061: break;
! 4062:
! 4063: case FTS_ABANDONED:
! 4064: switch (beta->state) {
! 4065: case FTS_ACTIVE:
! 4066: case FTS_EXPIRED:
! 4067: return alpha;
! 4068:
! 4069: case FTS_ABANDONED:
! 4070: /* Choose the prefix that was abandoned longest ago. */
! 4071: if (alpha->hard_lifetime_end_time <
! 4072: beta->hard_lifetime_end_time)
! 4073: return alpha;
! 4074:
! 4075: default:
! 4076: log_fatal("Impossible condition at %s:%d.", MDL);
! 4077: }
! 4078: break;
! 4079:
! 4080: default:
! 4081: log_fatal("Impossible condition at %s:%d.", MDL);
! 4082: }
! 4083:
! 4084: log_fatal("Triple impossible condition at %s:%d.", MDL);
! 4085: return NULL;
! 4086: }
! 4087:
! 4088: /*
! 4089: * Solicit is how a client starts requesting addresses.
! 4090: *
! 4091: * If the client asks for rapid commit, and we support it, we will
! 4092: * allocate the addresses and reply.
! 4093: *
! 4094: * Otherwise we will send an advertise message.
! 4095: */
! 4096:
! 4097: static void
! 4098: dhcpv6_solicit(struct data_string *reply_ret, struct packet *packet) {
! 4099: struct data_string client_id;
! 4100:
! 4101: /*
! 4102: * Validate our input.
! 4103: */
! 4104: if (!valid_client_msg(packet, &client_id)) {
! 4105: return;
! 4106: }
! 4107:
! 4108: lease_to_client(reply_ret, packet, &client_id, NULL);
! 4109:
! 4110: /*
! 4111: * Clean up.
! 4112: */
! 4113: data_string_forget(&client_id, MDL);
! 4114: }
! 4115:
! 4116: /*
! 4117: * Request is how a client actually requests addresses.
! 4118: *
! 4119: * Very similar to Solicit handling, except the server DUID is required.
! 4120: */
! 4121:
! 4122: /* TODO: reject unicast messages, unless we set unicast option */
! 4123: static void
! 4124: dhcpv6_request(struct data_string *reply_ret, struct packet *packet) {
! 4125: struct data_string client_id;
! 4126: struct data_string server_id;
! 4127:
! 4128: /*
! 4129: * Validate our input.
! 4130: */
! 4131: if (!valid_client_resp(packet, &client_id, &server_id)) {
! 4132: return;
! 4133: }
! 4134:
! 4135: /*
! 4136: * Issue our lease.
! 4137: */
! 4138: lease_to_client(reply_ret, packet, &client_id, &server_id);
! 4139:
! 4140: /*
! 4141: * Cleanup.
! 4142: */
! 4143: data_string_forget(&client_id, MDL);
! 4144: data_string_forget(&server_id, MDL);
! 4145: }
! 4146:
! 4147: /* Find a DHCPv6 packet's shared network from hints in the packet.
! 4148: */
! 4149: static isc_result_t
! 4150: shared_network_from_packet6(struct shared_network **shared,
! 4151: struct packet *packet)
! 4152: {
! 4153: const struct packet *chk_packet;
! 4154: const struct in6_addr *link_addr, *first_link_addr;
! 4155: struct iaddr tmp_addr;
! 4156: struct subnet *subnet;
! 4157: isc_result_t status;
! 4158:
! 4159: if ((shared == NULL) || (*shared != NULL) || (packet == NULL))
! 4160: return ISC_R_INVALIDARG;
! 4161:
! 4162: /*
! 4163: * First, find the link address where the packet from the client
! 4164: * first appeared (if this packet was relayed).
! 4165: */
! 4166: first_link_addr = NULL;
! 4167: chk_packet = packet->dhcpv6_container_packet;
! 4168: while (chk_packet != NULL) {
! 4169: link_addr = &chk_packet->dhcpv6_link_address;
! 4170: if (!IN6_IS_ADDR_UNSPECIFIED(link_addr) &&
! 4171: !IN6_IS_ADDR_LINKLOCAL(link_addr)) {
! 4172: first_link_addr = link_addr;
! 4173: break;
! 4174: }
! 4175: chk_packet = chk_packet->dhcpv6_container_packet;
! 4176: }
! 4177:
! 4178: /*
! 4179: * If there is a relayed link address, find the subnet associated
! 4180: * with that, and use that to get the appropriate
! 4181: * shared_network.
! 4182: */
! 4183: if (first_link_addr != NULL) {
! 4184: tmp_addr.len = sizeof(*first_link_addr);
! 4185: memcpy(tmp_addr.iabuf,
! 4186: first_link_addr, sizeof(*first_link_addr));
! 4187: subnet = NULL;
! 4188: if (!find_subnet(&subnet, tmp_addr, MDL)) {
! 4189: log_debug("No subnet found for link-address %s.",
! 4190: piaddr(tmp_addr));
! 4191: return ISC_R_NOTFOUND;
! 4192: }
! 4193: status = shared_network_reference(shared,
! 4194: subnet->shared_network, MDL);
! 4195: subnet_dereference(&subnet, MDL);
! 4196:
! 4197: /*
! 4198: * If there is no link address, we will use the interface
! 4199: * that this packet came in on to pick the shared_network.
! 4200: */
! 4201: } else if (packet->interface != NULL) {
! 4202: status = shared_network_reference(shared,
! 4203: packet->interface->shared_network,
! 4204: MDL);
! 4205: if (packet->dhcpv6_container_packet != NULL) {
! 4206: log_info("[L2 Relay] No link address in relay packet "
! 4207: "assuming L2 relay and using receiving "
! 4208: "interface");
! 4209: }
! 4210:
! 4211: } else {
! 4212: /*
! 4213: * We shouldn't be able to get here but if there is no link
! 4214: * address and no interface we don't know where to get the
! 4215: * pool from log an error and return an error.
! 4216: */
! 4217: log_error("No interface and no link address "
! 4218: "can't determine pool");
! 4219: status = ISC_R_INVALIDARG;
! 4220: }
! 4221:
! 4222: return status;
! 4223: }
! 4224:
! 4225: /*
! 4226: * When a client thinks it might be on a new link, it sends a
! 4227: * Confirm message.
! 4228: *
! 4229: * From RFC3315 section 18.2.2:
! 4230: *
! 4231: * When the server receives a Confirm message, the server determines
! 4232: * whether the addresses in the Confirm message are appropriate for the
! 4233: * link to which the client is attached. If all of the addresses in the
! 4234: * Confirm message pass this test, the server returns a status of
! 4235: * Success. If any of the addresses do not pass this test, the server
! 4236: * returns a status of NotOnLink. If the server is unable to perform
! 4237: * this test (for example, the server does not have information about
! 4238: * prefixes on the link to which the client is connected), or there were
! 4239: * no addresses in any of the IAs sent by the client, the server MUST
! 4240: * NOT send a reply to the client.
! 4241: */
! 4242:
! 4243: static void
! 4244: dhcpv6_confirm(struct data_string *reply_ret, struct packet *packet) {
! 4245: struct shared_network *shared;
! 4246: struct subnet *subnet;
! 4247: struct option_cache *ia, *ta, *oc;
! 4248: struct data_string cli_enc_opt_data, iaaddr, client_id, packet_oro;
! 4249: struct option_state *cli_enc_opt_state, *opt_state;
! 4250: struct iaddr cli_addr;
! 4251: int pass;
! 4252: isc_boolean_t inappropriate, has_addrs;
! 4253: char reply_data[65536];
! 4254: struct dhcpv6_packet *reply = (struct dhcpv6_packet *)reply_data;
! 4255: int reply_ofs = (int)(offsetof(struct dhcpv6_packet, options));
! 4256:
! 4257: /*
! 4258: * Basic client message validation.
! 4259: */
! 4260: memset(&client_id, 0, sizeof(client_id));
! 4261: if (!valid_client_msg(packet, &client_id)) {
! 4262: return;
! 4263: }
! 4264:
! 4265: /*
! 4266: * Do not process Confirms that do not have IA's we do not recognize.
! 4267: */
! 4268: ia = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA);
! 4269: ta = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_TA);
! 4270: if ((ia == NULL) && (ta == NULL))
! 4271: return;
! 4272:
! 4273: /*
! 4274: * IA_PD's are simply ignored.
! 4275: */
! 4276: delete_option(&dhcpv6_universe, packet->options, D6O_IA_PD);
! 4277:
! 4278: /*
! 4279: * Bit of variable initialization.
! 4280: */
! 4281: opt_state = cli_enc_opt_state = NULL;
! 4282: memset(&cli_enc_opt_data, 0, sizeof(cli_enc_opt_data));
! 4283: memset(&iaaddr, 0, sizeof(iaaddr));
! 4284: memset(&packet_oro, 0, sizeof(packet_oro));
! 4285:
! 4286: /* Determine what shared network the client is connected to. We
! 4287: * must not respond if we don't have any information about the
! 4288: * network the client is on.
! 4289: */
! 4290: shared = NULL;
! 4291: if ((shared_network_from_packet6(&shared, packet) != ISC_R_SUCCESS) ||
! 4292: (shared == NULL))
! 4293: goto exit;
! 4294:
! 4295: /* If there are no recorded subnets, then we have no
! 4296: * information about this subnet - ignore Confirms.
! 4297: */
! 4298: subnet = shared->subnets;
! 4299: if (subnet == NULL)
! 4300: goto exit;
! 4301:
! 4302: /* Are the addresses in all the IA's appropriate for that link? */
! 4303: has_addrs = inappropriate = ISC_FALSE;
! 4304: pass = D6O_IA_NA;
! 4305: while(!inappropriate) {
! 4306: /* If we've reached the end of the IA_NA pass, move to the
! 4307: * IA_TA pass.
! 4308: */
! 4309: if ((pass == D6O_IA_NA) && (ia == NULL)) {
! 4310: pass = D6O_IA_TA;
! 4311: ia = ta;
! 4312: }
! 4313:
! 4314: /* If we've reached the end of all passes, we're done. */
! 4315: if (ia == NULL)
! 4316: break;
! 4317:
! 4318: if (((pass == D6O_IA_NA) &&
! 4319: !get_encapsulated_IA_state(&cli_enc_opt_state,
! 4320: &cli_enc_opt_data,
! 4321: packet, ia, IA_NA_OFFSET)) ||
! 4322: ((pass == D6O_IA_TA) &&
! 4323: !get_encapsulated_IA_state(&cli_enc_opt_state,
! 4324: &cli_enc_opt_data,
! 4325: packet, ia, IA_TA_OFFSET))) {
! 4326: goto exit;
! 4327: }
! 4328:
! 4329: oc = lookup_option(&dhcpv6_universe, cli_enc_opt_state,
! 4330: D6O_IAADDR);
! 4331:
! 4332: for ( ; oc != NULL ; oc = oc->next) {
! 4333: if (!evaluate_option_cache(&iaaddr, packet, NULL, NULL,
! 4334: packet->options, NULL,
! 4335: &global_scope, oc, MDL) ||
! 4336: (iaaddr.len < IAADDR_OFFSET)) {
! 4337: log_error("dhcpv6_confirm: "
! 4338: "error evaluating IAADDR.");
! 4339: goto exit;
! 4340: }
! 4341:
! 4342: /* Copy out the IPv6 address for processing. */
! 4343: cli_addr.len = 16;
! 4344: memcpy(cli_addr.iabuf, iaaddr.data, 16);
! 4345:
! 4346: data_string_forget(&iaaddr, MDL);
! 4347:
! 4348: /* Record that we've processed at least one address. */
! 4349: has_addrs = ISC_TRUE;
! 4350:
! 4351: /* Find out if any subnets cover this address. */
! 4352: for (subnet = shared->subnets ; subnet != NULL ;
! 4353: subnet = subnet->next_sibling) {
! 4354: if (addr_eq(subnet_number(cli_addr,
! 4355: subnet->netmask),
! 4356: subnet->net))
! 4357: break;
! 4358: }
! 4359:
! 4360: /* If we reach the end of the subnet list, and no
! 4361: * subnet matches the client address, then it must
! 4362: * be inappropriate to the link (so far as our
! 4363: * configuration says). Once we've found one
! 4364: * inappropriate address, there is no reason to
! 4365: * continue searching.
! 4366: */
! 4367: if (subnet == NULL) {
! 4368: inappropriate = ISC_TRUE;
! 4369: break;
! 4370: }
! 4371: }
! 4372:
! 4373: option_state_dereference(&cli_enc_opt_state, MDL);
! 4374: data_string_forget(&cli_enc_opt_data, MDL);
! 4375:
! 4376: /* Advance to the next IA_*. */
! 4377: ia = ia->next;
! 4378: }
! 4379:
! 4380: /* If the client supplied no addresses, do not reply. */
! 4381: if (!has_addrs)
! 4382: goto exit;
! 4383:
! 4384: /*
! 4385: * Set up reply.
! 4386: */
! 4387: if (!start_reply(packet, &client_id, NULL, &opt_state, reply)) {
! 4388: goto exit;
! 4389: }
! 4390:
! 4391: /*
! 4392: * Set our status.
! 4393: */
! 4394: if (inappropriate) {
! 4395: if (!set_status_code(STATUS_NotOnLink,
! 4396: "Some of the addresses are not on link.",
! 4397: opt_state)) {
! 4398: goto exit;
! 4399: }
! 4400: } else {
! 4401: if (!set_status_code(STATUS_Success,
! 4402: "All addresses still on link.",
! 4403: opt_state)) {
! 4404: goto exit;
! 4405: }
! 4406: }
! 4407:
! 4408: /*
! 4409: * Only one option: add it.
! 4410: */
! 4411: reply_ofs += store_options6(reply_data+reply_ofs,
! 4412: sizeof(reply_data)-reply_ofs,
! 4413: opt_state, packet,
! 4414: required_opts, &packet_oro);
! 4415:
! 4416: /*
! 4417: * Return our reply to the caller.
! 4418: */
! 4419: reply_ret->len = reply_ofs;
! 4420: reply_ret->buffer = NULL;
! 4421: if (!buffer_allocate(&reply_ret->buffer, reply_ofs, MDL)) {
! 4422: log_fatal("No memory to store reply.");
! 4423: }
! 4424: reply_ret->data = reply_ret->buffer->data;
! 4425: memcpy(reply_ret->buffer->data, reply, reply_ofs);
! 4426:
! 4427: exit:
! 4428: /* Cleanup any stale data strings. */
! 4429: if (cli_enc_opt_data.buffer != NULL)
! 4430: data_string_forget(&cli_enc_opt_data, MDL);
! 4431: if (iaaddr.buffer != NULL)
! 4432: data_string_forget(&iaaddr, MDL);
! 4433: if (client_id.buffer != NULL)
! 4434: data_string_forget(&client_id, MDL);
! 4435: if (packet_oro.buffer != NULL)
! 4436: data_string_forget(&packet_oro, MDL);
! 4437:
! 4438: /* Release any stale option states. */
! 4439: if (cli_enc_opt_state != NULL)
! 4440: option_state_dereference(&cli_enc_opt_state, MDL);
! 4441: if (opt_state != NULL)
! 4442: option_state_dereference(&opt_state, MDL);
! 4443: }
! 4444:
! 4445: /*
! 4446: * Renew is when a client wants to extend its lease/prefix, at time T1.
! 4447: *
! 4448: * We handle this the same as if the client wants a new lease/prefix,
! 4449: * except for the error code of when addresses don't match.
! 4450: */
! 4451:
! 4452: /* TODO: reject unicast messages, unless we set unicast option */
! 4453: static void
! 4454: dhcpv6_renew(struct data_string *reply, struct packet *packet) {
! 4455: struct data_string client_id;
! 4456: struct data_string server_id;
! 4457:
! 4458: /*
! 4459: * Validate the request.
! 4460: */
! 4461: if (!valid_client_resp(packet, &client_id, &server_id)) {
! 4462: return;
! 4463: }
! 4464:
! 4465: /*
! 4466: * Renew our lease.
! 4467: */
! 4468: lease_to_client(reply, packet, &client_id, &server_id);
! 4469:
! 4470: /*
! 4471: * Cleanup.
! 4472: */
! 4473: data_string_forget(&server_id, MDL);
! 4474: data_string_forget(&client_id, MDL);
! 4475: }
! 4476:
! 4477: /*
! 4478: * Rebind is when a client wants to extend its lease, at time T2.
! 4479: *
! 4480: * We handle this the same as if the client wants a new lease, except
! 4481: * for the error code of when addresses don't match.
! 4482: */
! 4483:
! 4484: static void
! 4485: dhcpv6_rebind(struct data_string *reply, struct packet *packet) {
! 4486: struct data_string client_id;
! 4487:
! 4488: if (!valid_client_msg(packet, &client_id)) {
! 4489: return;
! 4490: }
! 4491:
! 4492: lease_to_client(reply, packet, &client_id, NULL);
! 4493:
! 4494: data_string_forget(&client_id, MDL);
! 4495: }
! 4496:
! 4497: static void
! 4498: ia_na_match_decline(const struct data_string *client_id,
! 4499: const struct data_string *iaaddr,
! 4500: struct iasubopt *lease)
! 4501: {
! 4502: char tmp_addr[INET6_ADDRSTRLEN];
! 4503:
! 4504: log_error("Client %s reports address %s is "
! 4505: "already in use by another host!",
! 4506: print_hex_1(client_id->len, client_id->data, 60),
! 4507: inet_ntop(AF_INET6, iaaddr->data,
! 4508: tmp_addr, sizeof(tmp_addr)));
! 4509: if (lease != NULL) {
! 4510: decline_lease6(lease->ipv6_pool, lease);
! 4511: lease->ia->cltt = cur_time;
! 4512: write_ia(lease->ia);
! 4513: }
! 4514: }
! 4515:
! 4516: static void
! 4517: ia_na_nomatch_decline(const struct data_string *client_id,
! 4518: const struct data_string *iaaddr,
! 4519: u_int32_t *ia_na_id,
! 4520: struct packet *packet,
! 4521: char *reply_data,
! 4522: int *reply_ofs,
! 4523: int reply_len)
! 4524: {
! 4525: char tmp_addr[INET6_ADDRSTRLEN];
! 4526: struct option_state *host_opt_state;
! 4527: int len;
! 4528:
! 4529: log_info("Client %s declines address %s, which is not offered to it.",
! 4530: print_hex_1(client_id->len, client_id->data, 60),
! 4531: inet_ntop(AF_INET6, iaaddr->data, tmp_addr, sizeof(tmp_addr)));
! 4532:
! 4533: /*
! 4534: * Create state for this IA_NA.
! 4535: */
! 4536: host_opt_state = NULL;
! 4537: if (!option_state_allocate(&host_opt_state, MDL)) {
! 4538: log_error("ia_na_nomatch_decline: out of memory "
! 4539: "allocating option_state.");
! 4540: goto exit;
! 4541: }
! 4542:
! 4543: if (!set_status_code(STATUS_NoBinding, "Decline for unknown address.",
! 4544: host_opt_state)) {
! 4545: goto exit;
! 4546: }
! 4547:
! 4548: /*
! 4549: * Insure we have enough space
! 4550: */
! 4551: if (reply_len < (*reply_ofs + 16)) {
! 4552: log_error("ia_na_nomatch_decline: "
! 4553: "out of space for reply packet.");
! 4554: goto exit;
! 4555: }
! 4556:
! 4557: /*
! 4558: * Put our status code into the reply packet.
! 4559: */
! 4560: len = store_options6(reply_data+(*reply_ofs)+16,
! 4561: reply_len-(*reply_ofs)-16,
! 4562: host_opt_state, packet,
! 4563: required_opts_STATUS_CODE, NULL);
! 4564:
! 4565: /*
! 4566: * Store the non-encapsulated option data for this
! 4567: * IA_NA into our reply packet. Defined in RFC 3315,
! 4568: * section 22.4.
! 4569: */
! 4570: /* option number */
! 4571: putUShort((unsigned char *)reply_data+(*reply_ofs), D6O_IA_NA);
! 4572: /* option length */
! 4573: putUShort((unsigned char *)reply_data+(*reply_ofs)+2, len + 12);
! 4574: /* IA_NA, copied from the client */
! 4575: memcpy(reply_data+(*reply_ofs)+4, ia_na_id, 4);
! 4576: /* t1 and t2, odd that we need them, but here it is */
! 4577: putULong((unsigned char *)reply_data+(*reply_ofs)+8, 0);
! 4578: putULong((unsigned char *)reply_data+(*reply_ofs)+12, 0);
! 4579:
! 4580: /*
! 4581: * Get ready for next IA_NA.
! 4582: */
! 4583: *reply_ofs += (len + 16);
! 4584:
! 4585: exit:
! 4586: option_state_dereference(&host_opt_state, MDL);
! 4587: }
! 4588:
! 4589: static void
! 4590: iterate_over_ia_na(struct data_string *reply_ret,
! 4591: struct packet *packet,
! 4592: const struct data_string *client_id,
! 4593: const struct data_string *server_id,
! 4594: const char *packet_type,
! 4595: void (*ia_na_match)(),
! 4596: void (*ia_na_nomatch)())
! 4597: {
! 4598: struct option_state *opt_state;
! 4599: struct host_decl *packet_host;
! 4600: struct option_cache *ia;
! 4601: struct option_cache *oc;
! 4602: /* cli_enc_... variables come from the IA_NA/IA_TA options */
! 4603: struct data_string cli_enc_opt_data;
! 4604: struct option_state *cli_enc_opt_state;
! 4605: struct host_decl *host;
! 4606: struct option_state *host_opt_state;
! 4607: struct data_string iaaddr;
! 4608: struct data_string fixed_addr;
! 4609: int iaaddr_is_found;
! 4610: char reply_data[65536];
! 4611: struct dhcpv6_packet *reply = (struct dhcpv6_packet *)reply_data;
! 4612: int reply_ofs = (int)(offsetof(struct dhcpv6_packet, options));
! 4613: char status_msg[32];
! 4614: struct iasubopt *lease;
! 4615: struct ia_xx *existing_ia_na;
! 4616: int i;
! 4617: struct data_string key;
! 4618: u_int32_t iaid;
! 4619:
! 4620: /*
! 4621: * Initialize to empty values, in case we have to exit early.
! 4622: */
! 4623: opt_state = NULL;
! 4624: memset(&cli_enc_opt_data, 0, sizeof(cli_enc_opt_data));
! 4625: cli_enc_opt_state = NULL;
! 4626: memset(&iaaddr, 0, sizeof(iaaddr));
! 4627: memset(&fixed_addr, 0, sizeof(fixed_addr));
! 4628: host_opt_state = NULL;
! 4629: lease = NULL;
! 4630:
! 4631: /*
! 4632: * Find the host record that matches from the packet, if any.
! 4633: */
! 4634: packet_host = NULL;
! 4635: if (!find_hosts_by_uid(&packet_host,
! 4636: client_id->data, client_id->len, MDL)) {
! 4637: packet_host = NULL;
! 4638: /*
! 4639: * Note: In general, we don't expect a client to provide
! 4640: * enough information to match by option for these
! 4641: * types of messages, but if we don't have a UID
! 4642: * match we can check anyway.
! 4643: */
! 4644: if (!find_hosts_by_option(&packet_host,
! 4645: packet, packet->options, MDL)) {
! 4646: packet_host = NULL;
! 4647: }
! 4648: }
! 4649:
! 4650: /*
! 4651: * Set our reply information.
! 4652: */
! 4653: reply->msg_type = DHCPV6_REPLY;
! 4654: memcpy(reply->transaction_id, packet->dhcpv6_transaction_id,
! 4655: sizeof(reply->transaction_id));
! 4656:
! 4657: /*
! 4658: * Build our option state for reply.
! 4659: */
! 4660: opt_state = NULL;
! 4661: if (!option_state_allocate(&opt_state, MDL)) {
! 4662: log_error("iterate_over_ia_na: no memory for option_state.");
! 4663: goto exit;
! 4664: }
! 4665: execute_statements_in_scope(NULL, packet, NULL, NULL,
! 4666: packet->options, opt_state,
! 4667: &global_scope, root_group, NULL);
! 4668:
! 4669: /*
! 4670: * RFC 3315, section 18.2.7 tells us which options to include.
! 4671: */
! 4672: oc = lookup_option(&dhcpv6_universe, opt_state, D6O_SERVERID);
! 4673: if (oc == NULL) {
! 4674: if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL,
! 4675: (unsigned char *)server_duid.data,
! 4676: server_duid.len, D6O_SERVERID, 0)) {
! 4677: log_error("iterate_over_ia_na: "
! 4678: "error saving server identifier.");
! 4679: goto exit;
! 4680: }
! 4681: }
! 4682:
! 4683: if (!save_option_buffer(&dhcpv6_universe, opt_state,
! 4684: client_id->buffer,
! 4685: (unsigned char *)client_id->data,
! 4686: client_id->len,
! 4687: D6O_CLIENTID, 0)) {
! 4688: log_error("iterate_over_ia_na: "
! 4689: "error saving client identifier.");
! 4690: goto exit;
! 4691: }
! 4692:
! 4693: snprintf(status_msg, sizeof(status_msg), "%s received.", packet_type);
! 4694: if (!set_status_code(STATUS_Success, status_msg, opt_state)) {
! 4695: goto exit;
! 4696: }
! 4697:
! 4698: /*
! 4699: * Add our options that are not associated with any IA_NA or IA_TA.
! 4700: */
! 4701: reply_ofs += store_options6(reply_data+reply_ofs,
! 4702: sizeof(reply_data)-reply_ofs,
! 4703: opt_state, packet,
! 4704: required_opts, NULL);
! 4705:
! 4706: /*
! 4707: * Loop through the IA_NA reported by the client, and deal with
! 4708: * addresses reported as already in use.
! 4709: */
! 4710: for (ia = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA);
! 4711: ia != NULL; ia = ia->next) {
! 4712: iaaddr_is_found = 0;
! 4713:
! 4714: if (!get_encapsulated_IA_state(&cli_enc_opt_state,
! 4715: &cli_enc_opt_data,
! 4716: packet, ia, IA_NA_OFFSET)) {
! 4717: goto exit;
! 4718: }
! 4719:
! 4720: iaid = getULong(cli_enc_opt_data.data);
! 4721:
! 4722: /*
! 4723: * XXX: It is possible that we can get multiple addresses
! 4724: * sent by the client. We don't send multiple
! 4725: * addresses, so this indicates a client error.
! 4726: * We should check for multiple IAADDR options, log
! 4727: * if found, and set as an error.
! 4728: */
! 4729: oc = lookup_option(&dhcpv6_universe, cli_enc_opt_state,
! 4730: D6O_IAADDR);
! 4731: if (oc == NULL) {
! 4732: /* no address given for this IA, ignore */
! 4733: option_state_dereference(&cli_enc_opt_state, MDL);
! 4734: data_string_forget(&cli_enc_opt_data, MDL);
! 4735: continue;
! 4736: }
! 4737:
! 4738: memset(&iaaddr, 0, sizeof(iaaddr));
! 4739: if (!evaluate_option_cache(&iaaddr, packet, NULL, NULL,
! 4740: packet->options, NULL,
! 4741: &global_scope, oc, MDL)) {
! 4742: log_error("iterate_over_ia_na: "
! 4743: "error evaluating IAADDR.");
! 4744: goto exit;
! 4745: }
! 4746:
! 4747: /*
! 4748: * Now we need to figure out which host record matches
! 4749: * this IA_NA and IAADDR.
! 4750: *
! 4751: * XXX: We don't currently track IA_NA separately, but
! 4752: * we will need to do this!
! 4753: */
! 4754: host = NULL;
! 4755: if (!find_hosts_by_option(&host, packet,
! 4756: cli_enc_opt_state, MDL)) {
! 4757: if (packet_host != NULL) {
! 4758: host = packet_host;
! 4759: } else {
! 4760: host = NULL;
! 4761: }
! 4762: }
! 4763: while (host != NULL) {
! 4764: if (host->fixed_addr != NULL) {
! 4765: if (!evaluate_option_cache(&fixed_addr, NULL,
! 4766: NULL, NULL, NULL,
! 4767: NULL, &global_scope,
! 4768: host->fixed_addr,
! 4769: MDL)) {
! 4770: log_error("iterate_over_ia_na: error "
! 4771: "evaluating host address.");
! 4772: goto exit;
! 4773: }
! 4774: if ((iaaddr.len >= 16) &&
! 4775: !memcmp(fixed_addr.data, iaaddr.data, 16)) {
! 4776: data_string_forget(&fixed_addr, MDL);
! 4777: break;
! 4778: }
! 4779: data_string_forget(&fixed_addr, MDL);
! 4780: }
! 4781: host = host->n_ipaddr;
! 4782: }
! 4783:
! 4784: if ((host == NULL) && (iaaddr.len >= IAADDR_OFFSET)) {
! 4785: /*
! 4786: * Find existing IA_NA.
! 4787: */
! 4788: if (ia_make_key(&key, iaid,
! 4789: (char *)client_id->data,
! 4790: client_id->len,
! 4791: MDL) != ISC_R_SUCCESS) {
! 4792: log_fatal("iterate_over_ia_na: no memory for "
! 4793: "key.");
! 4794: }
! 4795:
! 4796: existing_ia_na = NULL;
! 4797: if (ia_hash_lookup(&existing_ia_na, ia_na_active,
! 4798: (unsigned char *)key.data,
! 4799: key.len, MDL)) {
! 4800: /*
! 4801: * Make sure this address is in the IA_NA.
! 4802: */
! 4803: for (i=0; i<existing_ia_na->num_iasubopt; i++) {
! 4804: struct iasubopt *tmp;
! 4805: struct in6_addr *in6_addr;
! 4806:
! 4807: tmp = existing_ia_na->iasubopt[i];
! 4808: in6_addr = &tmp->addr;
! 4809: if (memcmp(in6_addr,
! 4810: iaaddr.data, 16) == 0) {
! 4811: iasubopt_reference(&lease,
! 4812: tmp, MDL);
! 4813: break;
! 4814: }
! 4815: }
! 4816: }
! 4817:
! 4818: data_string_forget(&key, MDL);
! 4819: }
! 4820:
! 4821: if ((host != NULL) || (lease != NULL)) {
! 4822: ia_na_match(client_id, &iaaddr, lease);
! 4823: } else {
! 4824: ia_na_nomatch(client_id, &iaaddr,
! 4825: (u_int32_t *)cli_enc_opt_data.data,
! 4826: packet, reply_data, &reply_ofs,
! 4827: sizeof(reply_data));
! 4828: }
! 4829:
! 4830: if (lease != NULL) {
! 4831: iasubopt_dereference(&lease, MDL);
! 4832: }
! 4833:
! 4834: data_string_forget(&iaaddr, MDL);
! 4835: option_state_dereference(&cli_enc_opt_state, MDL);
! 4836: data_string_forget(&cli_enc_opt_data, MDL);
! 4837: }
! 4838:
! 4839: /*
! 4840: * Return our reply to the caller.
! 4841: */
! 4842: reply_ret->len = reply_ofs;
! 4843: reply_ret->buffer = NULL;
! 4844: if (!buffer_allocate(&reply_ret->buffer, reply_ofs, MDL)) {
! 4845: log_fatal("No memory to store reply.");
! 4846: }
! 4847: reply_ret->data = reply_ret->buffer->data;
! 4848: memcpy(reply_ret->buffer->data, reply, reply_ofs);
! 4849:
! 4850: exit:
! 4851: if (lease != NULL) {
! 4852: iasubopt_dereference(&lease, MDL);
! 4853: }
! 4854: if (host_opt_state != NULL) {
! 4855: option_state_dereference(&host_opt_state, MDL);
! 4856: }
! 4857: if (fixed_addr.buffer != NULL) {
! 4858: data_string_forget(&fixed_addr, MDL);
! 4859: }
! 4860: if (iaaddr.buffer != NULL) {
! 4861: data_string_forget(&iaaddr, MDL);
! 4862: }
! 4863: if (cli_enc_opt_state != NULL) {
! 4864: option_state_dereference(&cli_enc_opt_state, MDL);
! 4865: }
! 4866: if (cli_enc_opt_data.buffer != NULL) {
! 4867: data_string_forget(&cli_enc_opt_data, MDL);
! 4868: }
! 4869: if (opt_state != NULL) {
! 4870: option_state_dereference(&opt_state, MDL);
! 4871: }
! 4872: }
! 4873:
! 4874: /*
! 4875: * Decline means a client has detected that something else is using an
! 4876: * address we gave it.
! 4877: *
! 4878: * Since we're only dealing with fixed leases for now, there's not
! 4879: * much we can do, other that log the occurrence.
! 4880: *
! 4881: * When we start issuing addresses from pools, then we will have to
! 4882: * record our declined addresses and issue another. In general with
! 4883: * IPv6 there is no worry about DoS by clients exhausting space, but
! 4884: * we still need to be aware of this possibility.
! 4885: */
! 4886:
! 4887: /* TODO: reject unicast messages, unless we set unicast option */
! 4888: /* TODO: IA_TA */
! 4889: static void
! 4890: dhcpv6_decline(struct data_string *reply, struct packet *packet) {
! 4891: struct data_string client_id;
! 4892: struct data_string server_id;
! 4893:
! 4894: /*
! 4895: * Validate our input.
! 4896: */
! 4897: if (!valid_client_resp(packet, &client_id, &server_id)) {
! 4898: return;
! 4899: }
! 4900:
! 4901: /*
! 4902: * Undefined for IA_PD.
! 4903: */
! 4904: delete_option(&dhcpv6_universe, packet->options, D6O_IA_PD);
! 4905:
! 4906: /*
! 4907: * And operate on each IA_NA in this packet.
! 4908: */
! 4909: iterate_over_ia_na(reply, packet, &client_id, &server_id, "Decline",
! 4910: ia_na_match_decline, ia_na_nomatch_decline);
! 4911:
! 4912: data_string_forget(&server_id, MDL);
! 4913: data_string_forget(&client_id, MDL);
! 4914: }
! 4915:
! 4916: static void
! 4917: ia_na_match_release(const struct data_string *client_id,
! 4918: const struct data_string *iaaddr,
! 4919: struct iasubopt *lease)
! 4920: {
! 4921: char tmp_addr[INET6_ADDRSTRLEN];
! 4922:
! 4923: log_info("Client %s releases address %s",
! 4924: print_hex_1(client_id->len, client_id->data, 60),
! 4925: inet_ntop(AF_INET6, iaaddr->data, tmp_addr, sizeof(tmp_addr)));
! 4926: if (lease != NULL) {
! 4927: release_lease6(lease->ipv6_pool, lease);
! 4928: lease->ia->cltt = cur_time;
! 4929: write_ia(lease->ia);
! 4930: }
! 4931: }
! 4932:
! 4933: static void
! 4934: ia_na_nomatch_release(const struct data_string *client_id,
! 4935: const struct data_string *iaaddr,
! 4936: u_int32_t *ia_na_id,
! 4937: struct packet *packet,
! 4938: char *reply_data,
! 4939: int *reply_ofs,
! 4940: int reply_len)
! 4941: {
! 4942: char tmp_addr[INET6_ADDRSTRLEN];
! 4943: struct option_state *host_opt_state;
! 4944: int len;
! 4945:
! 4946: log_info("Client %s releases address %s, which is not leased to it.",
! 4947: print_hex_1(client_id->len, client_id->data, 60),
! 4948: inet_ntop(AF_INET6, iaaddr->data, tmp_addr, sizeof(tmp_addr)));
! 4949:
! 4950: /*
! 4951: * Create state for this IA_NA.
! 4952: */
! 4953: host_opt_state = NULL;
! 4954: if (!option_state_allocate(&host_opt_state, MDL)) {
! 4955: log_error("ia_na_nomatch_release: out of memory "
! 4956: "allocating option_state.");
! 4957: goto exit;
! 4958: }
! 4959:
! 4960: if (!set_status_code(STATUS_NoBinding,
! 4961: "Release for non-leased address.",
! 4962: host_opt_state)) {
! 4963: goto exit;
! 4964: }
! 4965:
! 4966: /*
! 4967: * Insure we have enough space
! 4968: */
! 4969: if (reply_len < (*reply_ofs + 16)) {
! 4970: log_error("ia_na_nomatch_release: "
! 4971: "out of space for reply packet.");
! 4972: goto exit;
! 4973: }
! 4974:
! 4975: /*
! 4976: * Put our status code into the reply packet.
! 4977: */
! 4978: len = store_options6(reply_data+(*reply_ofs)+16,
! 4979: reply_len-(*reply_ofs)-16,
! 4980: host_opt_state, packet,
! 4981: required_opts_STATUS_CODE, NULL);
! 4982:
! 4983: /*
! 4984: * Store the non-encapsulated option data for this
! 4985: * IA_NA into our reply packet. Defined in RFC 3315,
! 4986: * section 22.4.
! 4987: */
! 4988: /* option number */
! 4989: putUShort((unsigned char *)reply_data+(*reply_ofs), D6O_IA_NA);
! 4990: /* option length */
! 4991: putUShort((unsigned char *)reply_data+(*reply_ofs)+2, len + 12);
! 4992: /* IA_NA, copied from the client */
! 4993: memcpy(reply_data+(*reply_ofs)+4, ia_na_id, 4);
! 4994: /* t1 and t2, odd that we need them, but here it is */
! 4995: putULong((unsigned char *)reply_data+(*reply_ofs)+8, 0);
! 4996: putULong((unsigned char *)reply_data+(*reply_ofs)+12, 0);
! 4997:
! 4998: /*
! 4999: * Get ready for next IA_NA.
! 5000: */
! 5001: *reply_ofs += (len + 16);
! 5002:
! 5003: exit:
! 5004: option_state_dereference(&host_opt_state, MDL);
! 5005: }
! 5006:
! 5007: static void
! 5008: ia_pd_match_release(const struct data_string *client_id,
! 5009: const struct data_string *iapref,
! 5010: struct iasubopt *prefix)
! 5011: {
! 5012: char tmp_addr[INET6_ADDRSTRLEN];
! 5013:
! 5014: log_info("Client %s releases prefix %s/%u",
! 5015: print_hex_1(client_id->len, client_id->data, 60),
! 5016: inet_ntop(AF_INET6, iapref->data + 9,
! 5017: tmp_addr, sizeof(tmp_addr)),
! 5018: (unsigned) getUChar(iapref->data + 8));
! 5019: if (prefix != NULL) {
! 5020: release_lease6(prefix->ipv6_pool, prefix);
! 5021: prefix->ia->cltt = cur_time;
! 5022: write_ia(prefix->ia);
! 5023: }
! 5024: }
! 5025:
! 5026: static void
! 5027: ia_pd_nomatch_release(const struct data_string *client_id,
! 5028: const struct data_string *iapref,
! 5029: u_int32_t *ia_pd_id,
! 5030: struct packet *packet,
! 5031: char *reply_data,
! 5032: int *reply_ofs,
! 5033: int reply_len)
! 5034: {
! 5035: char tmp_addr[INET6_ADDRSTRLEN];
! 5036: struct option_state *host_opt_state;
! 5037: int len;
! 5038:
! 5039: log_info("Client %s releases prefix %s/%u, which is not leased to it.",
! 5040: print_hex_1(client_id->len, client_id->data, 60),
! 5041: inet_ntop(AF_INET6, iapref->data + 9,
! 5042: tmp_addr, sizeof(tmp_addr)),
! 5043: (unsigned) getUChar(iapref->data + 8));
! 5044:
! 5045: /*
! 5046: * Create state for this IA_PD.
! 5047: */
! 5048: host_opt_state = NULL;
! 5049: if (!option_state_allocate(&host_opt_state, MDL)) {
! 5050: log_error("ia_pd_nomatch_release: out of memory "
! 5051: "allocating option_state.");
! 5052: goto exit;
! 5053: }
! 5054:
! 5055: if (!set_status_code(STATUS_NoBinding,
! 5056: "Release for non-leased prefix.",
! 5057: host_opt_state)) {
! 5058: goto exit;
! 5059: }
! 5060:
! 5061: /*
! 5062: * Insure we have enough space
! 5063: */
! 5064: if (reply_len < (*reply_ofs + 16)) {
! 5065: log_error("ia_pd_nomatch_release: "
! 5066: "out of space for reply packet.");
! 5067: goto exit;
! 5068: }
! 5069:
! 5070: /*
! 5071: * Put our status code into the reply packet.
! 5072: */
! 5073: len = store_options6(reply_data+(*reply_ofs)+16,
! 5074: reply_len-(*reply_ofs)-16,
! 5075: host_opt_state, packet,
! 5076: required_opts_STATUS_CODE, NULL);
! 5077:
! 5078: /*
! 5079: * Store the non-encapsulated option data for this
! 5080: * IA_PD into our reply packet. Defined in RFC 3315,
! 5081: * section 22.4.
! 5082: */
! 5083: /* option number */
! 5084: putUShort((unsigned char *)reply_data+(*reply_ofs), D6O_IA_PD);
! 5085: /* option length */
! 5086: putUShort((unsigned char *)reply_data+(*reply_ofs)+2, len + 12);
! 5087: /* IA_PD, copied from the client */
! 5088: memcpy(reply_data+(*reply_ofs)+4, ia_pd_id, 4);
! 5089: /* t1 and t2, odd that we need them, but here it is */
! 5090: putULong((unsigned char *)reply_data+(*reply_ofs)+8, 0);
! 5091: putULong((unsigned char *)reply_data+(*reply_ofs)+12, 0);
! 5092:
! 5093: /*
! 5094: * Get ready for next IA_PD.
! 5095: */
! 5096: *reply_ofs += (len + 16);
! 5097:
! 5098: exit:
! 5099: option_state_dereference(&host_opt_state, MDL);
! 5100: }
! 5101:
! 5102: static void
! 5103: iterate_over_ia_pd(struct data_string *reply_ret,
! 5104: struct packet *packet,
! 5105: const struct data_string *client_id,
! 5106: const struct data_string *server_id,
! 5107: const char *packet_type,
! 5108: void (*ia_pd_match)(),
! 5109: void (*ia_pd_nomatch)())
! 5110: {
! 5111: struct data_string reply_new;
! 5112: int reply_len;
! 5113: struct option_state *opt_state;
! 5114: struct host_decl *packet_host;
! 5115: struct option_cache *ia;
! 5116: struct option_cache *oc;
! 5117: /* cli_enc_... variables come from the IA_PD options */
! 5118: struct data_string cli_enc_opt_data;
! 5119: struct option_state *cli_enc_opt_state;
! 5120: struct host_decl *host;
! 5121: struct option_state *host_opt_state;
! 5122: struct data_string iaprefix;
! 5123: int iaprefix_is_found;
! 5124: char reply_data[65536];
! 5125: int reply_ofs;
! 5126: struct iasubopt *prefix;
! 5127: struct ia_xx *existing_ia_pd;
! 5128: int i;
! 5129: struct data_string key;
! 5130: u_int32_t iaid;
! 5131:
! 5132: /*
! 5133: * Initialize to empty values, in case we have to exit early.
! 5134: */
! 5135: memset(&reply_new, 0, sizeof(reply_new));
! 5136: opt_state = NULL;
! 5137: memset(&cli_enc_opt_data, 0, sizeof(cli_enc_opt_data));
! 5138: cli_enc_opt_state = NULL;
! 5139: memset(&iaprefix, 0, sizeof(iaprefix));
! 5140: host_opt_state = NULL;
! 5141: prefix = NULL;
! 5142:
! 5143: /*
! 5144: * Compute the available length for the reply.
! 5145: */
! 5146: reply_len = sizeof(reply_data) - reply_ret->len;
! 5147: reply_ofs = 0;
! 5148:
! 5149: /*
! 5150: * Find the host record that matches from the packet, if any.
! 5151: */
! 5152: packet_host = NULL;
! 5153: if (!find_hosts_by_uid(&packet_host,
! 5154: client_id->data, client_id->len, MDL)) {
! 5155: packet_host = NULL;
! 5156: /*
! 5157: * Note: In general, we don't expect a client to provide
! 5158: * enough information to match by option for these
! 5159: * types of messages, but if we don't have a UID
! 5160: * match we can check anyway.
! 5161: */
! 5162: if (!find_hosts_by_option(&packet_host,
! 5163: packet, packet->options, MDL)) {
! 5164: packet_host = NULL;
! 5165: }
! 5166: }
! 5167:
! 5168: /*
! 5169: * Build our option state for reply.
! 5170: */
! 5171: opt_state = NULL;
! 5172: if (!option_state_allocate(&opt_state, MDL)) {
! 5173: log_error("iterate_over_ia_pd: no memory for option_state.");
! 5174: goto exit;
! 5175: }
! 5176: execute_statements_in_scope(NULL, packet, NULL, NULL,
! 5177: packet->options, opt_state,
! 5178: &global_scope, root_group, NULL);
! 5179:
! 5180: /*
! 5181: * Loop through the IA_PD reported by the client, and deal with
! 5182: * prefixes reported as already in use.
! 5183: */
! 5184: for (ia = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_PD);
! 5185: ia != NULL; ia = ia->next) {
! 5186: iaprefix_is_found = 0;
! 5187:
! 5188: if (!get_encapsulated_IA_state(&cli_enc_opt_state,
! 5189: &cli_enc_opt_data,
! 5190: packet, ia, IA_PD_OFFSET)) {
! 5191: goto exit;
! 5192: }
! 5193:
! 5194: iaid = getULong(cli_enc_opt_data.data);
! 5195:
! 5196: oc = lookup_option(&dhcpv6_universe, cli_enc_opt_state,
! 5197: D6O_IAPREFIX);
! 5198: if (oc == NULL) {
! 5199: /* no prefix given for this IA_PD, ignore */
! 5200: option_state_dereference(&cli_enc_opt_state, MDL);
! 5201: data_string_forget(&cli_enc_opt_data, MDL);
! 5202: continue;
! 5203: }
! 5204:
! 5205: for (; oc != NULL; oc = oc->next) {
! 5206: memset(&iaprefix, 0, sizeof(iaprefix));
! 5207: if (!evaluate_option_cache(&iaprefix, packet, NULL, NULL,
! 5208: packet->options, NULL,
! 5209: &global_scope, oc, MDL)) {
! 5210: log_error("iterate_over_ia_pd: "
! 5211: "error evaluating IAPREFIX.");
! 5212: goto exit;
! 5213: }
! 5214:
! 5215: /*
! 5216: * Now we need to figure out which host record matches
! 5217: * this IA_PD and IAPREFIX.
! 5218: *
! 5219: * XXX: We don't currently track IA_PD separately, but
! 5220: * we will need to do this!
! 5221: */
! 5222: host = NULL;
! 5223: if (!find_hosts_by_option(&host, packet,
! 5224: cli_enc_opt_state, MDL)) {
! 5225: if (packet_host != NULL) {
! 5226: host = packet_host;
! 5227: } else {
! 5228: host = NULL;
! 5229: }
! 5230: }
! 5231: while (host != NULL) {
! 5232: if (host->fixed_prefix != NULL) {
! 5233: struct iaddrcidrnetlist *l;
! 5234: int plen = (int) getUChar(iaprefix.data + 8);
! 5235:
! 5236: for (l = host->fixed_prefix; l != NULL;
! 5237: l = l->next) {
! 5238: if (plen != l->cidrnet.bits)
! 5239: continue;
! 5240: if (memcmp(iaprefix.data + 9,
! 5241: l->cidrnet.lo_addr.iabuf,
! 5242: 16) == 0)
! 5243: break;
! 5244: }
! 5245: if ((l != NULL) && (iaprefix.len >= 17))
! 5246: break;
! 5247: }
! 5248: host = host->n_ipaddr;
! 5249: }
! 5250:
! 5251: if ((host == NULL) && (iaprefix.len >= IAPREFIX_OFFSET)) {
! 5252: /*
! 5253: * Find existing IA_PD.
! 5254: */
! 5255: if (ia_make_key(&key, iaid,
! 5256: (char *)client_id->data,
! 5257: client_id->len,
! 5258: MDL) != ISC_R_SUCCESS) {
! 5259: log_fatal("iterate_over_ia_pd: no memory for "
! 5260: "key.");
! 5261: }
! 5262:
! 5263: existing_ia_pd = NULL;
! 5264: if (ia_hash_lookup(&existing_ia_pd, ia_pd_active,
! 5265: (unsigned char *)key.data,
! 5266: key.len, MDL)) {
! 5267: /*
! 5268: * Make sure this prefix is in the IA_PD.
! 5269: */
! 5270: for (i = 0;
! 5271: i < existing_ia_pd->num_iasubopt;
! 5272: i++) {
! 5273: struct iasubopt *tmp;
! 5274: u_int8_t plen;
! 5275:
! 5276: plen = getUChar(iaprefix.data + 8);
! 5277: tmp = existing_ia_pd->iasubopt[i];
! 5278: if ((tmp->plen == plen) &&
! 5279: (memcmp(&tmp->addr,
! 5280: iaprefix.data + 9,
! 5281: 16) == 0)) {
! 5282: iasubopt_reference(&prefix,
! 5283: tmp, MDL);
! 5284: break;
! 5285: }
! 5286: }
! 5287: }
! 5288:
! 5289: data_string_forget(&key, MDL);
! 5290: }
! 5291:
! 5292: if ((host != NULL) || (prefix != NULL)) {
! 5293: ia_pd_match(client_id, &iaprefix, prefix);
! 5294: } else {
! 5295: ia_pd_nomatch(client_id, &iaprefix,
! 5296: (u_int32_t *)cli_enc_opt_data.data,
! 5297: packet, reply_data, &reply_ofs,
! 5298: reply_len - reply_ofs);
! 5299: }
! 5300:
! 5301: if (prefix != NULL) {
! 5302: iasubopt_dereference(&prefix, MDL);
! 5303: }
! 5304:
! 5305: data_string_forget(&iaprefix, MDL);
! 5306: }
! 5307:
! 5308: option_state_dereference(&cli_enc_opt_state, MDL);
! 5309: data_string_forget(&cli_enc_opt_data, MDL);
! 5310: }
! 5311:
! 5312: /*
! 5313: * Return our reply to the caller.
! 5314: * The IA_NA routine has already filled at least the header.
! 5315: */
! 5316: reply_new.len = reply_ret->len + reply_ofs;
! 5317: if (!buffer_allocate(&reply_new.buffer, reply_new.len, MDL)) {
! 5318: log_fatal("No memory to store reply.");
! 5319: }
! 5320: reply_new.data = reply_new.buffer->data;
! 5321: memcpy(reply_new.buffer->data,
! 5322: reply_ret->buffer->data, reply_ret->len);
! 5323: memcpy(reply_new.buffer->data + reply_ret->len,
! 5324: reply_data, reply_ofs);
! 5325: data_string_forget(reply_ret, MDL);
! 5326: data_string_copy(reply_ret, &reply_new, MDL);
! 5327: data_string_forget(&reply_new, MDL);
! 5328:
! 5329: exit:
! 5330: if (prefix != NULL) {
! 5331: iasubopt_dereference(&prefix, MDL);
! 5332: }
! 5333: if (host_opt_state != NULL) {
! 5334: option_state_dereference(&host_opt_state, MDL);
! 5335: }
! 5336: if (iaprefix.buffer != NULL) {
! 5337: data_string_forget(&iaprefix, MDL);
! 5338: }
! 5339: if (cli_enc_opt_state != NULL) {
! 5340: option_state_dereference(&cli_enc_opt_state, MDL);
! 5341: }
! 5342: if (cli_enc_opt_data.buffer != NULL) {
! 5343: data_string_forget(&cli_enc_opt_data, MDL);
! 5344: }
! 5345: if (opt_state != NULL) {
! 5346: option_state_dereference(&opt_state, MDL);
! 5347: }
! 5348: }
! 5349:
! 5350: /*
! 5351: * Release means a client is done with the leases.
! 5352: */
! 5353:
! 5354: /* TODO: reject unicast messages, unless we set unicast option */
! 5355: static void
! 5356: dhcpv6_release(struct data_string *reply, struct packet *packet) {
! 5357: struct data_string client_id;
! 5358: struct data_string server_id;
! 5359:
! 5360: /*
! 5361: * Validate our input.
! 5362: */
! 5363: if (!valid_client_resp(packet, &client_id, &server_id)) {
! 5364: return;
! 5365: }
! 5366:
! 5367: /*
! 5368: * And operate on each IA_NA in this packet.
! 5369: */
! 5370: iterate_over_ia_na(reply, packet, &client_id, &server_id, "Release",
! 5371: ia_na_match_release, ia_na_nomatch_release);
! 5372:
! 5373: /*
! 5374: * And operate on each IA_PD in this packet.
! 5375: */
! 5376: iterate_over_ia_pd(reply, packet, &client_id, &server_id, "Release",
! 5377: ia_pd_match_release, ia_pd_nomatch_release);
! 5378:
! 5379: data_string_forget(&server_id, MDL);
! 5380: data_string_forget(&client_id, MDL);
! 5381: }
! 5382:
! 5383: /*
! 5384: * Information-Request is used by clients who have obtained an address
! 5385: * from other means, but want configuration information from the server.
! 5386: */
! 5387:
! 5388: static void
! 5389: dhcpv6_information_request(struct data_string *reply, struct packet *packet) {
! 5390: struct data_string client_id;
! 5391: struct data_string server_id;
! 5392:
! 5393: /*
! 5394: * Validate our input.
! 5395: */
! 5396: if (!valid_client_info_req(packet, &server_id)) {
! 5397: return;
! 5398: }
! 5399:
! 5400: /*
! 5401: * Get our client ID, if there is one.
! 5402: */
! 5403: memset(&client_id, 0, sizeof(client_id));
! 5404: if (get_client_id(packet, &client_id) != ISC_R_SUCCESS) {
! 5405: data_string_forget(&client_id, MDL);
! 5406: }
! 5407:
! 5408: /*
! 5409: * Use the lease_to_client() function. This will work fine,
! 5410: * because the valid_client_info_req() insures that we
! 5411: * don't have any IA that would cause us to allocate
! 5412: * resources to the client.
! 5413: */
! 5414: lease_to_client(reply, packet, &client_id,
! 5415: server_id.data != NULL ? &server_id : NULL);
! 5416:
! 5417: /*
! 5418: * Cleanup.
! 5419: */
! 5420: if (client_id.data != NULL) {
! 5421: data_string_forget(&client_id, MDL);
! 5422: }
! 5423: data_string_forget(&server_id, MDL);
! 5424: }
! 5425:
! 5426: /*
! 5427: * The Relay-forw message is sent by relays. It typically contains a
! 5428: * single option, which encapsulates an entire packet.
! 5429: *
! 5430: * We need to build an encapsulated reply.
! 5431: */
! 5432:
! 5433: /* XXX: this is very, very similar to do_packet6(), and should probably
! 5434: be combined in a clever way */
! 5435: static void
! 5436: dhcpv6_relay_forw(struct data_string *reply_ret, struct packet *packet) {
! 5437: struct option_cache *oc;
! 5438: struct data_string enc_opt_data;
! 5439: struct packet *enc_packet;
! 5440: unsigned char msg_type;
! 5441: const struct dhcpv6_packet *msg;
! 5442: const struct dhcpv6_relay_packet *relay;
! 5443: struct data_string enc_reply;
! 5444: char link_addr[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
! 5445: char peer_addr[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
! 5446: struct data_string a_opt, packet_ero;
! 5447: struct option_state *opt_state;
! 5448: static char reply_data[65536];
! 5449: struct dhcpv6_relay_packet *reply;
! 5450: int reply_ofs;
! 5451:
! 5452: /*
! 5453: * Initialize variables for early exit.
! 5454: */
! 5455: opt_state = NULL;
! 5456: memset(&a_opt, 0, sizeof(a_opt));
! 5457: memset(&packet_ero, 0, sizeof(packet_ero));
! 5458: memset(&enc_reply, 0, sizeof(enc_reply));
! 5459: memset(&enc_opt_data, 0, sizeof(enc_opt_data));
! 5460: enc_packet = NULL;
! 5461:
! 5462: /*
! 5463: * Get our encapsulated relay message.
! 5464: */
! 5465: oc = lookup_option(&dhcpv6_universe, packet->options, D6O_RELAY_MSG);
! 5466: if (oc == NULL) {
! 5467: inet_ntop(AF_INET6, &packet->dhcpv6_link_address,
! 5468: link_addr, sizeof(link_addr));
! 5469: inet_ntop(AF_INET6, &packet->dhcpv6_peer_address,
! 5470: peer_addr, sizeof(peer_addr));
! 5471: log_info("Relay-forward from %s with link address=%s and "
! 5472: "peer address=%s missing Relay Message option.",
! 5473: piaddr(packet->client_addr), link_addr, peer_addr);
! 5474: goto exit;
! 5475: }
! 5476:
! 5477: if (!evaluate_option_cache(&enc_opt_data, NULL, NULL, NULL,
! 5478: NULL, NULL, &global_scope, oc, MDL)) {
! 5479: log_error("dhcpv6_forw_relay: error evaluating "
! 5480: "relayed message.");
! 5481: goto exit;
! 5482: }
! 5483:
! 5484: if (!packet6_len_okay((char *)enc_opt_data.data, enc_opt_data.len)) {
! 5485: log_error("dhcpv6_forw_relay: encapsulated packet too short.");
! 5486: goto exit;
! 5487: }
! 5488:
! 5489: /*
! 5490: * Build a packet structure from this encapsulated packet.
! 5491: */
! 5492: enc_packet = NULL;
! 5493: if (!packet_allocate(&enc_packet, MDL)) {
! 5494: log_error("dhcpv6_forw_relay: "
! 5495: "no memory for encapsulated packet.");
! 5496: goto exit;
! 5497: }
! 5498:
! 5499: if (!option_state_allocate(&enc_packet->options, MDL)) {
! 5500: log_error("dhcpv6_forw_relay: "
! 5501: "no memory for encapsulated packet's options.");
! 5502: goto exit;
! 5503: }
! 5504:
! 5505: enc_packet->client_port = packet->client_port;
! 5506: enc_packet->client_addr = packet->client_addr;
! 5507: interface_reference(&enc_packet->interface, packet->interface, MDL);
! 5508: enc_packet->dhcpv6_container_packet = packet;
! 5509:
! 5510: msg_type = enc_opt_data.data[0];
! 5511: if ((msg_type == DHCPV6_RELAY_FORW) ||
! 5512: (msg_type == DHCPV6_RELAY_REPL)) {
! 5513: relay = (struct dhcpv6_relay_packet *)enc_opt_data.data;
! 5514: enc_packet->dhcpv6_msg_type = relay->msg_type;
! 5515:
! 5516: /* relay-specific data */
! 5517: enc_packet->dhcpv6_hop_count = relay->hop_count;
! 5518: memcpy(&enc_packet->dhcpv6_link_address,
! 5519: relay->link_address, sizeof(relay->link_address));
! 5520: memcpy(&enc_packet->dhcpv6_peer_address,
! 5521: relay->peer_address, sizeof(relay->peer_address));
! 5522:
! 5523: if (!parse_option_buffer(enc_packet->options,
! 5524: relay->options,
! 5525: enc_opt_data.len-sizeof(*relay),
! 5526: &dhcpv6_universe)) {
! 5527: /* no logging here, as parse_option_buffer() logs all
! 5528: cases where it fails */
! 5529: goto exit;
! 5530: }
! 5531: } else {
! 5532: msg = (struct dhcpv6_packet *)enc_opt_data.data;
! 5533: enc_packet->dhcpv6_msg_type = msg->msg_type;
! 5534:
! 5535: /* message-specific data */
! 5536: memcpy(enc_packet->dhcpv6_transaction_id,
! 5537: msg->transaction_id,
! 5538: sizeof(enc_packet->dhcpv6_transaction_id));
! 5539:
! 5540: if (!parse_option_buffer(enc_packet->options,
! 5541: msg->options,
! 5542: enc_opt_data.len-sizeof(*msg),
! 5543: &dhcpv6_universe)) {
! 5544: /* no logging here, as parse_option_buffer() logs all
! 5545: cases where it fails */
! 5546: goto exit;
! 5547: }
! 5548: }
! 5549:
! 5550: /*
! 5551: * This is recursive. It is possible to exceed maximum packet size.
! 5552: * XXX: This will cause the packet send to fail.
! 5553: */
! 5554: build_dhcpv6_reply(&enc_reply, enc_packet);
! 5555:
! 5556: /*
! 5557: * If we got no encapsulated data, then it is discarded, and
! 5558: * our reply-forw is also discarded.
! 5559: */
! 5560: if (enc_reply.data == NULL) {
! 5561: goto exit;
! 5562: }
! 5563:
! 5564: /*
! 5565: * Now we can use the reply_data buffer.
! 5566: * Packet header stuff all comes from the forward message.
! 5567: */
! 5568: reply = (struct dhcpv6_relay_packet *)reply_data;
! 5569: reply->msg_type = DHCPV6_RELAY_REPL;
! 5570: reply->hop_count = packet->dhcpv6_hop_count;
! 5571: memcpy(reply->link_address, &packet->dhcpv6_link_address,
! 5572: sizeof(reply->link_address));
! 5573: memcpy(reply->peer_address, &packet->dhcpv6_peer_address,
! 5574: sizeof(reply->peer_address));
! 5575: reply_ofs = (int)(offsetof(struct dhcpv6_relay_packet, options));
! 5576:
! 5577: /*
! 5578: * Get the reply option state.
! 5579: */
! 5580: opt_state = NULL;
! 5581: if (!option_state_allocate(&opt_state, MDL)) {
! 5582: log_error("dhcpv6_relay_forw: no memory for option state.");
! 5583: goto exit;
! 5584: }
! 5585:
! 5586: /*
! 5587: * Append the interface-id if present.
! 5588: */
! 5589: oc = lookup_option(&dhcpv6_universe, packet->options,
! 5590: D6O_INTERFACE_ID);
! 5591: if (oc != NULL) {
! 5592: if (!evaluate_option_cache(&a_opt, packet,
! 5593: NULL, NULL,
! 5594: packet->options, NULL,
! 5595: &global_scope, oc, MDL)) {
! 5596: log_error("dhcpv6_relay_forw: error evaluating "
! 5597: "Interface ID.");
! 5598: goto exit;
! 5599: }
! 5600: if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL,
! 5601: (unsigned char *)a_opt.data,
! 5602: a_opt.len,
! 5603: D6O_INTERFACE_ID, 0)) {
! 5604: log_error("dhcpv6_relay_forw: error saving "
! 5605: "Interface ID.");
! 5606: goto exit;
! 5607: }
! 5608: data_string_forget(&a_opt, MDL);
! 5609: }
! 5610:
! 5611: /*
! 5612: * Append our encapsulated stuff for caller.
! 5613: */
! 5614: if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL,
! 5615: (unsigned char *)enc_reply.data,
! 5616: enc_reply.len,
! 5617: D6O_RELAY_MSG, 0)) {
! 5618: log_error("dhcpv6_relay_forw: error saving Relay MSG.");
! 5619: goto exit;
! 5620: }
! 5621:
! 5622: /*
! 5623: * Get the ERO if any.
! 5624: */
! 5625: oc = lookup_option(&dhcpv6_universe, packet->options, D6O_ERO);
! 5626: if (oc != NULL) {
! 5627: unsigned req;
! 5628: int i;
! 5629:
! 5630: if (!evaluate_option_cache(&packet_ero, packet,
! 5631: NULL, NULL,
! 5632: packet->options, NULL,
! 5633: &global_scope, oc, MDL) ||
! 5634: (packet_ero.len & 1)) {
! 5635: log_error("dhcpv6_relay_forw: error evaluating ERO.");
! 5636: goto exit;
! 5637: }
! 5638:
! 5639: /* Decode and apply the ERO. */
! 5640: for (i = 0; i < packet_ero.len; i += 2) {
! 5641: req = getUShort(packet_ero.data + i);
! 5642: /* Already in the reply? */
! 5643: oc = lookup_option(&dhcpv6_universe, opt_state, req);
! 5644: if (oc != NULL)
! 5645: continue;
! 5646: /* Get it from the packet if present. */
! 5647: oc = lookup_option(&dhcpv6_universe,
! 5648: packet->options,
! 5649: req);
! 5650: if (oc == NULL)
! 5651: continue;
! 5652: if (!evaluate_option_cache(&a_opt, packet,
! 5653: NULL, NULL,
! 5654: packet->options, NULL,
! 5655: &global_scope, oc, MDL)) {
! 5656: log_error("dhcpv6_relay_forw: error "
! 5657: "evaluating option %u.", req);
! 5658: goto exit;
! 5659: }
! 5660: if (!save_option_buffer(&dhcpv6_universe,
! 5661: opt_state,
! 5662: NULL,
! 5663: (unsigned char *)a_opt.data,
! 5664: a_opt.len,
! 5665: req,
! 5666: 0)) {
! 5667: log_error("dhcpv6_relay_forw: error saving "
! 5668: "option %u.", req);
! 5669: goto exit;
! 5670: }
! 5671: data_string_forget(&a_opt, MDL);
! 5672: }
! 5673: }
! 5674:
! 5675: reply_ofs += store_options6(reply_data + reply_ofs,
! 5676: sizeof(reply_data) - reply_ofs,
! 5677: opt_state, packet,
! 5678: required_opts_agent, &packet_ero);
! 5679:
! 5680: /*
! 5681: * Return our reply to the caller.
! 5682: */
! 5683: reply_ret->len = reply_ofs;
! 5684: reply_ret->buffer = NULL;
! 5685: if (!buffer_allocate(&reply_ret->buffer, reply_ret->len, MDL)) {
! 5686: log_fatal("No memory to store reply.");
! 5687: }
! 5688: reply_ret->data = reply_ret->buffer->data;
! 5689: memcpy(reply_ret->buffer->data, reply_data, reply_ofs);
! 5690:
! 5691: exit:
! 5692: if (opt_state != NULL)
! 5693: option_state_dereference(&opt_state, MDL);
! 5694: if (a_opt.data != NULL) {
! 5695: data_string_forget(&a_opt, MDL);
! 5696: }
! 5697: if (packet_ero.data != NULL) {
! 5698: data_string_forget(&packet_ero, MDL);
! 5699: }
! 5700: if (enc_reply.data != NULL) {
! 5701: data_string_forget(&enc_reply, MDL);
! 5702: }
! 5703: if (enc_opt_data.data != NULL) {
! 5704: data_string_forget(&enc_opt_data, MDL);
! 5705: }
! 5706: if (enc_packet != NULL) {
! 5707: packet_dereference(&enc_packet, MDL);
! 5708: }
! 5709: }
! 5710:
! 5711: static void
! 5712: dhcpv6_discard(struct packet *packet) {
! 5713: /* INSIST(packet->msg_type > 0); */
! 5714: /* INSIST(packet->msg_type < dhcpv6_type_name_max); */
! 5715:
! 5716: log_debug("Discarding %s from %s; message type not handled by server",
! 5717: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 5718: piaddr(packet->client_addr));
! 5719: }
! 5720:
! 5721: static void
! 5722: build_dhcpv6_reply(struct data_string *reply, struct packet *packet) {
! 5723: memset(reply, 0, sizeof(*reply));
! 5724: switch (packet->dhcpv6_msg_type) {
! 5725: case DHCPV6_SOLICIT:
! 5726: dhcpv6_solicit(reply, packet);
! 5727: break;
! 5728: case DHCPV6_ADVERTISE:
! 5729: dhcpv6_discard(packet);
! 5730: break;
! 5731: case DHCPV6_REQUEST:
! 5732: dhcpv6_request(reply, packet);
! 5733: break;
! 5734: case DHCPV6_CONFIRM:
! 5735: dhcpv6_confirm(reply, packet);
! 5736: break;
! 5737: case DHCPV6_RENEW:
! 5738: dhcpv6_renew(reply, packet);
! 5739: break;
! 5740: case DHCPV6_REBIND:
! 5741: dhcpv6_rebind(reply, packet);
! 5742: break;
! 5743: case DHCPV6_REPLY:
! 5744: dhcpv6_discard(packet);
! 5745: break;
! 5746: case DHCPV6_RELEASE:
! 5747: dhcpv6_release(reply, packet);
! 5748: break;
! 5749: case DHCPV6_DECLINE:
! 5750: dhcpv6_decline(reply, packet);
! 5751: break;
! 5752: case DHCPV6_RECONFIGURE:
! 5753: dhcpv6_discard(packet);
! 5754: break;
! 5755: case DHCPV6_INFORMATION_REQUEST:
! 5756: dhcpv6_information_request(reply, packet);
! 5757: break;
! 5758: case DHCPV6_RELAY_FORW:
! 5759: dhcpv6_relay_forw(reply, packet);
! 5760: break;
! 5761: case DHCPV6_RELAY_REPL:
! 5762: dhcpv6_discard(packet);
! 5763: break;
! 5764: case DHCPV6_LEASEQUERY:
! 5765: dhcpv6_leasequery(reply, packet);
! 5766: break;
! 5767: case DHCPV6_LEASEQUERY_REPLY:
! 5768: dhcpv6_discard(packet);
! 5769: break;
! 5770: default:
! 5771: /* XXX: would be nice if we had "notice" level,
! 5772: as syslog, for this */
! 5773: log_info("Discarding unknown DHCPv6 message type %d "
! 5774: "from %s", packet->dhcpv6_msg_type,
! 5775: piaddr(packet->client_addr));
! 5776: }
! 5777: }
! 5778:
! 5779: static void
! 5780: log_packet_in(const struct packet *packet) {
! 5781: struct data_string s;
! 5782: u_int32_t tid;
! 5783: char tmp_addr[INET6_ADDRSTRLEN];
! 5784: const void *addr;
! 5785:
! 5786: memset(&s, 0, sizeof(s));
! 5787:
! 5788: if (packet->dhcpv6_msg_type < dhcpv6_type_name_max) {
! 5789: data_string_sprintfa(&s, "%s message from %s port %d",
! 5790: dhcpv6_type_names[packet->dhcpv6_msg_type],
! 5791: piaddr(packet->client_addr),
! 5792: ntohs(packet->client_port));
! 5793: } else {
! 5794: data_string_sprintfa(&s,
! 5795: "Unknown message type %d from %s port %d",
! 5796: packet->dhcpv6_msg_type,
! 5797: piaddr(packet->client_addr),
! 5798: ntohs(packet->client_port));
! 5799: }
! 5800: if ((packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) ||
! 5801: (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL)) {
! 5802: addr = &packet->dhcpv6_link_address;
! 5803: data_string_sprintfa(&s, ", link address %s",
! 5804: inet_ntop(AF_INET6, addr,
! 5805: tmp_addr, sizeof(tmp_addr)));
! 5806: addr = &packet->dhcpv6_peer_address;
! 5807: data_string_sprintfa(&s, ", peer address %s",
! 5808: inet_ntop(AF_INET6, addr,
! 5809: tmp_addr, sizeof(tmp_addr)));
! 5810: } else {
! 5811: tid = 0;
! 5812: memcpy(((char *)&tid)+1, packet->dhcpv6_transaction_id, 3);
! 5813: data_string_sprintfa(&s, ", transaction ID 0x%06X", tid);
! 5814:
! 5815: /*
! 5816: oc = lookup_option(&dhcpv6_universe, packet->options,
! 5817: D6O_CLIENTID);
! 5818: if (oc != NULL) {
! 5819: memset(&tmp_ds, 0, sizeof(tmp_ds_));
! 5820: if (!evaluate_option_cache(&tmp_ds, packet, NULL, NULL,
! 5821: packet->options, NULL,
! 5822: &global_scope, oc, MDL)) {
! 5823: log_error("Error evaluating Client Identifier");
! 5824: } else {
! 5825: data_strint_sprintf(&s, ", client ID %s",
! 5826:
! 5827: data_string_forget(&tmp_ds, MDL);
! 5828: }
! 5829: }
! 5830: */
! 5831:
! 5832: }
! 5833: log_info("%s", s.data);
! 5834:
! 5835: data_string_forget(&s, MDL);
! 5836: }
! 5837:
! 5838: void
! 5839: dhcpv6(struct packet *packet) {
! 5840: struct data_string reply;
! 5841: struct sockaddr_in6 to_addr;
! 5842: int send_ret;
! 5843:
! 5844: /*
! 5845: * Log a message that we received this packet.
! 5846: */
! 5847: log_packet_in(packet);
! 5848:
! 5849: /*
! 5850: * Build our reply packet.
! 5851: */
! 5852: build_dhcpv6_reply(&reply, packet);
! 5853:
! 5854: if (reply.data != NULL) {
! 5855: /*
! 5856: * Send our reply, if we have one.
! 5857: */
! 5858: memset(&to_addr, 0, sizeof(to_addr));
! 5859: to_addr.sin6_family = AF_INET6;
! 5860: if ((packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) ||
! 5861: (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL)) {
! 5862: to_addr.sin6_port = local_port;
! 5863: } else {
! 5864: to_addr.sin6_port = remote_port;
! 5865: }
! 5866:
! 5867: #if defined (REPLY_TO_SOURCE_PORT)
! 5868: /*
! 5869: * This appears to have been included for testing so we would
! 5870: * not need a root client, but was accidently left in the
! 5871: * final code. We continue to include it in case
! 5872: * some users have come to rely upon it, but leave
! 5873: * it off by default as it's a bad idea.
! 5874: */
! 5875: to_addr.sin6_port = packet->client_port;
! 5876: #endif
! 5877:
! 5878: memcpy(&to_addr.sin6_addr, packet->client_addr.iabuf,
! 5879: sizeof(to_addr.sin6_addr));
! 5880:
! 5881: log_info("Sending %s to %s port %d",
! 5882: dhcpv6_type_names[reply.data[0]],
! 5883: piaddr(packet->client_addr),
! 5884: ntohs(to_addr.sin6_port));
! 5885:
! 5886: send_ret = send_packet6(packet->interface,
! 5887: reply.data, reply.len, &to_addr);
! 5888: if (send_ret != reply.len) {
! 5889: log_error("dhcpv6: send_packet6() sent %d of %d bytes",
! 5890: send_ret, reply.len);
! 5891: }
! 5892: data_string_forget(&reply, MDL);
! 5893: }
! 5894: }
! 5895:
! 5896: static void
! 5897: seek_shared_host(struct host_decl **hp, struct shared_network *shared) {
! 5898: struct host_decl *nofixed = NULL;
! 5899: struct host_decl *seek, *hold = NULL;
! 5900:
! 5901: /*
! 5902: * Seek forward through fixed addresses for the right link.
! 5903: *
! 5904: * Note: how to do this for fixed prefixes???
! 5905: */
! 5906: host_reference(&hold, *hp, MDL);
! 5907: host_dereference(hp, MDL);
! 5908: seek = hold;
! 5909: while (seek != NULL) {
! 5910: if (seek->fixed_addr == NULL)
! 5911: nofixed = seek;
! 5912: else if (fixed_matches_shared(seek, shared))
! 5913: break;
! 5914:
! 5915: seek = seek->n_ipaddr;
! 5916: }
! 5917:
! 5918: if ((seek == NULL) && (nofixed != NULL))
! 5919: seek = nofixed;
! 5920:
! 5921: if (seek != NULL)
! 5922: host_reference(hp, seek, MDL);
! 5923: }
! 5924:
! 5925: static isc_boolean_t
! 5926: fixed_matches_shared(struct host_decl *host, struct shared_network *shared) {
! 5927: struct subnet *subnet;
! 5928: struct data_string addr;
! 5929: isc_boolean_t matched;
! 5930: struct iaddr fixed;
! 5931:
! 5932: if (host->fixed_addr == NULL)
! 5933: return ISC_FALSE;
! 5934:
! 5935: memset(&addr, 0, sizeof(addr));
! 5936: if (!evaluate_option_cache(&addr, NULL, NULL, NULL, NULL, NULL,
! 5937: &global_scope, host->fixed_addr, MDL))
! 5938: return ISC_FALSE;
! 5939:
! 5940: if (addr.len < 16) {
! 5941: data_string_forget(&addr, MDL);
! 5942: return ISC_FALSE;
! 5943: }
! 5944:
! 5945: fixed.len = 16;
! 5946: memcpy(fixed.iabuf, addr.data, 16);
! 5947:
! 5948: matched = ISC_FALSE;
! 5949: for (subnet = shared->subnets ; subnet != NULL ;
! 5950: subnet = subnet->next_sibling) {
! 5951: if (addr_eq(subnet_number(fixed, subnet->netmask),
! 5952: subnet->net)) {
! 5953: matched = ISC_TRUE;
! 5954: break;
! 5955: }
! 5956: }
! 5957:
! 5958: data_string_forget(&addr, MDL);
! 5959: return matched;
! 5960: }
! 5961:
! 5962: #endif /* DHCPv6 */
! 5963:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>