File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / rfc3315.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 29 19:37:40 2013 UTC (10 years, 11 months ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_66p0, v2_66, HEAD
dnsmasq

    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>