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

version 1.1.1.2, 2014/06/15 16:31:38 version 1.1.1.4, 2021/03/17 00:56:46
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2014 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 130  static int dhcp6_maybe_relay(struct state *state, void Line 126  static int dhcp6_maybe_relay(struct state *state, void
       MAC address from the local ND cache. */        MAC address from the local ND cache. */
               
       if (!state->link_address)        if (!state->link_address)
        get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type);        get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type, now);
       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 313  static int dhcp6_no_relay(struct state *state, int msg Line 332  static int dhcp6_no_relay(struct state *state, int msg
   else if (msg_type != DHCP6IREQ)    else if (msg_type != DHCP6IREQ)
     return 0;      return 0;
   
  /* server-id must match except for SOLICIT and CONFIRM messages */  /* server-id must match except for SOLICIT, CONFIRM and REBIND messages */
  if (msg_type != DHCP6SOLICIT && msg_type != DHCP6CONFIRM && msg_type != DHCP6IREQ &&  if (msg_type != DHCP6SOLICIT && msg_type != DHCP6CONFIRM && msg_type != DHCP6IREQ && msg_type != DHCP6REBIND &&
       (!(opt = opt6_find(state->packet_options, state->end, OPTION6_SERVER_ID, 1)) ||        (!(opt = opt6_find(state->packet_options, state->end, OPTION6_SERVER_ID, 1)) ||
        opt6_len(opt) != daemon->duid_len ||         opt6_len(opt) != daemon->duid_len ||
        memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))         memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
Line 328  static int dhcp6_no_relay(struct state *state, int msg Line 347  static int dhcp6_no_relay(struct state *state, int msg
       (msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))        (msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
           
     {        {  
         *outmsgtypep = DHCP6REPLY;
       o1 = new_opt6(OPTION6_STATUS_CODE);        o1 = new_opt6(OPTION6_STATUS_CODE);
       put_opt6_short(DHCP6USEMULTI);        put_opt6_short(DHCP6USEMULTI);
       put_opt6_string("Use multicast");        put_opt6_string("Use multicast");
Line 380  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 470  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 525  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 625  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 635  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)
                   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 729  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 752  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 770  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);
                 address_assigned = 1;                  address_assigned = 1;
               }                }
                           
               if (address_assigned != 1)
                 {
                   /* If the server will not assign any addresses to any IAs in a
                      subsequent Request from the client, the server MUST send an Advertise
                      message to the client that doesn't include any IA options. */
                   if (!state->lease_allocate)
                     {
                       save_counter(o);
                       continue;
                     }
                   
                   /* If the server cannot assign any addresses to an IA in the message
                      from the client, the server MUST include the IA in the Reply message
                      with no addresses in the IA and a Status Code option in the IA
                      containing status code NoAddrsAvail. */
                   o1 = new_opt6(OPTION6_STATUS_CODE);
                   put_opt6_short(DHCP6NOADDRS);
                   put_opt6_string(_("address unavailable"));
                   end_opt6(o1);
                 }
               
             end_ia(t1cntr, min_time, 0);              end_ia(t1cntr, min_time, 0);
             end_opt6(o);                      end_opt6(o);        
           }            }
Line 805  static int dhcp6_no_relay(struct state *state, int msg Line 788  static int dhcp6_no_relay(struct state *state, int msg
             put_opt6_short(DHCP6NOADDRS);              put_opt6_short(DHCP6NOADDRS);
             put_opt6_string(_("no addresses available"));              put_opt6_string(_("no addresses available"));
             end_opt6(o1);              end_opt6(o1);
            log6_packet(state, "DHCPADVERTISE", NULL, _("no addresses available"));
             /* Some clients will ask repeatedly when we're not giving
                out addresses because we're in stateless mode. Avoid spamming
                the log in that case. */
             for (c = state->context; c; c = c->current)
               if (!(c->flags & CONTEXT_RA_STATELESS))
                 {
                   log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, _("no addresses available"));
                   break;
                 }
           }            }
   
         break;          break;
Line 836  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 846  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)
                       {                        {
                         /* Static range, not configured. */                          /* Static range, not configured. */
                         o1 = new_opt6(OPTION6_STATUS_CODE);                          o1 = new_opt6(OPTION6_STATUS_CODE);
                        put_opt6_short(DHCP6UNSPEC);                        put_opt6_short(DHCP6NOADDRS);
                         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 883  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 950  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 966  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 978  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 999  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 1014  static int dhcp6_no_relay(struct state *state, int msg Line 1005  static int dhcp6_no_relay(struct state *state, int msg
                   {                    {
                     preferred_time = valid_time = 0;                      preferred_time = valid_time = 0;
                     message = _("address invalid");                      message = _("address invalid");
                  }                  } 
   
                if (message)                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 1039  static int dhcp6_no_relay(struct state *state, int msg Line 1030  static int dhcp6_no_relay(struct state *state, int msg
               
     case DHCP6CONFIRM:      case DHCP6CONFIRM:
       {        {
           int good_addr = 0;
   
         /* set reply message type */          /* set reply message type */
         *outmsgtypep = DHCP6REPLY;          *outmsgtypep = DHCP6REPLY;
                   
Line 1052  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_available(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;
                   }                    }
   
                log6_quiet(state, "DHCPREPLY", req_addr, state->hostname);                good_addr = 1;
                 log6_quiet(state, "DHCPREPLY", &req_addr, state->hostname);
               }                }
           }                  }      
           
           /* No addresses, no reply: RFC 3315 18.2.2 */
           if (!good_addr)
             return 0;
   
         o1 = new_opt6(OPTION6_STATUS_CODE);          o1 = new_opt6(OPTION6_STATUS_CODE);
         put_opt6_short(DHCP6SUCCESS );          put_opt6_short(DHCP6SUCCESS );
Line 1118  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 1137  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 1180  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 1197  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 1214  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 1232  static int dhcp6_no_relay(struct state *state, int msg Line 1241  static int dhcp6_no_relay(struct state *state, int msg
               }                }
                           
           }            }
   
           /* We must answer with 'success' in global section anyway */
           o1 = new_opt6(OPTION6_STATUS_CODE);
           put_opt6_short(DHCP6SUCCESS);
           put_opt6_string(_("success"));
           end_opt6(o1);
         break;          break;
       }        }
   
