Diff for /embedaddon/dnsmasq/src/rfc3315.c between versions 1.1.1.3 and 1.1.1.4

version 1.1.1.3, 2016/11/02 09:57:01 version 1.1.1.4, 2021/03/17 00:56:46
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
   
    This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
Line 21 Line 21
   
 struct state {  struct state {
   unsigned char *clid;    unsigned char *clid;
  int clid_len, iaid, ia_type, interface, hostname_auth, lease_allocate;  int clid_len, ia_type, interface, hostname_auth, lease_allocate;
   char *client_hostname, *hostname, *domain, *send_domain;    char *client_hostname, *hostname, *domain, *send_domain;
   struct dhcp_context *context;    struct dhcp_context *context;
   struct in6_addr *link_address, *fallback, *ll_addr, *ula_addr;    struct in6_addr *link_address, *fallback, *ll_addr, *ula_addr;
  unsigned int xid, fqdn_flags;  unsigned int xid, fqdn_flags, iaid;
   char *iface_name;    char *iface_name;
   void *packet_options, *end;    void *packet_options, *end;
   struct dhcp_netid *tags, *context_tags;    struct dhcp_netid *tags, *context_tags;
   unsigned char mac[DHCP_CHADDR_MAX];    unsigned char mac[DHCP_CHADDR_MAX];
   unsigned int mac_len, mac_type;    unsigned int mac_len, mac_type;
 #ifdef OPTION6_PREFIX_CLASS  
   struct prefix_class *send_prefix_class;  
 #endif  
 };  };
   
 static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,   static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz, 
Line 49  static void get_context_tag(struct state *state, struc Line 46  static void get_context_tag(struct state *state, struc
 static int check_ia(struct state *state, void *opt, void **endp, void **ia_option);  static int check_ia(struct state *state, void *opt, void **endp, void **ia_option);
 static int build_ia(struct state *state, int *t1cntr);  static int build_ia(struct state *state, int *t1cntr);
 static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz);  static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz);
 #ifdef OPTION6_PREFIX_CLASS  
 static struct prefix_class *prefix_class_from_context(struct dhcp_context *context);  
 #endif  
 static void mark_context_used(struct state *state, struct in6_addr *addr);  static void mark_context_used(struct state *state, struct in6_addr *addr);
 static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr);  static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr);
 static int check_address(struct state *state, struct in6_addr *addr);  static int check_address(struct state *state, struct in6_addr *addr);
   static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state, time_t now);
   static struct addrlist *config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr);
 static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,   static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option, 
                         unsigned int *min_time, struct in6_addr *addr, time_t now);                          unsigned int *min_time, struct in6_addr *addr, time_t now);
 static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);  static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
