Annotation of embedaddon/dnsmasq/src/rfc3315.c, revision 1.1
1.1 ! misho 1: /* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
! 2:
! 3: This program is free software; you can redistribute it and/or modify
! 4: it under the terms of the GNU General Public License as published by
! 5: the Free Software Foundation; version 2 dated June, 1991, or
! 6: (at your option) version 3 dated 29 June, 2007.
! 7:
! 8: This program is distributed in the hope that it will be useful,
! 9: but WITHOUT ANY WARRANTY; without even the implied warranty of
! 10: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 11: GNU General Public License for more details.
! 12:
! 13: You should have received a copy of the GNU General Public License
! 14: along with this program. If not, see <http://www.gnu.org/licenses/>.
! 15: */
! 16:
! 17:
! 18: #include "dnsmasq.h"
! 19:
! 20: #ifdef HAVE_DHCP6
! 21:
! 22: struct state {
! 23: unsigned char *clid;
! 24: int clid_len, iaid, ia_type, interface, hostname_auth;
! 25: char *client_hostname, *hostname, *domain, *send_domain;
! 26: struct dhcp_context *context;
! 27: struct in6_addr *link_address;
! 28: unsigned int xid, fqdn_flags;
! 29: char *iface_name;
! 30: void *packet_options, *end;
! 31: struct dhcp_netid *tags, *context_tags;
! 32: #ifdef OPTION6_PREFIX_CLASS
! 33: struct prefix_class *send_prefix_class;
! 34: #endif
! 35: };
! 36:
! 37: static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **relay_tagsp, struct dhcp_context *context,
! 38: int interface, char *iface_name, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now);
! 39: static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dhcp_netid *tags, struct dhcp_context *context,
! 40: int interface, char *iface_name, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now);
! 41: static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
! 42: static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);
! 43:
! 44: static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize);
! 45: static void *opt6_next(void *opts, void *end);
! 46: static unsigned int opt6_uint(unsigned char *opt, int offset, int size);
! 47: static void get_context_tag(struct state *state, struct dhcp_context *context);
! 48: static int check_ia(struct state *state, void *opt, void **endp, void **ia_option);
! 49: static int build_ia(struct state *state, int *t1cntr);
! 50: static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz);
! 51: #ifdef OPTION6_PREFIX_CLASS
! 52: static struct prefix_class *prefix_class_from_context(struct dhcp_context *context);
! 53: #endif
! 54: static void mark_context_used(struct state *state, struct dhcp_context *context, struct in6_addr *addr);
! 55: static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr);
! 56: static int check_address(struct state *state, struct in6_addr *addr);
! 57: static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, unsigned int requested_time,
! 58: unsigned int *min_time, struct in6_addr *addr, int update_lease, time_t now);
! 59: static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
! 60: static int add_local_addrs(struct dhcp_context *context);
! 61: struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, struct dhcp_context *context);
! 62: static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
! 63: unsigned int *preferred_timep, unsigned int lease_time, unsigned int requested_time);
! 64:
! 65: #define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
! 66: #define opt6_type(opt) (opt6_uint(opt, -4, 2))
! 67: #define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4+(i)]))
! 68:
! 69:
! 70: unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
! 71: struct in6_addr *fallback, size_t sz, int is_unicast, time_t now)
! 72: {
! 73: struct dhcp_netid *relay_tags = NULL;
! 74: struct dhcp_vendor *vendor;
! 75: int msg_type;
! 76:
! 77: if (sz <= 4)
! 78: return 0;
! 79:
! 80: msg_type = *((unsigned char *)daemon->dhcp_packet.iov_base);
! 81:
! 82: /* Mark these so we only match each at most once, to avoid tangled linked lists */
! 83: for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
! 84: vendor->netid.next = &vendor->netid;
! 85:
! 86: save_counter(0);
! 87:
! 88: if (dhcp6_maybe_relay(NULL, &relay_tags, context, interface, iface_name, fallback, daemon->dhcp_packet.iov_base, sz, is_unicast, now))
! 89: return msg_type == DHCP6RELAYFORW ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
! 90:
! 91: return 0;
! 92: }
! 93:
! 94: /* This cost me blood to write, it will probably cost you blood to understand - srk. */
! 95: static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **relay_tagsp, struct dhcp_context *context,
! 96: int interface, char *iface_name, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now)
! 97: {
! 98: void *end = inbuff + sz;
! 99: void *opts = inbuff + 34;
! 100: int msg_type = *((unsigned char *)inbuff);
! 101: unsigned char *outmsgtypep;
! 102: void *opt;
! 103: struct dhcp_vendor *vendor;
! 104:
! 105: /* if not an encaplsulated relayed message, just do the stuff */
! 106: if (msg_type != DHCP6RELAYFORW)
! 107: {
! 108: /* if link_address != NULL if points to the link address field of the
! 109: innermost nested RELAYFORW message, which is where we find the
! 110: address of the network on which we can allocate an address.
! 111: Recalculate the available contexts using that information. */
! 112:
! 113: if (link_address)
! 114: {
! 115: struct dhcp_context *c;
! 116: context = NULL;
! 117:
! 118: if (!IN6_IS_ADDR_LOOPBACK(link_address) &&
! 119: !IN6_IS_ADDR_LINKLOCAL(link_address) &&
! 120: !IN6_IS_ADDR_MULTICAST(link_address))
! 121: for (c = daemon->dhcp6; c; c = c->next)
! 122: if ((c->flags & CONTEXT_DHCP) &&
! 123: !(c->flags & CONTEXT_TEMPLATE) &&
! 124: is_same_net6(link_address, &c->start6, c->prefix) &&
! 125: is_same_net6(link_address, &c->end6, c->prefix))
! 126: {
! 127: c->preferred = c->valid = 0xffffffff;
! 128: c->current = context;
! 129: context = c;
! 130: }
! 131:
! 132: if (!context)
! 133: {
! 134: inet_ntop(AF_INET6, link_address, daemon->addrbuff, ADDRSTRLEN);
! 135: my_syslog(MS_DHCP | LOG_WARNING,
! 136: _("no address range available for DHCPv6 request from relay at %s"),
! 137: daemon->addrbuff);
! 138: return 0;
! 139: }
! 140: }
! 141:
! 142: if (!context)
! 143: {
! 144: my_syslog(MS_DHCP | LOG_WARNING,
! 145: _("no address range available for DHCPv6 request via %s"), iface_name);
! 146: return 0;
! 147: }
! 148:
! 149: return dhcp6_no_relay(msg_type, link_address, *relay_tagsp, context, interface, iface_name, fallback, inbuff, sz, is_unicast, now);
! 150: }
! 151:
! 152: /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
! 153: which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
! 154: if (sz < 38)
! 155: return 0;
! 156:
! 157: /* copy header stuff into reply message and set type to reply */
! 158: outmsgtypep = put_opt6(inbuff, 34);
! 159: *outmsgtypep = DHCP6RELAYREPL;
! 160:
! 161: /* look for relay options and set tags if found. */
! 162: for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
! 163: {
! 164: int mopt;
! 165:
! 166: if (vendor->match_type == MATCH_SUBSCRIBER)
! 167: mopt = OPTION6_SUBSCRIBER_ID;
! 168: else if (vendor->match_type == MATCH_REMOTE)
! 169: mopt = OPTION6_REMOTE_ID;
! 170: else
! 171: continue;
! 172:
! 173: if ((opt = opt6_find(opts, end, mopt, 1)) &&
! 174: vendor->len == opt6_len(opt) &&
! 175: memcmp(vendor->data, opt6_ptr(opt, 0), vendor->len) == 0 &&
! 176: vendor->netid.next != &vendor->netid)
! 177: {
! 178: vendor->netid.next = *relay_tagsp;
! 179: *relay_tagsp = &vendor->netid;
! 180: break;
! 181: }
! 182: }
! 183:
! 184: for (opt = opts; opt; opt = opt6_next(opt, end))
! 185: {
! 186: int o = new_opt6(opt6_type(opt));
! 187: if (opt6_type(opt) == OPTION6_RELAY_MSG)
! 188: {
! 189: struct in6_addr link_address;
! 190: /* the packet data is unaligned, copy to aligned storage */
! 191: memcpy(&link_address, inbuff + 2, IN6ADDRSZ);
! 192: /* Not, zero is_unicast since that is now known to refer to the
! 193: relayed packet, not the original sent by the client */
! 194: if (!dhcp6_maybe_relay(&link_address, relay_tagsp, context, interface, iface_name, fallback, opt6_ptr(opt, 0), opt6_len(opt), 0, now))
! 195: return 0;
! 196: }
! 197: else
! 198: put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
! 199: end_opt6(o);
! 200: }
! 201:
! 202: return 1;
! 203: }
! 204:
! 205: static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dhcp_netid *tags, struct dhcp_context *context,
! 206: int interface, char *iface_name, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now)
! 207: {
! 208: void *opt;
! 209: int i, o, o1, start_opts;
! 210: struct dhcp_opt *opt_cfg;
! 211: struct dhcp_netid *tagif;
! 212: struct dhcp_config *config = NULL;
! 213: struct dhcp_netid known_id, iface_id, v6_id;
! 214: unsigned char *outmsgtypep;
! 215: struct dhcp_vendor *vendor;
! 216: struct dhcp_context *context_tmp;
! 217: unsigned int ignore = 0;
! 218: struct state state;
! 219: #ifdef OPTION6_PREFIX_CLASS
! 220: struct prefix_class *p;
! 221: int dump_all_prefix_classes = 0;
! 222: #endif
! 223:
! 224: state.packet_options = inbuff + 4;
! 225: state.end = inbuff + sz;
! 226: state.clid = NULL;
! 227: state.clid_len = 0;
! 228: state.context_tags = NULL;
! 229: state.tags = tags;
! 230: state.link_address = link_address;
! 231: state.interface = interface;
! 232: state.domain = NULL;
! 233: state.send_domain = NULL;
! 234: state.context = context;
! 235: state.hostname_auth = 0;
! 236: state.hostname = NULL;
! 237: state.client_hostname = NULL;
! 238: state.iface_name = iface_name;
! 239: state.fqdn_flags = 0x01; /* default to send if we recieve no FQDN option */
! 240: #ifdef OPTION6_PREFIX_CLASS
! 241: state.send_prefix_class = NULL;
! 242: #endif
! 243:
! 244: /* set tag with name == interface */
! 245: iface_id.net = iface_name;
! 246: iface_id.next = state.tags;
! 247: state.tags = &iface_id;
! 248:
! 249: /* set tag "dhcpv6" */
! 250: v6_id.net = "dhcpv6";
! 251: v6_id.next = state.tags;
! 252: state.tags = &v6_id;
! 253:
! 254: /* copy over transaction-id, and save pointer to message type */
! 255: outmsgtypep = put_opt6(inbuff, 4);
! 256: start_opts = save_counter(-1);
! 257: state.xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16;
! 258:
! 259: /* We're going to be linking tags from all context we use.
! 260: mark them as unused so we don't link one twice and break the list */
! 261: for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
! 262: {
! 263: context->netid.next = &context->netid;
! 264:
! 265: if (option_bool(OPT_LOG_OPTS))
! 266: {
! 267: inet_ntop(AF_INET6, &context_tmp->start6, daemon->dhcp_buff, ADDRSTRLEN);
! 268: inet_ntop(AF_INET6, &context_tmp->end6, daemon->dhcp_buff2, ADDRSTRLEN);
! 269: if (context_tmp->flags & (CONTEXT_STATIC))
! 270: my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCPv6 subnet: %s/%d"),
! 271: state.xid, daemon->dhcp_buff, context_tmp->prefix);
! 272: else
! 273: my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"),
! 274: state.xid, daemon->dhcp_buff, daemon->dhcp_buff2);
! 275: }
! 276: }
! 277:
! 278: if ((opt = opt6_find(state.packet_options, state.end, OPTION6_CLIENT_ID, 1)))
! 279: {
! 280: state.clid = opt6_ptr(opt, 0);
! 281: state.clid_len = opt6_len(opt);
! 282: o = new_opt6(OPTION6_CLIENT_ID);
! 283: put_opt6(state.clid, state.clid_len);
! 284: end_opt6(o);
! 285: }
! 286: else if (msg_type != DHCP6IREQ)
! 287: return 0;
! 288:
! 289: /* server-id must match except for SOLICIT and CONFIRM messages */
! 290: if (msg_type != DHCP6SOLICIT && msg_type != DHCP6CONFIRM && msg_type != DHCP6IREQ &&
! 291: (!(opt = opt6_find(state.packet_options, state.end, OPTION6_SERVER_ID, 1)) ||
! 292: opt6_len(opt) != daemon->duid_len ||
! 293: memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
! 294: return 0;
! 295:
! 296: o = new_opt6(OPTION6_SERVER_ID);
! 297: put_opt6(daemon->duid, daemon->duid_len);
! 298: end_opt6(o);
! 299:
! 300: if (is_unicast &&
! 301: (msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
! 302:
! 303: {
! 304: o1 = new_opt6(OPTION6_STATUS_CODE);
! 305: put_opt6_short(DHCP6USEMULTI);
! 306: put_opt6_string("Use multicast");
! 307: end_opt6(o1);
! 308: return 1;
! 309: }
! 310:
! 311: /* match vendor and user class options */
! 312: for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
! 313: {
! 314: int mopt;
! 315:
! 316: if (vendor->match_type == MATCH_VENDOR)
! 317: mopt = OPTION6_VENDOR_CLASS;
! 318: else if (vendor->match_type == MATCH_USER)
! 319: mopt = OPTION6_USER_CLASS;
! 320: else
! 321: continue;
! 322:
! 323: if ((opt = opt6_find(state.packet_options, state.end, mopt, 2)))
! 324: {
! 325: void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt));
! 326: int offset = 0;
! 327:
! 328: if (mopt == OPTION6_VENDOR_CLASS)
! 329: {
! 330: if (opt6_len(opt) < 4)
! 331: continue;
! 332:
! 333: if (vendor->enterprise != opt6_uint(opt, 0, 4))
! 334: continue;
! 335:
! 336: offset = 4;
! 337: }
! 338:
! 339: for (enc_opt = opt6_ptr(opt, offset); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
! 340: for (i = 0; i <= (opt6_len(enc_opt) - vendor->len); i++)
! 341: if (memcmp(vendor->data, opt6_ptr(enc_opt, i), vendor->len) == 0)
! 342: {
! 343: vendor->netid.next = state.tags;
! 344: state.tags = &vendor->netid;
! 345: break;
! 346: }
! 347: }
! 348: }
! 349:
! 350: if (option_bool(OPT_LOG_OPTS) && (opt = opt6_find(state.packet_options, state.end, OPTION6_VENDOR_CLASS, 4)))
! 351: my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %u"), state.xid, opt6_uint(opt, 0, 4));
! 352:
! 353: /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
! 354: Otherwise assume the option is an array, and look for a matching element.
! 355: If no data given, existance of the option is enough. This code handles
! 356: V-I opts too. */
! 357: for (opt_cfg = daemon->dhcp_match6; opt_cfg; opt_cfg = opt_cfg->next)
! 358: {
! 359: int match = 0;
! 360:
! 361: if (opt_cfg->flags & DHOPT_RFC3925)
! 362: {
! 363: for (opt = opt6_find(state.packet_options, state.end, OPTION6_VENDOR_OPTS, 4);
! 364: opt;
! 365: opt = opt6_find(opt6_next(opt, state.end), state.end, OPTION6_VENDOR_OPTS, 4))
! 366: {
! 367: void *vopt;
! 368: void *vend = opt6_ptr(opt, opt6_len(opt));
! 369:
! 370: for (vopt = opt6_find(opt6_ptr(opt, 4), vend, opt_cfg->opt, 0);
! 371: vopt;
! 372: vopt = opt6_find(opt6_next(vopt, vend), vend, opt_cfg->opt, 0))
! 373: if ((match = match_bytes(opt_cfg, opt6_ptr(vopt, 0), opt6_len(vopt))))
! 374: break;
! 375: }
! 376: if (match)
! 377: break;
! 378: }
! 379: else
! 380: {
! 381: if (!(opt = opt6_find(state.packet_options, state.end, opt_cfg->opt, 1)))
! 382: continue;
! 383:
! 384: match = match_bytes(opt_cfg, opt6_ptr(opt, 0), opt6_len(opt));
! 385: }
! 386:
! 387: if (match)
! 388: {
! 389: opt_cfg->netid->next = state.tags;
! 390: state.tags = opt_cfg->netid;
! 391: }
! 392: }
! 393:
! 394: if ((opt = opt6_find(state.packet_options, state.end, OPTION6_FQDN, 1)))
! 395: {
! 396: /* RFC4704 refers */
! 397: int len = opt6_len(opt) - 1;
! 398:
! 399: state.fqdn_flags = opt6_uint(opt, 0, 1);
! 400:
! 401: /* Always force update, since the client has no way to do it itself. */
! 402: if (!option_bool(OPT_FQDN_UPDATE) && !(state.fqdn_flags & 0x01))
! 403: state.fqdn_flags |= 0x03;
! 404:
! 405: state.fqdn_flags &= ~0x04;
! 406:
! 407: if (len != 0 && len < 255)
! 408: {
! 409: unsigned char *pp, *op = opt6_ptr(opt, 1);
! 410: char *pq = daemon->dhcp_buff;
! 411:
! 412: pp = op;
! 413: while (*op != 0 && ((op + (*op)) - pp) < len)
! 414: {
! 415: memcpy(pq, op+1, *op);
! 416: pq += *op;
! 417: op += (*op)+1;
! 418: *(pq++) = '.';
! 419: }
! 420:
! 421: if (pq != daemon->dhcp_buff)
! 422: pq--;
! 423: *pq = 0;
! 424:
! 425: if (legal_hostname(daemon->dhcp_buff))
! 426: {
! 427: state.client_hostname = daemon->dhcp_buff;
! 428: if (option_bool(OPT_LOG_OPTS))
! 429: my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), state.xid, state.client_hostname);
! 430: }
! 431: }
! 432: }
! 433:
! 434: if (state.clid)
! 435: {
! 436: config = find_config6(daemon->dhcp_conf, context, state.clid, state.clid_len, NULL);
! 437:
! 438: if (have_config(config, CONFIG_NAME))
! 439: {
! 440: state.hostname = config->hostname;
! 441: state.domain = config->domain;
! 442: state.hostname_auth = 1;
! 443: }
! 444: else if (state.client_hostname)
! 445: {
! 446: state.domain = strip_hostname(state.client_hostname);
! 447:
! 448: if (strlen(state.client_hostname) != 0)
! 449: {
! 450: state.hostname = state.client_hostname;
! 451: if (!config)
! 452: {
! 453: /* Search again now we have a hostname.
! 454: Only accept configs without CLID here, (it won't match)
! 455: to avoid impersonation by name. */
! 456: struct dhcp_config *new = find_config6(daemon->dhcp_conf, context, NULL, 0, state.hostname);
! 457: if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
! 458: config = new;
! 459: }
! 460: }
! 461: }
! 462: }
! 463:
! 464: if (config)
! 465: {
! 466: struct dhcp_netid_list *list;
! 467:
! 468: for (list = config->netid; list; list = list->next)
! 469: {
! 470: list->list->next = state.tags;
! 471: state.tags = list->list;
! 472: }
! 473:
! 474: /* set "known" tag for known hosts */
! 475: known_id.net = "known";
! 476: known_id.next = state.tags;
! 477: state.tags = &known_id;
! 478:
! 479: if (have_config(config, CONFIG_DISABLE))
! 480: ignore = 1;
! 481: }
! 482:
! 483: #ifdef OPTION6_PREFIX_CLASS
! 484: /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
! 485: if (daemon->prefix_classes && (msg_type == DHCP6SOLICIT || msg_type == DHCP6REQUEST))
! 486: {
! 487: void *oro;
! 488:
! 489: if ((oro = opt6_find(state.packet_options, state.end, OPTION6_ORO, 0)))
! 490: for (i = 0; i < opt6_len(oro) - 1; i += 2)
! 491: if (opt6_uint(oro, i, 2) == OPTION6_PREFIX_CLASS)
! 492: {
! 493: dump_all_prefix_classes = 1;
! 494: break;
! 495: }
! 496:
! 497: if (msg_type != DHCP6SOLICIT || dump_all_prefix_classes)
! 498: /* Add the tags associated with prefix classes so we can use the DHCP ranges.
! 499: Not done for SOLICIT as we add them one-at-time. */
! 500: for (p = daemon->prefix_classes; p ; p = p->next)
! 501: {
! 502: p->tag.next = state.tags;
! 503: state.tags = &p->tag;
! 504: }
! 505: }
! 506: #endif
! 507:
! 508: tagif = run_tag_if(state.tags);
! 509:
! 510: /* if all the netids in the ignore list are present, ignore this client */
! 511: if (daemon->dhcp_ignore)
! 512: {
! 513: struct dhcp_netid_list *id_list;
! 514:
! 515: for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
! 516: if (match_netid(id_list->list, tagif, 0))
! 517: ignore = 1;
! 518: }
! 519:
! 520: /* if all the netids in the ignore_name list are present, ignore client-supplied name */
! 521: if (!state.hostname_auth)
! 522: {
! 523: struct dhcp_netid_list *id_list;
! 524:
! 525: for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
! 526: if ((!id_list->list) || match_netid(id_list->list, tagif, 0))
! 527: break;
! 528: if (id_list)
! 529: state.hostname = NULL;
! 530: }
! 531:
! 532:
! 533: switch (msg_type)
! 534: {
! 535: default:
! 536: return 0;
! 537:
! 538:
! 539: case DHCP6SOLICIT:
! 540: {
! 541: void *rapid_commit = opt6_find(state.packet_options, state.end, OPTION6_RAPID_COMMIT, 0);
! 542: int address_assigned = 0;
! 543: /* tags without all prefix-class tags */
! 544: struct dhcp_netid *solicit_tags = tagif;
! 545: struct dhcp_context *c;
! 546:
! 547: if (rapid_commit)
! 548: {
! 549: o = new_opt6(OPTION6_RAPID_COMMIT);
! 550: end_opt6(o);
! 551: }
! 552:
! 553: /* set reply message type */
! 554: *outmsgtypep = rapid_commit ? DHCP6REPLY : DHCP6ADVERTISE;
! 555:
! 556: log6_packet(&state, "DHCPSOLICIT", NULL, ignore ? _("ignored") : NULL);
! 557:
! 558: if (ignore)
! 559: return 0;
! 560:
! 561: /* reset USED bits in leases */
! 562: lease6_reset();
! 563:
! 564: /* Can use configured address max once per prefix */
! 565: for (c = context; c; c = c->current)
! 566: c->flags &= ~CONTEXT_CONF_USED;
! 567:
! 568: for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end))
! 569: {
! 570: void *ia_option, *ia_end;
! 571: unsigned int min_time = 0xffffffff;
! 572: int t1cntr;
! 573: int ia_counter;
! 574: /* set unless we're sending a particular prefix-class, when we
! 575: want only dhcp-ranges with the correct tags set and not those without any tags. */
! 576: int plain_range = 1;
! 577: u32 lease_time, requested_time;
! 578: struct dhcp_lease *ltmp;
! 579: struct in6_addr *req_addr;
! 580: struct in6_addr addr;
! 581:
! 582: if (!check_ia(&state, opt, &ia_end, &ia_option))
! 583: continue;
! 584:
! 585: /* reset USED bits in contexts - one address per prefix per IAID */
! 586: for (c = context; c; c = c->current)
! 587: c->flags &= ~CONTEXT_USED;
! 588:
! 589: #ifdef OPTION6_PREFIX_CLASS
! 590: if (daemon->prefix_classes && state.ia_type == OPTION6_IA_NA)
! 591: {
! 592: void *prefix_opt;
! 593: int prefix_class;
! 594:
! 595: if (dump_all_prefix_classes)
! 596: /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
! 597: plain_range = 0;
! 598: else
! 599: {
! 600: if ((prefix_opt = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_PREFIX_CLASS, 2)))
! 601: {
! 602:
! 603: prefix_class = opt6_uint(prefix_opt, 0, 2);
! 604:
! 605: for (p = daemon->prefix_classes; p ; p = p->next)
! 606: if (p->class == prefix_class)
! 607: break;
! 608:
! 609: if (!p)
! 610: my_syslog(MS_DHCP | LOG_WARNING, _("unknown prefix-class %d"), prefix_class);
! 611: else
! 612: {
! 613: /* add tag to list, and exclude undecorated dhcp-ranges */
! 614: p->tag.next = state.tags;
! 615: solicit_tags = run_tag_if(&p->tag);
! 616: plain_range = 0;
! 617: state.send_prefix_class = p;
! 618: }
! 619: }
! 620: else
! 621: {
! 622: /* client didn't ask for a prefix class, lets see if we can find one. */
! 623: for (p = daemon->prefix_classes; p ; p = p->next)
! 624: {
! 625: p->tag.next = NULL;
! 626: if (match_netid(&p->tag, solicit_tags, 1))
! 627: break;
! 628: }
! 629:
! 630: if (p)
! 631: {
! 632: plain_range = 0;
! 633: state.send_prefix_class = p;
! 634: }
! 635: }
! 636:
! 637: if (p && option_bool(OPT_LOG_OPTS))
! 638: my_syslog(MS_DHCP | LOG_INFO, "%u prefix class %d tag:%s", state.xid, p->class, p->tag.net);
! 639: }
! 640: }
! 641: #endif
! 642:
! 643: o = build_ia(&state, &t1cntr);
! 644:
! 645: for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
! 646: {
! 647: req_addr = opt6_ptr(ia_option, 0);
! 648: requested_time = opt6_uint(ia_option, 16, 4);
! 649:
! 650: if ((c = address6_valid(context, req_addr, solicit_tags, plain_range)))
! 651: {
! 652: lease_time = c->lease_time;
! 653: /* If the client asks for an address on the same network as a configured address,
! 654: offer the configured address instead, to make moving to newly-configured
! 655: addresses automatic. */
! 656: if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(&state, &addr))
! 657: {
! 658: req_addr = &addr;
! 659: mark_config_used(c, &addr);
! 660: if (have_config(config, CONFIG_TIME))
! 661: lease_time = config->lease_time;
! 662: }
! 663: else if (!(c = address6_available(context, req_addr, solicit_tags, plain_range)))
! 664: continue; /* not an address we're allowed */
! 665: else if (!check_address(&state, req_addr))
! 666: continue; /* address leased elsewhere */
! 667:
! 668: /* add address to output packet */
! 669: #ifdef OPTION6_PREFIX_CLASS
! 670: if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
! 671: state.send_prefix_class = prefix_class_from_context(c);
! 672: #endif
! 673: add_address(&state, c, lease_time, requested_time, &min_time, req_addr, rapid_commit != NULL, now);
! 674: mark_context_used(&state, context, req_addr);
! 675: get_context_tag(&state, c);
! 676: address_assigned = 1;
! 677: }
! 678: }
! 679:
! 680: /* Suggest configured address(es) */
! 681: for (c = context; c; c = c->current)
! 682: if (!(c->flags & CONTEXT_CONF_USED) &&
! 683: match_netid(c->filter, solicit_tags, plain_range) &&
! 684: config_valid(config, c, &addr) &&
! 685: check_address(&state, &addr))
! 686: {
! 687: mark_config_used(context, &addr);
! 688: if (have_config(config, CONFIG_TIME))
! 689: lease_time = config->lease_time;
! 690: else
! 691: lease_time = c->lease_time;
! 692: /* add address to output packet */
! 693: #ifdef OPTION6_PREFIX_CLASS
! 694: if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
! 695: state.send_prefix_class = prefix_class_from_context(c);
! 696: #endif
! 697: add_address(&state, c, lease_time, lease_time, &min_time, &addr, rapid_commit != NULL, now);
! 698: mark_context_used(&state, context, &addr);
! 699: get_context_tag(&state, c);
! 700: address_assigned = 1;
! 701: }
! 702:
! 703: /* return addresses for existing leases */
! 704: ltmp = NULL;
! 705: while ((ltmp = lease6_find_by_client(ltmp, state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state.clid, state.clid_len, state.iaid)))
! 706: {
! 707: req_addr = (struct in6_addr *)ltmp->hwaddr;
! 708: if ((c = address6_available(context, req_addr, solicit_tags, plain_range)))
! 709: {
! 710: #ifdef OPTION6_PREFIX_CLASS
! 711: if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
! 712: state.send_prefix_class = prefix_class_from_context(c);
! 713: #endif
! 714: add_address(&state, c, c->lease_time, c->lease_time, &min_time, req_addr, rapid_commit != NULL, now);
! 715: mark_context_used(&state, context, req_addr);
! 716: get_context_tag(&state, c);
! 717: address_assigned = 1;
! 718: }
! 719: }
! 720:
! 721: /* Return addresses for all valid contexts which don't yet have one */
! 722: while ((c = address6_allocate(context, state.clid, state.clid_len, state.iaid, ia_counter, solicit_tags, plain_range, &addr)))
! 723: {
! 724: #ifdef OPTION6_PREFIX_CLASS
! 725: if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
! 726: state.send_prefix_class = prefix_class_from_context(c);
! 727: #endif
! 728: add_address(&state, c, c->lease_time, c->lease_time, &min_time, &addr, rapid_commit != NULL, now);
! 729: mark_context_used(&state, context, &addr);
! 730: get_context_tag(&state, c);
! 731: address_assigned = 1;
! 732: }
! 733:
! 734: end_ia(t1cntr, min_time, 0);
! 735: end_opt6(o);
! 736: }
! 737:
! 738: if (address_assigned)
! 739: {
! 740: o1 = new_opt6(OPTION6_STATUS_CODE);
! 741: put_opt6_short(DHCP6SUCCESS);
! 742: put_opt6_string(_("success"));
! 743: end_opt6(o1);
! 744:
! 745: /* If --dhcp-authoritative is set, we can tell client not to wait for
! 746: other possible servers */
! 747: o = new_opt6(OPTION6_PREFERENCE);
! 748: put_opt6_char(option_bool(OPT_AUTHORITATIVE) ? 255 : 0);
! 749: end_opt6(o);
! 750: tagif = add_options(&state, fallback, context);
! 751: }
! 752: else
! 753: {
! 754: /* no address, return error */
! 755: o1 = new_opt6(OPTION6_STATUS_CODE);
! 756: put_opt6_short(DHCP6NOADDRS);
! 757: put_opt6_string(_("no addresses available"));
! 758: end_opt6(o1);
! 759: log6_packet(&state, "DHCPADVERTISE", NULL, _("no addresses available"));
! 760: }
! 761:
! 762: break;
! 763: }
! 764:
! 765: case DHCP6REQUEST:
! 766: {
! 767: int address_assigned = 0;
! 768:
! 769: /* set reply message type */
! 770: *outmsgtypep = DHCP6REPLY;
! 771:
! 772: log6_packet(&state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);
! 773:
! 774: if (ignore)
! 775: return 0;
! 776:
! 777: for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end))
! 778: {
! 779: void *ia_option, *ia_end;
! 780: unsigned int min_time = 0xffffffff;
! 781: int t1cntr;
! 782:
! 783: if (!check_ia(&state, opt, &ia_end, &ia_option))
! 784: continue;
! 785:
! 786: o = build_ia(&state, &t1cntr);
! 787:
! 788: for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
! 789: {
! 790: struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
! 791: u32 requested_time = opt6_uint(ia_option, 16, 4);
! 792: struct dhcp_context *dynamic, *c;
! 793: unsigned int lease_time;
! 794: struct in6_addr addr;
! 795: int config_ok = 0;
! 796:
! 797: if ((c = address6_valid(context, req_addr, tagif, 1)))
! 798: config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr);
! 799:
! 800: if ((dynamic = address6_available(context, req_addr, tagif, 1)) || c)
! 801: {
! 802: if (!dynamic && !config_ok)
! 803: {
! 804: /* Static range, not configured. */
! 805: o1 = new_opt6(OPTION6_STATUS_CODE);
! 806: put_opt6_short(DHCP6UNSPEC);
! 807: put_opt6_string(_("address unavailable"));
! 808: end_opt6(o1);
! 809: }
! 810: else if (!check_address(&state, req_addr))
! 811: {
! 812: /* Address leased to another DUID/IAID */
! 813: o1 = new_opt6(OPTION6_STATUS_CODE);
! 814: put_opt6_short(DHCP6UNSPEC);
! 815: put_opt6_string(_("address in use"));
! 816: end_opt6(o1);
! 817: }
! 818: else
! 819: {
! 820: if (!dynamic)
! 821: dynamic = c;
! 822:
! 823: lease_time = dynamic->lease_time;
! 824:
! 825: if (config_ok && have_config(config, CONFIG_TIME))
! 826: lease_time = config->lease_time;
! 827:
! 828: #ifdef OPTION6_PREFIX_CLASS
! 829: if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
! 830: state.send_prefix_class = prefix_class_from_context(c);
! 831: #endif
! 832: add_address(&state, dynamic, lease_time, requested_time, &min_time, req_addr, 1, now);
! 833: get_context_tag(&state, dynamic);
! 834: address_assigned = 1;
! 835: }
! 836: }
! 837: else
! 838: {
! 839: /* requested address not on the correct link */
! 840: o1 = new_opt6(OPTION6_STATUS_CODE);
! 841: put_opt6_short(DHCP6NOTONLINK);
! 842: put_opt6_string(_("not on link"));
! 843: end_opt6(o1);
! 844: }
! 845: }
! 846:
! 847: end_ia(t1cntr, min_time, 0);
! 848: end_opt6(o);
! 849: }
! 850:
! 851: if (address_assigned)
! 852: {
! 853: o1 = new_opt6(OPTION6_STATUS_CODE);
! 854: put_opt6_short(DHCP6SUCCESS);
! 855: put_opt6_string(_("success"));
! 856: end_opt6(o1);
! 857: }
! 858: else
! 859: {
! 860: /* no address, return error */
! 861: o1 = new_opt6(OPTION6_STATUS_CODE);
! 862: put_opt6_short(DHCP6NOADDRS);
! 863: put_opt6_string(_("no addresses available"));
! 864: end_opt6(o1);
! 865: log6_packet(&state, "DHCPREPLY", NULL, _("no addresses available"));
! 866: }
! 867:
! 868: tagif = add_options(&state, fallback, context);
! 869: break;
! 870: }
! 871:
! 872:
! 873: case DHCP6RENEW:
! 874: {
! 875: /* set reply message type */
! 876: *outmsgtypep = DHCP6REPLY;
! 877:
! 878: log6_packet(&state, "DHCPRENEW", NULL, NULL);
! 879:
! 880: for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end))
! 881: {
! 882: void *ia_option, *ia_end;
! 883: unsigned int min_time = 0xffffffff;
! 884: int t1cntr, iacntr;
! 885:
! 886: if (!check_ia(&state, opt, &ia_end, &ia_option))
! 887: continue;
! 888:
! 889: o = build_ia(&state, &t1cntr);
! 890: iacntr = save_counter(-1);
! 891:
! 892: for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
! 893: {
! 894: struct dhcp_lease *lease = NULL;
! 895: struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
! 896: u32 requested_time = opt6_uint(ia_option, 16, 4);
! 897: unsigned int preferred_time = 0; /* in case renewal inappropriate */
! 898: unsigned int valid_time = 0;
! 899: char *message = NULL;
! 900: struct dhcp_context *this_context;
! 901:
! 902: if (!(lease = lease6_find(state.clid, state.clid_len,
! 903: state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
! 904: state.iaid, req_addr)))
! 905: {
! 906: /* If the server cannot find a client entry for the IA the server
! 907: returns the IA containing no addresses with a Status Code option set
! 908: to NoBinding in the Reply message. */
! 909: save_counter(iacntr);
! 910: t1cntr = 0;
! 911:
! 912: log6_packet(&state, "DHCPREPLY", req_addr, _("lease not found"));
! 913:
! 914: o1 = new_opt6(OPTION6_STATUS_CODE);
! 915: put_opt6_short(DHCP6NOBINDING);
! 916: put_opt6_string(_("no binding found"));
! 917: end_opt6(o1);
! 918: break;
! 919: }
! 920:
! 921:
! 922: if ((this_context = address6_available(context, req_addr, tagif, 1)) ||
! 923: (this_context = address6_valid(context, req_addr, tagif, 1)))
! 924: {
! 925: struct in6_addr addr;
! 926: unsigned int lease_time;
! 927:
! 928: get_context_tag(&state, this_context);
! 929:
! 930: if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME))
! 931: lease_time = config->lease_time;
! 932: else
! 933: lease_time = this_context->lease_time;
! 934:
! 935: calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time, requested_time);
! 936:
! 937: lease_set_expires(lease, valid_time, now);
! 938: if (state.ia_type == OPTION6_IA_NA && state.hostname)
! 939: {
! 940: char *addr_domain = get_domain6(req_addr);
! 941: if (!state.send_domain)
! 942: state.send_domain = addr_domain;
! 943: lease_set_hostname(lease, state.hostname, state.hostname_auth, addr_domain, state.domain);
! 944: message = state.hostname;
! 945: }
! 946:
! 947:
! 948: if (preferred_time == 0)
! 949: message = _("deprecated");
! 950: }
! 951: else
! 952: message = _("address invalid");
! 953:
! 954: log6_packet(&state, "DHCPREPLY", req_addr, message);
! 955:
! 956: o1 = new_opt6(OPTION6_IAADDR);
! 957: put_opt6(req_addr, sizeof(*req_addr));
! 958: put_opt6_long(preferred_time);
! 959: put_opt6_long(valid_time);
! 960: end_opt6(o1);
! 961: }
! 962:
! 963: end_ia(t1cntr, min_time, 1);
! 964: end_opt6(o);
! 965: }
! 966:
! 967: tagif = add_options(&state, fallback, context);
! 968: break;
! 969:
! 970: }
! 971:
! 972: case DHCP6CONFIRM:
! 973: {
! 974: /* set reply message type */
! 975: *outmsgtypep = DHCP6REPLY;
! 976:
! 977: log6_packet(&state, "DHCPCONFIRM", NULL, NULL);
! 978:
! 979: for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end))
! 980: {
! 981: void *ia_option, *ia_end;
! 982:
! 983: for (check_ia(&state, opt, &ia_end, &ia_option);
! 984: ia_option;
! 985: ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
! 986: {
! 987: struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
! 988:
! 989: if (!address6_available(context, req_addr, tagif, 1))
! 990: {
! 991: o1 = new_opt6(OPTION6_STATUS_CODE);
! 992: put_opt6_short(DHCP6NOTONLINK);
! 993: put_opt6_string(_("confirm failed"));
! 994: end_opt6(o1);
! 995: return 1;
! 996: }
! 997:
! 998: log6_packet(&state, "DHCPREPLY", req_addr, state.hostname);
! 999: }
! 1000: }
! 1001:
! 1002: o1 = new_opt6(OPTION6_STATUS_CODE);
! 1003: put_opt6_short(DHCP6SUCCESS );
! 1004: put_opt6_string(_("all addresses still on link"));
! 1005: end_opt6(o1);
! 1006: break;
! 1007: }
! 1008:
! 1009: case DHCP6IREQ:
! 1010: {
! 1011: /* We can't discriminate contexts based on address, as we don't know it.
! 1012: If there is only one possible context, we can use its tags */
! 1013: if (context && context->netid.net && !context->current)
! 1014: {
! 1015: context->netid.next = NULL;
! 1016: state.context_tags = &context->netid;
! 1017: }
! 1018: log6_packet(&state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state.hostname);
! 1019: if (ignore)
! 1020: return 0;
! 1021: *outmsgtypep = DHCP6REPLY;
! 1022: tagif = add_options(&state, fallback, context);
! 1023: break;
! 1024: }
! 1025:
! 1026:
! 1027: case DHCP6RELEASE:
! 1028: {
! 1029: /* set reply message type */
! 1030: *outmsgtypep = DHCP6REPLY;
! 1031:
! 1032: log6_packet(&state, "DHCPRELEASE", NULL, NULL);
! 1033:
! 1034: for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end))
! 1035: {
! 1036: void *ia_option, *ia_end;
! 1037: int made_ia = 0;
! 1038:
! 1039: for (check_ia(&state, opt, &ia_end, &ia_option);
! 1040: ia_option;
! 1041: ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
! 1042: {
! 1043: struct dhcp_lease *lease;
! 1044:
! 1045: if ((lease = lease6_find(state.clid, state.clid_len, state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
! 1046: state.iaid, opt6_ptr(ia_option, 0))))
! 1047: lease_prune(lease, now);
! 1048: else
! 1049: {
! 1050: if (!made_ia)
! 1051: {
! 1052: o = new_opt6(state.ia_type);
! 1053: put_opt6_long(state.iaid);
! 1054: if (state.ia_type == OPTION6_IA_NA)
! 1055: {
! 1056: put_opt6_long(0);
! 1057: put_opt6_long(0);
! 1058: }
! 1059: made_ia = 1;
! 1060: }
! 1061:
! 1062: o1 = new_opt6(OPTION6_IAADDR);
! 1063: put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
! 1064: put_opt6_long(0);
! 1065: put_opt6_long(0);
! 1066: end_opt6(o1);
! 1067: }
! 1068: }
! 1069:
! 1070: if (made_ia)
! 1071: {
! 1072: o1 = new_opt6(OPTION6_STATUS_CODE);
! 1073: put_opt6_short(DHCP6NOBINDING);
! 1074: put_opt6_string(_("no binding found"));
! 1075: end_opt6(o1);
! 1076:
! 1077: end_opt6(o);
! 1078: }
! 1079: }
! 1080:
! 1081: o1 = new_opt6(OPTION6_STATUS_CODE);
! 1082: put_opt6_short(DHCP6SUCCESS);
! 1083: put_opt6_string(_("release received"));
! 1084: end_opt6(o1);
! 1085:
! 1086: break;
! 1087: }
! 1088:
! 1089: case DHCP6DECLINE:
! 1090: {
! 1091: /* set reply message type */
! 1092: *outmsgtypep = DHCP6REPLY;
! 1093:
! 1094: log6_packet(&state, "DHCPDECLINE", NULL, NULL);
! 1095:
! 1096: for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end))
! 1097: {
! 1098: void *ia_option, *ia_end;
! 1099: int made_ia = 0;
! 1100:
! 1101: for (check_ia(&state, opt, &ia_end, &ia_option);
! 1102: ia_option;
! 1103: ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
! 1104: {
! 1105: struct dhcp_lease *lease;
! 1106: struct in6_addr *addrp = opt6_ptr(ia_option, 0);
! 1107:
! 1108: if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, addrp))
! 1109: {
! 1110: prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
! 1111: inet_ntop(AF_INET6, addrp, daemon->addrbuff, ADDRSTRLEN);
! 1112: my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
! 1113: daemon->addrbuff, daemon->dhcp_buff3);
! 1114: config->flags |= CONFIG_DECLINED;
! 1115: config->decline_time = now;
! 1116: }
! 1117: else
! 1118: /* make sure this host gets a different address next time. */
! 1119: for (; context; context = context->current)
! 1120: context->addr_epoch++;
! 1121:
! 1122: if ((lease = lease6_find(state.clid, state.clid_len, state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
! 1123: state.iaid, opt6_ptr(ia_option, 0))))
! 1124: lease_prune(lease, now);
! 1125: else
! 1126: {
! 1127: if (!made_ia)
! 1128: {
! 1129: o = new_opt6(state.ia_type);
! 1130: put_opt6_long(state.iaid);
! 1131: if (state.ia_type == OPTION6_IA_NA)
! 1132: {
! 1133: put_opt6_long(0);
! 1134: put_opt6_long(0);
! 1135: }
! 1136: made_ia = 1;
! 1137: }
! 1138:
! 1139: o1 = new_opt6(OPTION6_IAADDR);
! 1140: put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
! 1141: put_opt6_long(0);
! 1142: put_opt6_long(0);
! 1143: end_opt6(o1);
! 1144: }
! 1145: }
! 1146:
! 1147: if (made_ia)
! 1148: {
! 1149: o1 = new_opt6(OPTION6_STATUS_CODE);
! 1150: put_opt6_short(DHCP6NOBINDING);
! 1151: put_opt6_string(_("no binding found"));
! 1152: end_opt6(o1);
! 1153:
! 1154: end_opt6(o);
! 1155: }
! 1156:
! 1157: }
! 1158: break;
! 1159: }
! 1160:
! 1161: }
! 1162:
! 1163: log_tags(tagif, state.xid);
! 1164:
! 1165: if (option_bool(OPT_LOG_OPTS))
! 1166: log6_opts(0, state.xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1));
! 1167:
! 1168: return 1;
! 1169:
! 1170: }
! 1171:
! 1172: struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, struct dhcp_context *context)
! 1173: {
! 1174: void *oro;
! 1175: /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
! 1176: struct dhcp_netid *tagif = option_filter(state->tags, state->context_tags, daemon->dhcp_opts6);
! 1177: struct dhcp_opt *opt_cfg;
! 1178: int done_dns = 0, do_encap = 0;
! 1179: int i, o, o1;
! 1180:
! 1181: oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0);
! 1182:
! 1183: for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
! 1184: {
! 1185: /* netids match and not encapsulated? */
! 1186: if (!(opt_cfg->flags & DHOPT_TAGOK))
! 1187: continue;
! 1188:
! 1189: if (!(opt_cfg->flags & DHOPT_FORCE) && oro)
! 1190: {
! 1191: for (i = 0; i < opt6_len(oro) - 1; i += 2)
! 1192: if (opt6_uint(oro, i, 2) == (unsigned)opt_cfg->opt)
! 1193: break;
! 1194:
! 1195: /* option not requested */
! 1196: if (i >= opt6_len(oro) - 1)
! 1197: continue;
! 1198: }
! 1199:
! 1200: if (opt_cfg->opt == OPTION6_DNS_SERVER)
! 1201: {
! 1202: done_dns = 1;
! 1203: if (opt_cfg->len == 0)
! 1204: continue;
! 1205: }
! 1206:
! 1207: o = new_opt6(opt_cfg->opt);
! 1208: if (opt_cfg->flags & DHOPT_ADDR6)
! 1209: {
! 1210: int j;
! 1211: struct in6_addr *a = (struct in6_addr *)opt_cfg->val;
! 1212: for (j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
! 1213: {
! 1214: /* zero means "self" (but not in vendorclass options.) */
! 1215: if (IN6_IS_ADDR_UNSPECIFIED(a))
! 1216: {
! 1217: if (!add_local_addrs(context))
! 1218: put_opt6(fallback, IN6ADDRSZ);
! 1219: }
! 1220: else
! 1221: put_opt6(a, IN6ADDRSZ);
! 1222: }
! 1223: }
! 1224: else if (opt_cfg->val)
! 1225: put_opt6(opt_cfg->val, opt_cfg->len);
! 1226: end_opt6(o);
! 1227: }
! 1228:
! 1229: if (daemon->port == NAMESERVER_PORT && !done_dns &&
! 1230: (!IN6_IS_ADDR_UNSPECIFIED(&context->local6) ||
! 1231: !IN6_IS_ADDR_UNSPECIFIED(fallback)))
! 1232: {
! 1233: o = new_opt6(OPTION6_DNS_SERVER);
! 1234: if (!add_local_addrs(context))
! 1235: put_opt6(fallback, IN6ADDRSZ);
! 1236: end_opt6(o);
! 1237: }
! 1238:
! 1239: /* handle vendor-identifying vendor-encapsulated options,
! 1240: dhcp-option = vi-encap:13,17,....... */
! 1241: for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
! 1242: opt_cfg->flags &= ~DHOPT_ENCAP_DONE;
! 1243:
! 1244: if (oro)
! 1245: for (i = 0; i < opt6_len(oro) - 1; i += 2)
! 1246: if (opt6_uint(oro, i, 2) == OPTION6_VENDOR_OPTS)
! 1247: do_encap = 1;
! 1248:
! 1249: for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
! 1250: {
! 1251: if (opt_cfg->flags & DHOPT_RFC3925)
! 1252: {
! 1253: int found = 0;
! 1254: struct dhcp_opt *oc;
! 1255:
! 1256: if (opt_cfg->flags & DHOPT_ENCAP_DONE)
! 1257: continue;
! 1258:
! 1259: for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
! 1260: {
! 1261: oc->flags &= ~DHOPT_ENCAP_MATCH;
! 1262:
! 1263: if (!(oc->flags & DHOPT_RFC3925) || opt_cfg->u.encap != oc->u.encap)
! 1264: continue;
! 1265:
! 1266: oc->flags |= DHOPT_ENCAP_DONE;
! 1267: if (match_netid(oc->netid, tagif, 1))
! 1268: {
! 1269: /* option requested/forced? */
! 1270: if (!oro || do_encap || (oc->flags & DHOPT_FORCE))
! 1271: {
! 1272: oc->flags |= DHOPT_ENCAP_MATCH;
! 1273: found = 1;
! 1274: }
! 1275: }
! 1276: }
! 1277:
! 1278: if (found)
! 1279: {
! 1280: o = new_opt6(OPTION6_VENDOR_OPTS);
! 1281: put_opt6_long(opt_cfg->u.encap);
! 1282:
! 1283: for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
! 1284: if (oc->flags & DHOPT_ENCAP_MATCH)
! 1285: {
! 1286: o1 = new_opt6(oc->opt);
! 1287: put_opt6(oc->val, oc->len);
! 1288: end_opt6(o1);
! 1289: }
! 1290: end_opt6(o);
! 1291: }
! 1292: }
! 1293: }
! 1294:
! 1295:
! 1296: if (state->hostname)
! 1297: {
! 1298: unsigned char *p;
! 1299: size_t len = strlen(state->hostname);
! 1300:
! 1301: if (state->send_domain)
! 1302: len += strlen(state->send_domain) + 1;
! 1303:
! 1304: o = new_opt6(OPTION6_FQDN);
! 1305: if ((p = expand(len + 3)))
! 1306: {
! 1307: *(p++) = state->fqdn_flags;
! 1308: p = do_rfc1035_name(p, state->hostname);
! 1309: if (state->send_domain)
! 1310: p = do_rfc1035_name(p, state->send_domain);
! 1311: *p = 0;
! 1312: }
! 1313: end_opt6(o);
! 1314: }
! 1315:
! 1316:
! 1317: /* logging */
! 1318: if (option_bool(OPT_LOG_OPTS) && oro)
! 1319: {
! 1320: char *q = daemon->namebuff;
! 1321: for (i = 0; i < opt6_len(oro) - 1; i += 2)
! 1322: {
! 1323: char *s = option_string(AF_INET6, opt6_uint(oro, i, 2), NULL, 0, NULL, 0);
! 1324: q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
! 1325: "%d%s%s%s",
! 1326: opt6_uint(oro, i, 2),
! 1327: strlen(s) != 0 ? ":" : "",
! 1328: s,
! 1329: (i > opt6_len(oro) - 3) ? "" : ", ");
! 1330: if ( i > opt6_len(oro) - 3 || (q - daemon->namebuff) > 40)
! 1331: {
! 1332: q = daemon->namebuff;
! 1333: my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), state->xid, daemon->namebuff);
! 1334: }
! 1335: }
! 1336: }
! 1337:
! 1338: return tagif;
! 1339: }
! 1340:
! 1341: static int add_local_addrs(struct dhcp_context *context)
! 1342: {
! 1343: int done = 0;
! 1344:
! 1345: for (; context; context = context->current)
! 1346: if ((context->flags & CONTEXT_USED) && !IN6_IS_ADDR_UNSPECIFIED(&context->local6))
! 1347: {
! 1348: /* squash duplicates */
! 1349: struct dhcp_context *c;
! 1350: for (c = context->current; c; c = c->current)
! 1351: if ((c->flags & CONTEXT_USED) &&
! 1352: IN6_ARE_ADDR_EQUAL(&context->local6, &c->local6))
! 1353: break;
! 1354:
! 1355: if (!c)
! 1356: {
! 1357: done = 1;
! 1358: put_opt6(&context->local6, IN6ADDRSZ);
! 1359: }
! 1360: }
! 1361:
! 1362: return done;
! 1363: }
! 1364:
! 1365:
! 1366: static void get_context_tag(struct state *state, struct dhcp_context *context)
! 1367: {
! 1368: /* get tags from context if we've not used it before */
! 1369: if (context->netid.next == &context->netid && context->netid.net)
! 1370: {
! 1371: context->netid.next = state->context_tags;
! 1372: state->context_tags = &context->netid;
! 1373: if (!state->hostname_auth)
! 1374: {
! 1375: struct dhcp_netid_list *id_list;
! 1376:
! 1377: for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
! 1378: if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
! 1379: break;
! 1380: if (id_list)
! 1381: state->hostname = NULL;
! 1382: }
! 1383: }
! 1384: }
! 1385:
! 1386: #ifdef OPTION6_PREFIX_CLASS
! 1387: static struct prefix_class *prefix_class_from_context(struct dhcp_context *context)
! 1388: {
! 1389: struct prefix_class *p;
! 1390: struct dhcp_netid *t;
! 1391:
! 1392: for (p = daemon->prefix_classes; p ; p = p->next)
! 1393: for (t = context->filter; t; t = t->next)
! 1394: if (strcmp(p->tag.net, t->net) == 0)
! 1395: return p;
! 1396:
! 1397: return NULL;
! 1398: }
! 1399: #endif
! 1400:
! 1401: static int check_ia(struct state *state, void *opt, void **endp, void **ia_option)
! 1402: {
! 1403: state->ia_type = opt6_type(opt);
! 1404: *ia_option = NULL;
! 1405:
! 1406: if (state->ia_type != OPTION6_IA_NA && state->ia_type != OPTION6_IA_TA)
! 1407: return 0;
! 1408:
! 1409: if (state->ia_type == OPTION6_IA_NA && opt6_len(opt) < 12)
! 1410: return 0;
! 1411:
! 1412: if (state->ia_type == OPTION6_IA_TA && opt6_len(opt) < 4)
! 1413: return 0;
! 1414:
! 1415: *endp = opt6_ptr(opt, opt6_len(opt));
! 1416: state->iaid = opt6_uint(opt, 0, 4);
! 1417: *ia_option = opt6_find(opt6_ptr(opt, state->ia_type == OPTION6_IA_NA ? 12 : 4), *endp, OPTION6_IAADDR, 24);
! 1418:
! 1419: return 1;
! 1420: }
! 1421:
! 1422:
! 1423: static int build_ia(struct state *state, int *t1cntr)
! 1424: {
! 1425: int o = new_opt6(state->ia_type);
! 1426:
! 1427: put_opt6_long(state->iaid);
! 1428: *t1cntr = 0;
! 1429:
! 1430: if (state->ia_type == OPTION6_IA_NA)
! 1431: {
! 1432: /* save pointer */
! 1433: *t1cntr = save_counter(-1);
! 1434: /* so we can fill these in later */
! 1435: put_opt6_long(0);
! 1436: put_opt6_long(0);
! 1437: }
! 1438:
! 1439: return o;
! 1440: }
! 1441:
! 1442: static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
! 1443: {
! 1444: if (t1cntr != 0)
! 1445: {
! 1446: /* go back an fill in fields in IA_NA option */
! 1447: int sav = save_counter(t1cntr);
! 1448: unsigned int t1, t2, fuzz = 0;
! 1449:
! 1450: if (do_fuzz)
! 1451: {
! 1452: fuzz = rand16();
! 1453:
! 1454: while (fuzz > (min_time/16))
! 1455: fuzz = fuzz/2;
! 1456: }
! 1457:
! 1458: t1 = (min_time == 0xffffffff) ? 0xffffffff : min_time/2 - fuzz;
! 1459: t2 = (min_time == 0xffffffff) ? 0xffffffff : ((min_time/8)*7) - fuzz;
! 1460: put_opt6_long(t1);
! 1461: put_opt6_long(t2);
! 1462: save_counter(sav);
! 1463: }
! 1464: }
! 1465:
! 1466: static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, unsigned int requested_time,
! 1467: unsigned int *min_time, struct in6_addr *addr, int do_update, time_t now)
! 1468: {
! 1469: unsigned int valid_time, preferred_time;
! 1470: int o = new_opt6(OPTION6_IAADDR);
! 1471: struct dhcp_lease *lease;
! 1472:
! 1473: calculate_times(context, min_time, &valid_time, &preferred_time, lease_time, requested_time);
! 1474:
! 1475: put_opt6(addr, sizeof(*addr));
! 1476: put_opt6_long(preferred_time);
! 1477: put_opt6_long(valid_time);
! 1478:
! 1479: #ifdef OPTION6_PREFIX_CLASS
! 1480: if (state->send_prefix_class)
! 1481: {
! 1482: int o1 = new_opt6(OPTION6_PREFIX_CLASS);
! 1483: put_opt6_short(state->send_prefix_class->class);
! 1484: end_opt6(o1);
! 1485: }
! 1486: #endif
! 1487:
! 1488: end_opt6(o);
! 1489:
! 1490: if (do_update)
! 1491: update_leases(state, context, addr, valid_time, now);
! 1492:
! 1493: if ((lease = lease6_find_by_addr(addr, 128, 0)))
! 1494: lease->flags |= LEASE_USED;
! 1495:
! 1496: /* get tags from context if we've not used it before */
! 1497: if (context->netid.next == &context->netid && context->netid.net)
! 1498: {
! 1499: context->netid.next = state->context_tags;
! 1500: state->context_tags = &context->netid;
! 1501:
! 1502: if (!state->hostname_auth)
! 1503: {
! 1504: struct dhcp_netid_list *id_list;
! 1505:
! 1506: for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
! 1507: if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
! 1508: break;
! 1509: if (id_list)
! 1510: state->hostname = NULL;
! 1511: }
! 1512: }
! 1513:
! 1514: log6_packet(state, do_update ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname);
! 1515:
! 1516: }
! 1517:
! 1518: static void mark_context_used(struct state *state, struct dhcp_context *context, struct in6_addr *addr)
! 1519: {
! 1520: /* Mark that we have an address for this prefix. */
! 1521: #ifdef OPTION6_PREFIX_CLASS
! 1522: for (; context; context = context->current)
! 1523: if (is_same_net6(addr, &context->start6, context->prefix) &&
! 1524: (!state->send_prefix_class || state->send_prefix_class == prefix_class_from_context(context)))
! 1525: context->flags |= CONTEXT_USED;
! 1526: #else
! 1527: (void)state; /* warning */
! 1528: for (; context; context = context->current)
! 1529: if (is_same_net6(addr, &context->start6, context->prefix))
! 1530: context->flags |= CONTEXT_USED;
! 1531: #endif
! 1532: }
! 1533:
! 1534: static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr)
! 1535: {
! 1536: for (; context; context = context->current)
! 1537: if (is_same_net6(addr, &context->start6, context->prefix))
! 1538: context->flags |= CONTEXT_CONF_USED;
! 1539: }
! 1540:
! 1541: /* make sure address not leased to another CLID/IAID */
! 1542: static int check_address(struct state *state, struct in6_addr *addr)
! 1543: {
! 1544: struct dhcp_lease *lease;
! 1545:
! 1546: if (!(lease = lease6_find_by_addr(addr, 128, 0)))
! 1547: return 1;
! 1548:
! 1549: if (lease->clid_len != state->clid_len ||
! 1550: memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
! 1551: lease->hwaddr_type != state->iaid)
! 1552: return 0;
! 1553:
! 1554: return 1;
! 1555: }
! 1556:
! 1557: static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
! 1558: unsigned int *preferred_timep, unsigned int lease_time, unsigned int requested_time)
! 1559: {
! 1560: unsigned int preferred_time, valid_time;
! 1561:
! 1562: if (requested_time < 120u )
! 1563: requested_time = 120u; /* sanity */
! 1564: if (lease_time == 0xffffffff || (requested_time != 0xffffffff && requested_time < lease_time))
! 1565: lease_time = requested_time;
! 1566:
! 1567: valid_time = (context->valid < lease_time) ? context->valid : lease_time;
! 1568: preferred_time = (context->preferred < lease_time) ? context->preferred : lease_time;
! 1569:
! 1570: if (context->flags & CONTEXT_DEPRECATE)
! 1571: preferred_time = 0;
! 1572:
! 1573: if (preferred_time != 0 && preferred_time < *min_time)
! 1574: *min_time = preferred_time;
! 1575:
! 1576: if (valid_time != 0 && valid_time < *min_time)
! 1577: *min_time = valid_time;
! 1578:
! 1579: *valid_timep = valid_time;
! 1580: *preferred_timep = preferred_time;
! 1581: }
! 1582:
! 1583: static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now)
! 1584: {
! 1585: struct dhcp_lease *lease = lease6_find_by_addr(addr, 128, 0);
! 1586: struct dhcp_netid *tagif = run_tag_if(state->tags);
! 1587:
! 1588: if (!lease)
! 1589: lease = lease6_allocate(addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
! 1590:
! 1591: if (lease)
! 1592: {
! 1593: lease_set_expires(lease, lease_time, now);
! 1594: lease_set_hwaddr(lease, NULL, state->clid, 0, state->iaid, state->clid_len, now, 0);
! 1595: lease_set_interface(lease, state->interface, now);
! 1596: if (state->hostname && state->ia_type == OPTION6_IA_NA)
! 1597: {
! 1598: char *addr_domain = get_domain6(addr);
! 1599: if (!state->send_domain)
! 1600: state->send_domain = addr_domain;
! 1601: lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
! 1602: }
! 1603:
! 1604: #ifdef HAVE_SCRIPT
! 1605: if (daemon->lease_change_command)
! 1606: {
! 1607: void *class_opt;
! 1608: lease->flags |= LEASE_CHANGED;
! 1609: free(lease->extradata);
! 1610: lease->extradata = NULL;
! 1611: lease->extradata_size = lease->extradata_len = 0;
! 1612: lease->vendorclass_count = 0;
! 1613:
! 1614: if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
! 1615: {
! 1616: void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
! 1617: lease->vendorclass_count++;
! 1618: /* send enterprise number first */
! 1619: sprintf(daemon->dhcp_buff2, "%u", opt6_uint(class_opt, 0, 4));
! 1620: lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);
! 1621:
! 1622: if (opt6_len(class_opt) >= 6)
! 1623: for (enc_opt = opt6_ptr(class_opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
! 1624: {
! 1625: lease->vendorclass_count++;
! 1626: lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
! 1627: }
! 1628: }
! 1629:
! 1630: lease_add_extradata(lease, (unsigned char *)state->client_hostname,
! 1631: state->client_hostname ? strlen(state->client_hostname) : 0, 0);
! 1632:
! 1633: /* space-concat tag set */
! 1634: if (!tagif && !context->netid.net)
! 1635: lease_add_extradata(lease, NULL, 0, 0);
! 1636: else
! 1637: {
! 1638: if (context->netid.net)
! 1639: lease_add_extradata(lease, (unsigned char *)context->netid.net, strlen(context->netid.net), tagif ? ' ' : 0);
! 1640:
! 1641: if (tagif)
! 1642: {
! 1643: struct dhcp_netid *n;
! 1644: for (n = tagif; n; n = n->next)
! 1645: {
! 1646: struct dhcp_netid *n1;
! 1647: /* kill dupes */
! 1648: for (n1 = n->next; n1; n1 = n1->next)
! 1649: if (strcmp(n->net, n1->net) == 0)
! 1650: break;
! 1651: if (!n1)
! 1652: lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
! 1653: }
! 1654: }
! 1655: }
! 1656:
! 1657: if (state->link_address)
! 1658: inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
! 1659:
! 1660: lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0);
! 1661:
! 1662: if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2)))
! 1663: {
! 1664: void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
! 1665: for (enc_opt = opt6_ptr(class_opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
! 1666: lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
! 1667: }
! 1668: }
! 1669: #endif
! 1670:
! 1671: }
! 1672: }
! 1673:
! 1674:
! 1675:
! 1676: static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts)
! 1677: {
! 1678: void *opt;
! 1679: char *desc = nest ? "nest" : "sent";
! 1680:
! 1681: if (start_opts == end_opts)
! 1682: return;
! 1683:
! 1684: for (opt = start_opts; opt; opt = opt6_next(opt, end_opts))
! 1685: {
! 1686: int type = opt6_type(opt);
! 1687: void *ia_options = NULL;
! 1688: char *optname;
! 1689:
! 1690: if (type == OPTION6_IA_NA)
! 1691: {
! 1692: sprintf(daemon->namebuff, "IAID=%u T1=%u T2=%u",
! 1693: opt6_uint(opt, 0, 4), opt6_uint(opt, 4, 4), opt6_uint(opt, 8, 4));
! 1694: optname = "ia-na";
! 1695: ia_options = opt6_ptr(opt, 12);
! 1696: }
! 1697: else if (type == OPTION6_IA_TA)
! 1698: {
! 1699: sprintf(daemon->namebuff, "IAID=%u", opt6_uint(opt, 0, 4));
! 1700: optname = "ia-ta";
! 1701: ia_options = opt6_ptr(opt, 4);
! 1702: }
! 1703: else if (type == OPTION6_IAADDR)
! 1704: {
! 1705: inet_ntop(AF_INET6, opt6_ptr(opt, 0), daemon->addrbuff, ADDRSTRLEN);
! 1706: sprintf(daemon->namebuff, "%s PL=%u VL=%u",
! 1707: daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
! 1708: optname = "iaaddr";
! 1709: ia_options = opt6_ptr(opt, 24);
! 1710: }
! 1711: #ifdef OPTION6_PREFIX_CLASS
! 1712: else if (type == OPTION6_PREFIX_CLASS)
! 1713: {
! 1714: optname = "prefix-class";
! 1715: sprintf(daemon->namebuff, "class=%u", opt6_uint(opt, 0, 2));
! 1716: }
! 1717: #endif
! 1718: else if (type == OPTION6_STATUS_CODE)
! 1719: {
! 1720: int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
! 1721: memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), opt6_len(opt)-2);
! 1722: daemon->namebuff[len + opt6_len(opt) - 2] = 0;
! 1723: optname = "status";
! 1724: }
! 1725: else
! 1726: {
! 1727: /* account for flag byte on FQDN */
! 1728: int offset = type == OPTION6_FQDN ? 1 : 0;
! 1729: optname = option_string(AF_INET6, type, opt6_ptr(opt, offset), opt6_len(opt) - offset, daemon->namebuff, MAXDNAME);
! 1730: }
! 1731:
! 1732: my_syslog(MS_DHCP | LOG_INFO, "%u %s size:%3d option:%3d %s %s",
! 1733: xid, desc, opt6_len(opt), type, optname, daemon->namebuff);
! 1734:
! 1735: if (ia_options)
! 1736: log6_opts(1, xid, ia_options, opt6_ptr(opt, opt6_len(opt)));
! 1737: }
! 1738: }
! 1739:
! 1740: static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string)
! 1741: {
! 1742: int clid_len = state->clid_len;
! 1743:
! 1744: /* avoid buffer overflow */
! 1745: if (clid_len > 100)
! 1746: clid_len = 100;
! 1747:
! 1748: print_mac(daemon->namebuff, state->clid, clid_len);
! 1749:
! 1750: if (addr)
! 1751: {
! 1752: inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, 255);
! 1753: strcat(daemon->dhcp_buff2, " ");
! 1754: }
! 1755: else
! 1756: daemon->dhcp_buff2[0] = 0;
! 1757:
! 1758: if(option_bool(OPT_LOG_OPTS))
! 1759: my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s %s",
! 1760: state->xid,
! 1761: type,
! 1762: state->iface_name,
! 1763: daemon->dhcp_buff2,
! 1764: daemon->namebuff,
! 1765: string ? string : "");
! 1766: else
! 1767: my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s %s",
! 1768: type,
! 1769: state->iface_name,
! 1770: daemon->dhcp_buff2,
! 1771: daemon->namebuff,
! 1772: string ? string : "");
! 1773: }
! 1774:
! 1775: static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize)
! 1776: {
! 1777: u16 opt, opt_len;
! 1778: void *start;
! 1779:
! 1780: if (!opts)
! 1781: return NULL;
! 1782:
! 1783: while (1)
! 1784: {
! 1785: if (end - opts < 4)
! 1786: return NULL;
! 1787:
! 1788: start = opts;
! 1789: GETSHORT(opt, opts);
! 1790: GETSHORT(opt_len, opts);
! 1791:
! 1792: if (opt_len > (end - opts))
! 1793: return NULL;
! 1794:
! 1795: if (opt == search && (opt_len >= minsize))
! 1796: return start;
! 1797:
! 1798: opts += opt_len;
! 1799: }
! 1800: }
! 1801:
! 1802: static void *opt6_next(void *opts, void *end)
! 1803: {
! 1804: u16 opt_len;
! 1805:
! 1806: if (end - opts < 4)
! 1807: return NULL;
! 1808:
! 1809: opts += 2;
! 1810: GETSHORT(opt_len, opts);
! 1811:
! 1812: if (opt_len >= (end - opts))
! 1813: return NULL;
! 1814:
! 1815: return opts + opt_len;
! 1816: }
! 1817:
! 1818: static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
! 1819: {
! 1820: /* this worries about unaligned data and byte order */
! 1821: unsigned int ret = 0;
! 1822: int i;
! 1823: unsigned char *p = opt6_ptr(opt, offset);
! 1824:
! 1825: for (i = 0; i < size; i++)
! 1826: ret = (ret << 8) | *p++;
! 1827:
! 1828: return ret;
! 1829: }
! 1830:
! 1831: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>