Line 1274  static struct dhcp_netid *add_options(struct state *st Line 1289  static struct dhcp_netid *add_options(struct state *st
               
       if (opt_cfg->opt == OPTION6_REFRESH_TIME)        if (opt_cfg->opt == OPTION6_REFRESH_TIME)
         done_refresh = 1;          done_refresh = 1;
          
         if (opt_cfg->opt == OPTION6_DNS_SERVER)
           done_dns = 1;
               
       if (opt_cfg->flags & DHOPT_ADDR6)        if (opt_cfg->flags & DHOPT_ADDR6)
         {          {
           int len, j;            int len, j;
           struct in6_addr *a;            struct in6_addr *a;
                       
           if (opt_cfg->opt == OPTION6_DNS_SERVER)  
             done_dns = 1;  
             
           for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, j = 0;             for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, j = 0; 
                j < opt_cfg->len; j += IN6ADDRSZ, a++)                 j < opt_cfg->len; j += IN6ADDRSZ, a++)
             if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||              if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
Line 1296  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 1341  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 1426  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 1506  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 1566  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 1605  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 1650  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 1686  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 1876  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 1929  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 2008  static unsigned int opt6_uint(unsigned char *opt, int  Line 2076  static unsigned int opt6_uint(unsigned char *opt, int 
   return ret;    return ret;
 }   } 
   
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id)void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, 
                      struct in6_addr *peer_address, u32 scope_id, time_t now)
 {  {
   /* ->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 2022  void relay_upstream6(struct dhcp_relay *relay, ssize_t Line 2091  void relay_upstream6(struct dhcp_relay *relay, ssize_t
   unsigned char mac[DHCP_CHADDR_MAX];    unsigned char mac[DHCP_CHADDR_MAX];
   
   inet_pton(AF_INET6, ALL_SERVERS, &multicast);    inet_pton(AF_INET6, ALL_SERVERS, &multicast);
  get_client_mac(peer_address, scope_id, mac, &maclen, &mactype);  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 2037  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 2045  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 2066  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 2080  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 2110  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.2  
changed lines
  Added in v.1.1.1.4


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