Line 89  unsigned short dhcp6_reply(struct dhcp_context *contex Line 85  unsigned short dhcp6_reply(struct dhcp_context *contex
   for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)    for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
     vendor->netid.next = &vendor->netid;      vendor->netid.next = &vendor->netid;
       
  save_counter(0);  reset_counter();
   state.context = context;    state.context = context;
   state.interface = interface;    state.interface = interface;
   state.iface_name = iface_name;    state.iface_name = iface_name;
Line 118  static int dhcp6_maybe_relay(struct state *state, void Line 114  static int dhcp6_maybe_relay(struct state *state, void
   void *opt;    void *opt;
   struct dhcp_vendor *vendor;    struct dhcp_vendor *vendor;
   
  /* if not an encaplsulated relayed message, just do the stuff */  /* if not an encapsulated relayed message, just do the stuff */
   if (msg_type != DHCP6RELAYFORW)    if (msg_type != DHCP6RELAYFORW)
     {      {
       /* if link_address != NULL if points to the link address field of the         /* if link_address != NULL if points to the link address field of the 
Line 134  static int dhcp6_maybe_relay(struct state *state, void Line 130  static int dhcp6_maybe_relay(struct state *state, void
       else        else
         {          {
           struct dhcp_context *c;            struct dhcp_context *c;
             struct shared_network *share = NULL;
           state->context = NULL;            state->context = NULL;
           
           if (!IN6_IS_ADDR_LOOPBACK(state->link_address) &&            if (!IN6_IS_ADDR_LOOPBACK(state->link_address) &&
               !IN6_IS_ADDR_LINKLOCAL(state->link_address) &&                !IN6_IS_ADDR_LINKLOCAL(state->link_address) &&
               !IN6_IS_ADDR_MULTICAST(state->link_address))                !IN6_IS_ADDR_MULTICAST(state->link_address))
             for (c = daemon->dhcp6; c; c = c->next)              for (c = daemon->dhcp6; c; c = c->next)
              if ((c->flags & CONTEXT_DHCP) &&              {
                  !(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&                for (share = daemon->shared_networks; share; share = share->next)
                  is_same_net6(state->link_address, &c->start6, c->prefix) &&                  {
                  is_same_net6(state->link_address, &c->end6, c->prefix))                    if (share->shared_addr.s_addr != 0)
                {                      continue;
                  c->preferred = c->valid = 0xffffffff;                    
                  c->current = state->context;                    if (share->if_index != 0 ||
                  state->context = c;                        !IN6_ARE_ADDR_EQUAL(state->link_address, &share->match_addr6))
                }                      continue;
                     
                     if ((c->flags & CONTEXT_DHCP) &&
                         !(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
                         is_same_net6(&share->shared_addr6, &c->start6, c->prefix) &&
                         is_same_net6(&share->shared_addr6, &c->end6, c->prefix))
                       break;
                   }
                 
                 if (share ||
                     ((c->flags & CONTEXT_DHCP) &&
                      !(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
                      is_same_net6(state->link_address, &c->start6, c->prefix) &&
                      is_same_net6(state->link_address, &c->end6, c->prefix)))
                   {
                     c->preferred = c->valid = 0xffffffff;
                     c->current = state->context;
                     state->context = c;
                   }
               }
                       
           if (!state->context)            if (!state->context)
             {              {
Line 206  static int dhcp6_maybe_relay(struct state *state, void Line 222  static int dhcp6_maybe_relay(struct state *state, void
   /* RFC-6939 */    /* RFC-6939 */
   if ((opt = opt6_find(opts, end, OPTION6_CLIENT_MAC, 3)))    if ((opt = opt6_find(opts, end, OPTION6_CLIENT_MAC, 3)))
     {      {
         if (opt6_len(opt) - 2 > DHCP_CHADDR_MAX) {
           return 0;
         }
       state->mac_type = opt6_uint(opt, 0, 2);        state->mac_type = opt6_uint(opt, 0, 2);
       state->mac_len = opt6_len(opt) - 2;        state->mac_len = opt6_len(opt) - 2;
       memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);        memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);
Line 213  static int dhcp6_maybe_relay(struct state *state, void Line 232  static int dhcp6_maybe_relay(struct state *state, void
       
   for (opt = opts; opt; opt = opt6_next(opt, end))    for (opt = opts; opt; opt = opt6_next(opt, end))
     {      {
      int o = new_opt6(opt6_type(opt));      if (opt6_ptr(opt, 0) + opt6_len(opt) > end) 
      if (opt6_type(opt) == OPTION6_RELAY_MSG)        return 0;
      
       /* Don't copy MAC address into reply. */
       if (opt6_type(opt) != OPTION6_CLIENT_MAC)
         {          {
          struct in6_addr align;          int o = new_opt6(opt6_type(opt));
          /* the packet data is unaligned, copy to aligned storage */          if (opt6_type(opt) == OPTION6_RELAY_MSG)
          memcpy(&align, inbuff + 2, IN6ADDRSZ);             {
          state->link_address = &align;              struct in6_addr align;
          /* zero is_unicast since that is now known to refer to the               /* the packet data is unaligned, copy to aligned storage */
             relayed packet, not the original sent by the client */              memcpy(&align, inbuff + 2, IN6ADDRSZ); 
          if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))              state->link_address = &align;
            return 0;              /* zero is_unicast since that is now known to refer to the 
                  relayed packet, not the original sent by the client */
               if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
                 return 0;
             }
           else
             put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
           end_opt6(o);
         }          }
       else if (opt6_type(opt) != OPTION6_CLIENT_MAC)  
         put_opt6(opt6_ptr(opt, 0), opt6_len(opt));  
       end_opt6(o);            
     }      }
       
   return 1;    return 1;
Line 246  static int dhcp6_no_relay(struct state *state, int msg Line 272  static int dhcp6_no_relay(struct state *state, int msg
   struct dhcp_context *context_tmp;    struct dhcp_context *context_tmp;
   struct dhcp_mac *mac_opt;    struct dhcp_mac *mac_opt;
   unsigned int ignore = 0;    unsigned int ignore = 0;
 #ifdef OPTION6_PREFIX_CLASS  
   struct prefix_class *p;  
   int dump_all_prefix_classes = 0;  
 #endif  
   
   state->packet_options = inbuff + 4;    state->packet_options = inbuff + 4;
   state->end = inbuff + sz;    state->end = inbuff + sz;
Line 262  static int dhcp6_no_relay(struct state *state, int msg Line 284  static int dhcp6_no_relay(struct state *state, int msg
   state->hostname_auth = 0;    state->hostname_auth = 0;
   state->hostname = NULL;    state->hostname = NULL;
   state->client_hostname = NULL;    state->client_hostname = NULL;
  state->fqdn_flags = 0x01; /* default to send if we recieve no FQDN option */  state->fqdn_flags = 0x01; /* default to send if we receive no FQDN option */
#ifdef OPTION6_PREFIX_CLASS 
  state->send_prefix_class = NULL; 
#endif 
   
   /* set tag with name == interface */    /* set tag with name == interface */
   iface_id.net = state->iface_name;    iface_id.net = state->iface_name;
Line 381  static int dhcp6_no_relay(struct state *state, int msg Line 400  static int dhcp6_no_relay(struct state *state, int msg
       
   /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.    /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
      Otherwise assume the option is an array, and look for a matching element.        Otherwise assume the option is an array, and look for a matching element. 
     If no data given, existance of the option is enough. This code handles      If no data given, existence of the option is enough. This code handles 
      V-I opts too. */       V-I opts too. */
   for (opt_cfg = daemon->dhcp_match6; opt_cfg; opt_cfg = opt_cfg->next)    for (opt_cfg = daemon->dhcp_match6; opt_cfg; opt_cfg = opt_cfg->next)
     {      {
Line 471  static int dhcp6_no_relay(struct state *state, int msg Line 490  static int dhcp6_no_relay(struct state *state, int msg
                         
            if (legal_hostname(daemon->dhcp_buff))             if (legal_hostname(daemon->dhcp_buff))
              {               {
                  struct dhcp_match_name *m;
                  size_t nl = strlen(daemon->dhcp_buff);
                  
                state->client_hostname = daemon->dhcp_buff;                 state->client_hostname = daemon->dhcp_buff;
                  
                if (option_bool(OPT_LOG_OPTS))                 if (option_bool(OPT_LOG_OPTS))
                 my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), state->xid, state->client_hostname);                  my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), state->xid, state->client_hostname);
                
                for (m = daemon->dhcp_name_match; m; m = m->next)
                  {
                    size_t ml = strlen(m->name);
                    char save = 0;
                    
                    if (nl < ml)
                      continue;
                    if (nl > ml)
                      {
                        save = state->client_hostname[ml];
                        state->client_hostname[ml] = 0;
                      }
                    
                    if (hostname_isequal(state->client_hostname, m->name) &&
                        (save == 0 || m->wildcard))
                      {
                        m->netid->next = state->tags;
                        state->tags = m->netid;
                      }
                    
                    if (save != 0)
                      state->client_hostname[ml] = save;
                  }
              }               }
          }           }
     }          }    
       
  if (state->clid)  if (state->clid &&
       (config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len,
                             state->mac, state->mac_len, state->mac_type, NULL, run_tag_if(state->tags))) &&
       have_config(config, CONFIG_NAME))
     {      {
      config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL);      state->hostname = config->hostname;
       state->domain = config->domain;
       state->hostname_auth = 1;
     }
   else if (state->client_hostname)
     {
       state->domain = strip_hostname(state->client_hostname);
               
      if (have_config(config, CONFIG_NAME))      if (strlen(state->client_hostname) != 0)
         {          {
          state->hostname = config->hostname;          state->hostname = state->client_hostname;
          state->domain = config->domain; 
          state->hostname_auth = 1; 
        } 
      else if (state->client_hostname) 
        { 
          state->domain = strip_hostname(state->client_hostname); 
                       
          if (strlen(state->client_hostname) != 0)          if (!config)
             {              {
              state->hostname = state->client_hostname;              /* Search again now we have a hostname. 
              if (!config)                 Only accept configs without CLID here, (it won't match)
                {                 to avoid impersonation by name. */
                  /* Search again now we have a hostname.               struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname, run_tag_if(state->tags));
                     Only accept configs without CLID here, (it won't match)              if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
                     to avoid impersonation by name. */                config = new;
                  struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname); 
                  if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr) 
                    config = new; 
                } 
             }              }
         }          }
     }      }
Line 526  static int dhcp6_no_relay(struct state *state, int msg Line 572  static int dhcp6_no_relay(struct state *state, int msg
       if (have_config(config, CONFIG_DISABLE))        if (have_config(config, CONFIG_DISABLE))
         ignore = 1;          ignore = 1;
     }      }
  else if (state->clid &&
#ifdef OPTION6_PREFIX_CLASS           find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len,
  /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */                       state->mac, state->mac_len, state->mac_type, NULL, run_tag_if(state->tags)))
  if (daemon->prefix_classes && (msg_type == DHCP6SOLICIT || msg_type == DHCP6REQUEST)) 
     {      {
      void *oro;      known_id.net = "known-othernet";
            known_id.next = state->tags;
      if ((oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0)))      state->tags = &known_id;
        for (i = 0; i <  opt6_len(oro) - 1; i += 2)    }
          if (opt6_uint(oro, i, 2) == OPTION6_PREFIX_CLASS)  
            { 
              dump_all_prefix_classes = 1; 
              break; 
            } 
       
      if (msg_type != DHCP6SOLICIT || dump_all_prefix_classes) 
        /* Add the tags associated with prefix classes so we can use the DHCP ranges. 
           Not done for SOLICIT as we add them  one-at-time. */ 
        for (p = daemon->prefix_classes; p ; p = p->next) 
          { 
            p->tag.next = state->tags; 
            state->tags = &p->tag; 
          } 
    }     
#endif 
 
   tagif = run_tag_if(state->tags);    tagif = run_tag_if(state->tags);
       
   /* if all the netids in the ignore list are present, ignore this client */    /* if all the netids in the ignore list are present, ignore this client */
Line 626  static int dhcp6_no_relay(struct state *state, int msg Line 655  static int dhcp6_no_relay(struct state *state, int msg
             int plain_range = 1;              int plain_range = 1;
             u32 lease_time;              u32 lease_time;
             struct dhcp_lease *ltmp;              struct dhcp_lease *ltmp;
            struct in6_addr *req_addr;            struct in6_addr req_addr, addr;
            struct in6_addr addr;            
 
             if (!check_ia(state, opt, &ia_end, &ia_option))              if (!check_ia(state, opt, &ia_end, &ia_option))
               continue;                continue;
                           
Line 636  static int dhcp6_no_relay(struct state *state, int msg Line 664  static int dhcp6_no_relay(struct state *state, int msg
             for (c = state->context; c; c = c->current)              for (c = state->context; c; c = c->current)
               c->flags &= ~CONTEXT_USED;                c->flags &= ~CONTEXT_USED;
   
 #ifdef OPTION6_PREFIX_CLASS  
             if (daemon->prefix_classes && state->ia_type == OPTION6_IA_NA)  
               {  
                 void *prefix_opt;  
                 int prefix_class;  
                   
                 if (dump_all_prefix_classes)  
                   /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */  
                   plain_range = 0;  
                 else   
                   {   
                     if ((prefix_opt = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_PREFIX_CLASS, 2)))  
                       {  
                           
                         prefix_class = opt6_uint(prefix_opt, 0, 2);  
                           
                         for (p = daemon->prefix_classes; p ; p = p->next)  
                           if (p->class == prefix_class)  
                             break;  
                           
                         if (!p)  
                           my_syslog(MS_DHCP | LOG_WARNING, _("unknown prefix-class %d"), prefix_class);  
                         else  
                           {  
                             /* add tag to list, and exclude undecorated dhcp-ranges */  
                             p->tag.next = state->tags;  
                             solicit_tags = run_tag_if(&p->tag);  
                             plain_range = 0;  
                             state->send_prefix_class = p;  
                           }  
                       }  
                     else  
                       {  
                         /* client didn't ask for a prefix class, lets see if we can find one. */  
                         for (p = daemon->prefix_classes; p ; p = p->next)  
                           {  
                             p->tag.next = NULL;  
                             if (match_netid(&p->tag, solicit_tags, 1))  
                               break;  
                           }  
                           
                         if (p)  
                           {  
                             plain_range = 0;  
                             state->send_prefix_class = p;  
                           }  
                       }  
   
                     if (p && option_bool(OPT_LOG_OPTS))  
                       my_syslog(MS_DHCP | LOG_INFO, "%u prefix class %d tag:%s", state->xid, p->class, p->tag.net);   
                   }  
               }  
 #endif  
   
             o = build_ia(state, &t1cntr);              o = build_ia(state, &t1cntr);
             if (address_assigned)              if (address_assigned)
                 address_assigned = 2;                  address_assigned = 2;
   
             for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))              for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
               {                {
                req_addr = opt6_ptr(ia_option, 0);                /* worry about alignment here. */
                 memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
                                                                   
                if ((c = address6_valid(state->context, req_addr, solicit_tags, plain_range)))                if ((c = address6_valid(state->context, &req_addr, solicit_tags, plain_range)))
                   {                    {
                     lease_time = c->lease_time;                      lease_time = c->lease_time;
                     /* If the client asks for an address on the same network as a configured address,                       /* If the client asks for an address on the same network as a configured address, 
                        offer the configured address instead, to make moving to newly-configured                         offer the configured address instead, to make moving to newly-configured
                        addresses automatic. */                         addresses automatic. */
                    if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr))                    if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr, state, now))
                       {                        {
                        req_addr = &addr;                        req_addr = addr;
                         mark_config_used(c, &addr);                          mark_config_used(c, &addr);
                         if (have_config(config, CONFIG_TIME))                          if (have_config(config, CONFIG_TIME))
                           lease_time = config->lease_time;                            lease_time = config->lease_time;
                       }                        }
                    else if (!(c = address6_available(state->context, req_addr, solicit_tags, plain_range)))                    else if (!(c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
                       continue; /* not an address we're allowed */                        continue; /* not an address we're allowed */
                    else if (!check_address(state, req_addr))                    else if (!check_address(state, &req_addr))
                       continue; /* address leased elsewhere */                        continue; /* address leased elsewhere */
                                           
                     /* add address to output packet */                      /* add address to output packet */
#ifdef OPTION6_PREFIX_CLASS                    add_address(state, c, lease_time, ia_option, &min_time, &req_addr, now);
                    if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)                    mark_context_used(state, &req_addr);
                      state->send_prefix_class = prefix_class_from_context(c); 
#endif                     
                    add_address(state, c, lease_time, ia_option, &min_time, req_addr, now); 
                    mark_context_used(state, req_addr); 
                     get_context_tag(state, c);                      get_context_tag(state, c);
                     address_assigned = 1;                      address_assigned = 1;
                   }                    }
Line 732  static int dhcp6_no_relay(struct state *state, int msg Line 703  static int dhcp6_no_relay(struct state *state, int msg
             for (c = state->context; c; c = c->current)               for (c = state->context; c; c = c->current) 
               if (!(c->flags & CONTEXT_CONF_USED) &&                if (!(c->flags & CONTEXT_CONF_USED) &&
                   match_netid(c->filter, solicit_tags, plain_range) &&                    match_netid(c->filter, solicit_tags, plain_range) &&
                  config_valid(config, c, &addr) &&                   config_valid(config, c, &addr, state, now))
                  check_address(state, &addr)) 
                 {                  {
                   mark_config_used(state->context, &addr);                    mark_config_used(state->context, &addr);
                   if (have_config(config, CONFIG_TIME))                    if (have_config(config, CONFIG_TIME))
                     lease_time = config->lease_time;                      lease_time = config->lease_time;
                   else                    else
                     lease_time = c->lease_time;                      lease_time = c->lease_time;
   
                   /* add address to output packet */                    /* add address to output packet */
 #ifdef OPTION6_PREFIX_CLASS  
                   if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)  
                     state->send_prefix_class = prefix_class_from_context(c);  
 #endif  
                   add_address(state, c, lease_time, NULL, &min_time, &addr, now);                    add_address(state, c, lease_time, NULL, &min_time, &addr, now);
                   mark_context_used(state, &addr);                    mark_context_used(state, &addr);
                   get_context_tag(state, c);                    get_context_tag(state, c);
Line 755  static int dhcp6_no_relay(struct state *state, int msg Line 722  static int dhcp6_no_relay(struct state *state, int msg
             ltmp = NULL;              ltmp = NULL;
             while ((ltmp = lease6_find_by_client(ltmp, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state->clid, state->clid_len, state->iaid)))              while ((ltmp = lease6_find_by_client(ltmp, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state->clid, state->clid_len, state->iaid)))
               {                {
                req_addr = &ltmp->addr6;                req_addr = ltmp->addr6;
                if ((c = address6_available(state->context, req_addr, solicit_tags, plain_range)))                if ((c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
                   {                    {
#ifdef OPTION6_PREFIX_CLASS                    add_address(state, c, c->lease_time, NULL, &min_time, &req_addr, now);
                    if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)                    mark_context_used(state, &req_addr);
                      state->send_prefix_class = prefix_class_from_context(c); 
#endif 
                    add_address(state, c, c->lease_time, NULL, &min_time, req_addr, now); 
                    mark_context_used(state, req_addr); 
                     get_context_tag(state, c);                      get_context_tag(state, c);
                     address_assigned = 1;                      address_assigned = 1;
                   }                    }
Line 773  static int dhcp6_no_relay(struct state *state, int msg Line 736  static int dhcp6_no_relay(struct state *state, int msg
             while ((c = address6_allocate(state->context, state->clid, state->clid_len, state->ia_type == OPTION6_IA_TA,              while ((c = address6_allocate(state->context, state->clid, state->clid_len, state->ia_type == OPTION6_IA_TA,
                                           state->iaid, ia_counter, solicit_tags, plain_range, &addr)))                                            state->iaid, ia_counter, solicit_tags, plain_range, &addr)))
               {                {
 #ifdef OPTION6_PREFIX_CLASS  
                 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)  
                   state->send_prefix_class = prefix_class_from_context(c);  
 #endif  
                 add_address(state, c, c->lease_time, NULL, &min_time, &addr, now);                  add_address(state, c, c->lease_time, NULL, &min_time, &addr, now);
                 mark_context_used(state, &addr);                  mark_context_used(state, &addr);
                 get_context_tag(state, c);                  get_context_tag(state, c);
Line 869  static int dhcp6_no_relay(struct state *state, int msg Line 828  static int dhcp6_no_relay(struct state *state, int msg
   
              if (!ia_option)               if (!ia_option)
                {                 {
                 /* If we get a request with a IA_*A without addresses, treat it exactly like                 /* If we get a request with an IA_*A without addresses, treat it exactly like
                     a SOLICT with rapid commit set. */                      a SOLICT with rapid commit set. */
                  save_counter(start);                   save_counter(start);
                  goto request_no_address;                    goto request_no_address; 
Line 879  static int dhcp6_no_relay(struct state *state, int msg Line 838  static int dhcp6_no_relay(struct state *state, int msg
                               
             for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))              for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
               {                {
                struct in6_addr *req_addr = opt6_ptr(ia_option, 0);                struct in6_addr req_addr;
                 struct dhcp_context *dynamic, *c;                  struct dhcp_context *dynamic, *c;
                 unsigned int lease_time;                  unsigned int lease_time;
                 struct in6_addr addr;  
                 int config_ok = 0;                  int config_ok = 0;
   
                   /* align. */
                   memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
                                   
                if ((c = address6_valid(state->context, req_addr, tagif, 1)))                if ((c = address6_valid(state->context, &req_addr, tagif, 1)))
                  config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr);                  config_ok = (config_implies(config, c, &req_addr) != NULL);
                                   
                if ((dynamic = address6_available(state->context, req_addr, tagif, 1)) || c)                if ((dynamic = address6_available(state->context, &req_addr, tagif, 1)) || c)
                   {                    {
                     if (!dynamic && !config_ok)                      if (!dynamic && !config_ok)
                       {                        {
Line 898  static int dhcp6_no_relay(struct state *state, int msg Line 859  static int dhcp6_no_relay(struct state *state, int msg
                         put_opt6_string(_("address unavailable"));                          put_opt6_string(_("address unavailable"));
                         end_opt6(o1);                          end_opt6(o1);
                       }                        }
                    else if (!check_address(state, req_addr))                    else if (!check_address(state, &req_addr))
                       {                        {
                         /* Address leased to another DUID/IAID */                          /* Address leased to another DUID/IAID */
                         o1 = new_opt6(OPTION6_STATUS_CODE);                          o1 = new_opt6(OPTION6_STATUS_CODE);
Line 916  static int dhcp6_no_relay(struct state *state, int msg Line 877  static int dhcp6_no_relay(struct state *state, int msg
                         if (config_ok && have_config(config, CONFIG_TIME))                          if (config_ok && have_config(config, CONFIG_TIME))
                           lease_time = config->lease_time;                            lease_time = config->lease_time;
   
#ifdef OPTION6_PREFIX_CLASS                        add_address(state, dynamic, lease_time, ia_option, &min_time, &req_addr, now);
                        if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA) 
                          state->send_prefix_class = prefix_class_from_context(c); 
#endif 
                        add_address(state, dynamic, lease_time, ia_option, &min_time, req_addr, now); 
                         get_context_tag(state, dynamic);                          get_context_tag(state, dynamic);
                         address_assigned = 1;                          address_assigned = 1;
                       }                        }
Line 983  static int dhcp6_no_relay(struct state *state, int msg Line 940  static int dhcp6_no_relay(struct state *state, int msg
             for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))              for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
               {                {
                 struct dhcp_lease *lease = NULL;                  struct dhcp_lease *lease = NULL;
                struct in6_addr *req_addr = opt6_ptr(ia_option, 0);                struct in6_addr req_addr;
                 unsigned int preferred_time =  opt6_uint(ia_option, 16, 4);                  unsigned int preferred_time =  opt6_uint(ia_option, 16, 4);
                 unsigned int valid_time =  opt6_uint(ia_option, 20, 4);                  unsigned int valid_time =  opt6_uint(ia_option, 20, 4);
                 char *message = NULL;                  char *message = NULL;
                 struct dhcp_context *this_context;                  struct dhcp_context *this_context;
   
                   memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ); 
                                   
                 if (!(lease = lease6_find(state->clid, state->clid_len,                  if (!(lease = lease6_find(state->clid, state->clid_len,
                                           state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,                                             state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, 
                                          state->iaid, req_addr)))                                          state->iaid, &req_addr)))
                   {                    {
                     /* If the server cannot find a client entry for the IA the server                      /* If the server cannot find a client entry for the IA the server
                        returns the IA containing no addresses with a Status Code option set                         returns the IA containing no addresses with a Status Code option set
Line 999  static int dhcp6_no_relay(struct state *state, int msg Line 958  static int dhcp6_no_relay(struct state *state, int msg
                     save_counter(iacntr);                      save_counter(iacntr);
                     t1cntr = 0;                      t1cntr = 0;
                                           
                    log6_packet(state, "DHCPREPLY", req_addr, _("lease not found"));                    log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found"));
                                           
                     o1 = new_opt6(OPTION6_STATUS_CODE);                      o1 = new_opt6(OPTION6_STATUS_CODE);
                     put_opt6_short(DHCP6NOBINDING);                      put_opt6_short(DHCP6NOBINDING);
Line 1011  static int dhcp6_no_relay(struct state *state, int msg Line 970  static int dhcp6_no_relay(struct state *state, int msg
                   }                    }
                                   
                                   
                if ((this_context = address6_available(state->context, req_addr, tagif, 1)) ||                if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||
                    (this_context = address6_valid(state->context, req_addr, tagif, 1)))                    (this_context = address6_valid(state->context, &req_addr, tagif, 1)))
                   {                    {
                     struct in6_addr addr;  
                     unsigned int lease_time;                      unsigned int lease_time;
   
                     get_context_tag(state, this_context);                      get_context_tag(state, this_context);
                                           
                    if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME))                    if (config_implies(config, this_context, &req_addr) && have_config(config, CONFIG_TIME))
                       lease_time = config->lease_time;                        lease_time = config->lease_time;
                     else                       else 
                       lease_time = this_context->lease_time;                        lease_time = this_context->lease_time;
Line 1032  static int dhcp6_no_relay(struct state *state, int msg Line 990  static int dhcp6_no_relay(struct state *state, int msg
                       lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);                        lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
                     if (state->ia_type == OPTION6_IA_NA && state->hostname)                      if (state->ia_type == OPTION6_IA_NA && state->hostname)
                       {                        {
                        char *addr_domain = get_domain6(req_addr);                        char *addr_domain = get_domain6(&req_addr);
                         if (!state->send_domain)                          if (!state->send_domain)
                           state->send_domain = addr_domain;                            state->send_domain = addr_domain;
                         lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);                           lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain); 
Line 1050  static int dhcp6_no_relay(struct state *state, int msg Line 1008  static int dhcp6_no_relay(struct state *state, int msg
                   }                     } 
   
                 if (message && (message != state->hostname))                  if (message && (message != state->hostname))
                  log6_packet(state, "DHCPREPLY", req_addr, message);                       log6_packet(state, "DHCPREPLY", &req_addr, message);     
                 else                  else
                  log6_quiet(state, "DHCPREPLY", req_addr, message);                  log6_quiet(state, "DHCPREPLY", &req_addr, message);
                   
                 o1 =  new_opt6(OPTION6_IAADDR);                  o1 =  new_opt6(OPTION6_IAADDR);
                put_opt6(req_addr, sizeof(*req_addr));                put_opt6(&req_addr, sizeof(req_addr));
                 put_opt6_long(preferred_time);                  put_opt6_long(preferred_time);
                 put_opt6_long(valid_time);                  put_opt6_long(valid_time);
                 end_opt6(o1);                  end_opt6(o1);
Line 1087  static int dhcp6_no_relay(struct state *state, int msg Line 1045  static int dhcp6_no_relay(struct state *state, int msg
                  ia_option;                   ia_option;
                  ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))                   ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
               {                {
                struct in6_addr *req_addr = opt6_ptr(ia_option, 0);                struct in6_addr req_addr;
 
                 /* alignment */
                 memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
                                   
                if (!address6_valid(state->context, req_addr, tagif, 1))                if (!address6_valid(state->context, &req_addr, tagif, 1))
                   {                    {
                     o1 = new_opt6(OPTION6_STATUS_CODE);                      o1 = new_opt6(OPTION6_STATUS_CODE);
                     put_opt6_short(DHCP6NOTONLINK);                      put_opt6_short(DHCP6NOTONLINK);
                     put_opt6_string(_("confirm failed"));                      put_opt6_string(_("confirm failed"));
                     end_opt6(o1);                      end_opt6(o1);
                       log6_quiet(state, "DHCPREPLY", &req_addr, _("confirm failed"));
                     return 1;                      return 1;
                   }                    }
   
                 good_addr = 1;                  good_addr = 1;
                log6_quiet(state, "DHCPREPLY", req_addr, state->hostname);                log6_quiet(state, "DHCPREPLY", &req_addr, state->hostname);
               }                }
           }                  }      
                   
Line 1158  static int dhcp6_no_relay(struct state *state, int msg Line 1120  static int dhcp6_no_relay(struct state *state, int msg
                  ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))                    ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) 
               {                {
                 struct dhcp_lease *lease;                  struct dhcp_lease *lease;
                                struct in6_addr addr;
 
                 /* align */
                 memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
                 if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,                  if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
                                         state->iaid, opt6_ptr(ia_option, 0))))                                         state->iaid, &addr)))
                   lease_prune(lease, now);                    lease_prune(lease, now);
                 else                  else
                   {                    {
Line 1177  static int dhcp6_no_relay(struct state *state, int msg Line 1142  static int dhcp6_no_relay(struct state *state, int msg
                       }                        }
                                           
                     o1 = new_opt6(OPTION6_IAADDR);                      o1 = new_opt6(OPTION6_IAADDR);
                    put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);                    put_opt6(&addr, IN6ADDRSZ);
                     put_opt6_long(0);                      put_opt6_long(0);
                     put_opt6_long(0);                      put_opt6_long(0);
                     end_opt6(o1);                      end_opt6(o1);
Line 1220  static int dhcp6_no_relay(struct state *state, int msg Line 1185  static int dhcp6_no_relay(struct state *state, int msg
                  ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))                    ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) 
               {                {
                 struct dhcp_lease *lease;                  struct dhcp_lease *lease;
                struct in6_addr *addrp = opt6_ptr(ia_option, 0);                struct in6_addr addr;
                 struct addrlist *addr_list;
                 
                 /* align */
                 memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
   
                if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, addrp))                if ((addr_list = config_implies(config, state->context, &addr)))
                   {                    {
                     prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);                      prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
                    inet_ntop(AF_INET6, addrp, daemon->addrbuff, ADDRSTRLEN);                    inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
                     my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),                       my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"), 
                               daemon->addrbuff, daemon->dhcp_buff3);                                daemon->addrbuff, daemon->dhcp_buff3);
                    config->flags |= CONFIG_DECLINED;                    addr_list->flags |= ADDRLIST_DECLINED;
                    config->decline_time = now;                    addr_list->decline_time = now;
                   }                    }
                 else                  else
                   /* make sure this host gets a different address next time. */                    /* make sure this host gets a different address next time. */
Line 1237  static int dhcp6_no_relay(struct state *state, int msg Line 1206  static int dhcp6_no_relay(struct state *state, int msg
                     context_tmp->addr_epoch++;                      context_tmp->addr_epoch++;
                                   
                 if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,                  if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
                                         state->iaid, opt6_ptr(ia_option, 0))))                                         state->iaid, &addr)))
                   lease_prune(lease, now);                    lease_prune(lease, now);
                 else                  else
                   {                    {
Line 1254  static int dhcp6_no_relay(struct state *state, int msg Line 1223  static int dhcp6_no_relay(struct state *state, int msg
                       }                        }
                                           
                     o1 = new_opt6(OPTION6_IAADDR);                      o1 = new_opt6(OPTION6_IAADDR);
                    put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);                    put_opt6(&addr, IN6ADDRSZ);
                     put_opt6_long(0);                      put_opt6_long(0);
                     put_opt6_long(0);                      put_opt6_long(0);
                     end_opt6(o1);                      end_opt6(o1);
Line 1273  static int dhcp6_no_relay(struct state *state, int msg Line 1242  static int dhcp6_no_relay(struct state *state, int msg
                           
           }            }
   
        /* We must anwser with 'success' in global section anyway */        /* We must answer with 'success' in global section anyway */
         o1 = new_opt6(OPTION6_STATUS_CODE);          o1 = new_opt6(OPTION6_STATUS_CODE);
         put_opt6_short(DHCP6SUCCESS);          put_opt6_short(DHCP6SUCCESS);
         put_opt6_string(_("success"));          put_opt6_string(_("success"));
Line 1342  static struct dhcp_netid *add_options(struct state *st Line 1311  static struct dhcp_netid *add_options(struct state *st
                                       
               for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)                for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
                 {                  {
                     struct in6_addr *p = NULL;
   
                   if (IN6_IS_ADDR_UNSPECIFIED(a))                    if (IN6_IS_ADDR_UNSPECIFIED(a))
                     {                      {
                       if (!add_local_addrs(state->context))                        if (!add_local_addrs(state->context))
                        put_opt6(state->fallback, IN6ADDRSZ);                        p = state->fallback;
                     }                      }
                   else if (IN6_IS_ADDR_ULA_ZERO(a))                    else if (IN6_IS_ADDR_ULA_ZERO(a))
                     {                      {
                       if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr))                        if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr))
                        put_opt6(state->ula_addr, IN6ADDRSZ);                        p = state->ula_addr;
                     }                      }
                   else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))                    else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
                     {                      {
                       if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr))                        if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr))
                        put_opt6(state->ll_addr, IN6ADDRSZ);                        p = state->ll_addr;
                     }                      }
                   else                    else
                    put_opt6(a, IN6ADDRSZ);                    p = a;
 
                   if (!p)
                     continue;
                   else if (opt_cfg->opt == OPTION6_NTP_SERVER)
                     {
                       if (IN6_IS_ADDR_MULTICAST(p))
                         o1 = new_opt6(NTP_SUBOPTION_MC_ADDR);
                       else
                         o1 = new_opt6(NTP_SUBOPTION_SRV_ADDR);
                       put_opt6(p, IN6ADDRSZ);
                       end_opt6(o1);
                     }
                   else
                     put_opt6(p, IN6ADDRSZ);
                 }                  }
   
               end_opt6(o);                end_opt6(o);
Line 1387  static struct dhcp_netid *add_options(struct state *st Line 1372  static struct dhcp_netid *add_options(struct state *st
       unsigned int lease_time = 0xffffffff;        unsigned int lease_time = 0xffffffff;
               
       /* Find the smallest lease tie of all contexts,        /* Find the smallest lease tie of all contexts,
         subjext to the RFC-4242 stipulation that this must not          subject to the RFC-4242 stipulation that this must not 
          be less than 600. */           be less than 600. */
       for (c = state->context; c; c = c->next)        for (c = state->context; c; c = c->next)
         if (c->lease_time < lease_time)          if (c->lease_time < lease_time)
Line 1472  static struct dhcp_netid *add_options(struct state *st Line 1457  static struct dhcp_netid *add_options(struct state *st
       if ((p = expand(len + 2)))        if ((p = expand(len + 2)))
         {          {
           *(p++) = state->fqdn_flags;            *(p++) = state->fqdn_flags;
          p = do_rfc1035_name(p, state->hostname);          p = do_rfc1035_name(p, state->hostname, NULL);
           if (state->send_domain)            if (state->send_domain)
             {              {
              p = do_rfc1035_name(p, state->send_domain);              p = do_rfc1035_name(p, state->send_domain, NULL);
               *p = 0;                *p = 0;
             }              }
         }          }
Line 1552  static void get_context_tag(struct state *state, struc Line 1537  static void get_context_tag(struct state *state, struc
     }      }
 }   } 
   
 #ifdef OPTION6_PREFIX_CLASS  
 static struct prefix_class *prefix_class_from_context(struct dhcp_context *context)  
 {  
   struct prefix_class *p;  
   struct dhcp_netid *t;  
     
   for (p = daemon->prefix_classes; p ; p = p->next)  
     for (t = context->filter; t; t = t->next)  
       if (strcmp(p->tag.net, t->net) == 0)  
         return p;  
     
  return NULL;  
 }  
 #endif  
   
 static int check_ia(struct state *state, void *opt, void **endp, void **ia_option)  static int check_ia(struct state *state, void *opt, void **endp, void **ia_option)
 {  {
   state->ia_type = opt6_type(opt);    state->ia_type = opt6_type(opt);
Line 1612  static void end_ia(int t1cntr, unsigned int min_time,  Line 1582  static void end_ia(int t1cntr, unsigned int min_time, 
 {  {
   if (t1cntr != 0)    if (t1cntr != 0)
     {      {
      /* go back an fill in fields in IA_NA option */      /* go back and fill in fields in IA_NA option */
       int sav = save_counter(t1cntr);        int sav = save_counter(t1cntr);
       unsigned int t1, t2, fuzz = 0;        unsigned int t1, t2, fuzz = 0;
   
Line 1651  static void add_address(struct state *state, struct dh Line 1621  static void add_address(struct state *state, struct dh
   put_opt6(addr, sizeof(*addr));    put_opt6(addr, sizeof(*addr));
   put_opt6_long(preferred_time);    put_opt6_long(preferred_time);
   put_opt6_long(valid_time);                    put_opt6_long(valid_time);                
     
 #ifdef OPTION6_PREFIX_CLASS  
   if (state->send_prefix_class)  
     {  
       int o1 = new_opt6(OPTION6_PREFIX_CLASS);  
       put_opt6_short(state->send_prefix_class->class);  
       end_opt6(o1);  
     }  
 #endif  
   
   end_opt6(o);    end_opt6(o);
       
   if (state->lease_allocate)    if (state->lease_allocate)
Line 1696  static void mark_context_used(struct state *state, str Line 1656  static void mark_context_used(struct state *state, str
   struct dhcp_context *context;    struct dhcp_context *context;
   
   /* Mark that we have an address for this prefix. */    /* Mark that we have an address for this prefix. */
 #ifdef OPTION6_PREFIX_CLASS  
   for (context = state->context; context; context = context->current)    for (context = state->context; context; context = context->current)
     if (is_same_net6(addr, &context->start6, context->prefix) &&  
         (!state->send_prefix_class || state->send_prefix_class == prefix_class_from_context(context)))  
       context->flags |= CONTEXT_USED;  
 #else  
   for (context = state->context; context; context = context->current)  
     if (is_same_net6(addr, &context->start6, context->prefix))      if (is_same_net6(addr, &context->start6, context->prefix))
       context->flags |= CONTEXT_USED;        context->flags |= CONTEXT_USED;
 #endif  
 }  }
   
 static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr)  static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr)
Line 1732  static int check_address(struct state *state, struct i Line 1685  static int check_address(struct state *state, struct i
 }  }
   
   
   /* return true of *addr could have been generated from config. */
   static struct addrlist *config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr)
   {
     int prefix;
     struct in6_addr wild_addr;
     struct addrlist *addr_list;
     
     if (!config || !(config->flags & CONFIG_ADDR6))
       return NULL;
     
     for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
       {
         prefix = (addr_list->flags & ADDRLIST_PREFIX) ? addr_list->prefixlen : 128;
         wild_addr = addr_list->addr.addr6;
         
         if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
           {
             wild_addr = context->start6;
             setaddr6part(&wild_addr, addr6part(&addr_list->addr.addr6));
           }
         else if (!is_same_net6(&context->start6, addr, context->prefix))
           continue;
         
         if (is_same_net6(&wild_addr, addr, prefix))
           return addr_list;
       }
     
     return NULL;
   }
   
   static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state, time_t now)
   {
     u64 addrpart, i, addresses;
     struct addrlist *addr_list;
     
     if (!config || !(config->flags & CONFIG_ADDR6))
       return 0;
   
     for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
       if (!(addr_list->flags & ADDRLIST_DECLINED) ||
           difftime(now, addr_list->decline_time) >= (float)DECLINE_BACKOFF)
         {
           addrpart = addr6part(&addr_list->addr.addr6);
           addresses = 1;
           
           if (addr_list->flags & ADDRLIST_PREFIX)
             addresses = (u64)1<<(128-addr_list->prefixlen);
           
           if ((addr_list->flags & ADDRLIST_WILDCARD))
             {
               if (context->prefix != 64)
                 continue;
               
               *addr = context->start6;
             }
           else if (is_same_net6(&context->start6, &addr_list->addr.addr6, context->prefix))
             *addr = addr_list->addr.addr6;
           else
             continue;
           
           for (i = 0 ; i < addresses; i++)
             {
               setaddr6part(addr, addrpart+i);
               
               if (check_address(state, addr))
                 return 1;
             }
         }
     
     return 0;
   }
   
 /* Calculate valid and preferred times to send in leases/renewals.   /* Calculate valid and preferred times to send in leases/renewals. 
   
    Inputs are:     Inputs are:
Line 1922  static void log6_opts(int nest, unsigned int xid, void Line 1947  static void log6_opts(int nest, unsigned int xid, void
         }          }
       else if (type == OPTION6_IAADDR)        else if (type == OPTION6_IAADDR)
         {          {
          inet_ntop(AF_INET6, opt6_ptr(opt, 0), daemon->addrbuff, ADDRSTRLEN);          struct in6_addr addr;
 
           /* align */
           memcpy(&addr, opt6_ptr(opt, 0), IN6ADDRSZ);
           inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
           sprintf(daemon->namebuff, "%s PL=%u VL=%u",             sprintf(daemon->namebuff, "%s PL=%u VL=%u", 
                   daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));                    daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
           optname = "iaaddr";            optname = "iaaddr";
           ia_options = opt6_ptr(opt, 24);            ia_options = opt6_ptr(opt, 24);
         }          }
 #ifdef OPTION6_PREFIX_CLASS  
       else if (type == OPTION6_PREFIX_CLASS)  
         {  
           optname = "prefix-class";  
           sprintf(daemon->namebuff, "class=%u", opt6_uint(opt, 0, 2));  
         }  
 #endif  
       else if (type == OPTION6_STATUS_CODE)        else if (type == OPTION6_STATUS_CODE)
         {          {
           int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));            int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
Line 1975  static void log6_packet(struct state *state, char *typ Line 1997  static void log6_packet(struct state *state, char *typ
   
   if (addr)    if (addr)
     {      {
      inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, 255);      inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, DHCP_BUFF_SZ - 1);
       strcat(daemon->dhcp_buff2, " ");        strcat(daemon->dhcp_buff2, " ");
     }      }
   else    else
Line 2059  void relay_upstream6(struct dhcp_relay *relay, ssize_t Line 2081  void relay_upstream6(struct dhcp_relay *relay, ssize_t
 {  {
   /* ->local is same value for all relays on ->current chain */    /* ->local is same value for all relays on ->current chain */
       
  struct all_addr from;  union all_addr from;
   unsigned char *header;    unsigned char *header;
   unsigned char *inbuff = daemon->dhcp_packet.iov_base;    unsigned char *inbuff = daemon->dhcp_packet.iov_base;
   int msg_type = *inbuff;    int msg_type = *inbuff;
Line 2072  void relay_upstream6(struct dhcp_relay *relay, ssize_t Line 2094  void relay_upstream6(struct dhcp_relay *relay, ssize_t
   get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);    get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);
   
   /* source address == relay address */    /* source address == relay address */
  from.addr.addr6 = relay->local.addr.addr6;  from.addr6 = relay->local.addr6;
           
   /* Get hop count from nested relayed message */     /* Get hop count from nested relayed message */ 
   if (msg_type == DHCP6RELAYFORW)    if (msg_type == DHCP6RELAYFORW)
Line 2084  void relay_upstream6(struct dhcp_relay *relay, ssize_t Line 2106  void relay_upstream6(struct dhcp_relay *relay, ssize_t
   if (hopcount > 32)    if (hopcount > 32)
     return;      return;
   
  save_counter(0);  reset_counter();
   
   if ((header = put_opt6(NULL, 34)))    if ((header = put_opt6(NULL, 34)))
     {      {
Line 2092  void relay_upstream6(struct dhcp_relay *relay, ssize_t Line 2114  void relay_upstream6(struct dhcp_relay *relay, ssize_t
   
       header[0] = DHCP6RELAYFORW;        header[0] = DHCP6RELAYFORW;
       header[1] = hopcount;        header[1] = hopcount;
      memcpy(&header[2],  &relay->local.addr.addr6, IN6ADDRSZ);      memcpy(&header[2],  &relay->local.addr6, IN6ADDRSZ);
       memcpy(&header[18], peer_address, IN6ADDRSZ);        memcpy(&header[18], peer_address, IN6ADDRSZ);
     
       /* RFC-6939 */        /* RFC-6939 */
Line 2113  void relay_upstream6(struct dhcp_relay *relay, ssize_t Line 2135  void relay_upstream6(struct dhcp_relay *relay, ssize_t
           union mysockaddr to;            union mysockaddr to;
                       
           to.sa.sa_family = AF_INET6;            to.sa.sa_family = AF_INET6;
          to.in6.sin6_addr = relay->server.addr.addr6;          to.in6.sin6_addr = relay->server.addr6;
           to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);            to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
           to.in6.sin6_flowinfo = 0;            to.in6.sin6_flowinfo = 0;
           to.in6.sin6_scope_id = 0;            to.in6.sin6_scope_id = 0;
   
          if (IN6_ARE_ADDR_EQUAL(&relay->server.addr.addr6, &multicast))          if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast))
             {              {
               int multicast_iface;                int multicast_iface;
               if (!relay->interface || strchr(relay->interface, '*') ||                if (!relay->interface || strchr(relay->interface, '*') ||
Line 2127  void relay_upstream6(struct dhcp_relay *relay, ssize_t Line 2149  void relay_upstream6(struct dhcp_relay *relay, ssize_t
                 my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));                  my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
             }              }
                                   
          send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(0), &to, &from, 0);          send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);
                       
           if (option_bool(OPT_LOG_OPTS))            if (option_bool(OPT_LOG_OPTS))
             {              {
Line 2157  unsigned short relay_reply6(struct sockaddr_in6 *peer, Line 2179  unsigned short relay_reply6(struct sockaddr_in6 *peer,
   memcpy(&link, &inbuff[2], IN6ADDRSZ);     memcpy(&link, &inbuff[2], IN6ADDRSZ); 
       
   for (relay = daemon->relay6; relay; relay = relay->next)    for (relay = daemon->relay6; relay; relay = relay->next)
    if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr.addr6) &&    if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr6) &&
         (!relay->interface || wildcard_match(relay->interface, arrival_interface)))          (!relay->interface || wildcard_match(relay->interface, arrival_interface)))
       break;        break;
               
  save_counter(0);  reset_counter();
   
   if (relay)    if (relay)
     {      {

Removed from v.1.1.1.3  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>