Diff for /embedaddon/dnsmasq/src/dhcp6.c between versions 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2014/06/15 16:31:38 version 1.1.1.3, 2016/11/02 09:57:01
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley/* dnsmasq is Copyright (c) 2000-2016 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 27  struct iface_param { Line 27  struct iface_param {
   int ind, addr_match;    int ind, addr_match;
 };  };
   
 struct mac_param {  
   struct in6_addr *target;  
   unsigned char *mac;  
   unsigned int maclen;  
 };  
   
   
 static int complete_context6(struct in6_addr *local,  int prefix,  static int complete_context6(struct in6_addr *local,  int prefix,
                              int scope, int if_index, int flags,                                int scope, int if_index, int flags, 
                              unsigned int preferred, unsigned int valid, void *vparam);                               unsigned int preferred, unsigned int valid, void *vparam);
 static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv);  
 static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);   static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm); 
   
 void dhcp6_init(void)  void dhcp6_init(void)
Line 144  void dhcp6_packet(time_t now) Line 137  void dhcp6_packet(time_t now)
   
   if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0)    if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0)
     {      {
         struct dhcp_bridge *bridge, *alias;
   
       for (tmp = daemon->if_except; tmp; tmp = tmp->next)        for (tmp = daemon->if_except; tmp; tmp = tmp->next)
         if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))          if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
           return;            return;
Line 160  void dhcp6_packet(time_t now) Line 155  void dhcp6_packet(time_t now)
       memset(&parm.fallback, 0, IN6ADDRSZ);        memset(&parm.fallback, 0, IN6ADDRSZ);
       memset(&parm.ll_addr, 0, IN6ADDRSZ);        memset(&parm.ll_addr, 0, IN6ADDRSZ);
       memset(&parm.ula_addr, 0, IN6ADDRSZ);        memset(&parm.ula_addr, 0, IN6ADDRSZ);
   
         /* If the interface on which the DHCPv6 request was received is
            an alias of some other interface (as specified by the
            --bridge-interface option), change parm.ind so that we look
            for DHCPv6 contexts associated with the aliased interface
            instead of with the aliasing one. */
         for (bridge = daemon->bridges; bridge; bridge = bridge->next)
           {
             for (alias = bridge->alias; alias; alias = alias->next)
               if (wildcard_matchn(alias->iface, ifr.ifr_name, IF_NAMESIZE))
                 {
                   parm.ind = if_nametoindex(bridge->iface);
                   if (!parm.ind)
                     {
                       my_syslog(MS_DHCP | LOG_WARNING,
                                 _("unknown interface %s in bridge-interface"),
                                 bridge->iface);
                       return;
                     }
                   break;
                 }
             if (alias)
               break;
           }
               
       for (context = daemon->dhcp6; context; context = context->next)        for (context = daemon->dhcp6; context; context = context->next)
         if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)          if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
Line 201  void dhcp6_packet(time_t now) Line 220  void dhcp6_packet(time_t now)
           inet_pton(AF_INET6, ALL_SERVERS, &all_servers);            inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
                       
           if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))            if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
            relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id);            relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id, now);
           return;            return;
         }          }
               
       /* May have configured relay, but not DHCP server */        /* May have configured relay, but not DHCP server */
       if (!daemon->doing_dhcp6)        if (!daemon->doing_dhcp6)
         return;          return;
      
       lease_prune(NULL, now); /* lose any expired leases */        lease_prune(NULL, now); /* lose any expired leases */
               
       port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,         port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback, 
Line 225  void dhcp6_packet(time_t now) Line 244  void dhcp6_packet(time_t now)
   if (port != 0)    if (port != 0)
     {      {
       from.sin6_port = htons(port);        from.sin6_port = htons(port);
      while (sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, save_counter(0)      while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, 
                    0, (struct sockaddr *)&from, sizeof(from)) == -1 &&                               save_counter(0)0, (struct sockaddr *)&from, 
           retry_send());                               sizeof(from))));
     }      }
 }  }
   
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep)void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep, time_t now)
 {  {
   /* Recieving a packet from a host does not populate the neighbour    /* Recieving a packet from a host does not populate the neighbour
      cache, so we send a neighbour discovery request if we can't        cache, so we send a neighbour discovery request if we can't 
      find the sender. Repeat a few times in case of packet loss. */       find the sender. Repeat a few times in case of packet loss. */
       
   struct neigh_packet neigh;    struct neigh_packet neigh;
  struct sockaddr_in6 addr;  union mysockaddr addr;
  struct mac_param mac_param;  int i, maclen;
  int i; 
   
   neigh.type = ND_NEIGHBOR_SOLICIT;    neigh.type = ND_NEIGHBOR_SOLICIT;
   neigh.code = 0;    neigh.code = 0;
   neigh.reserved = 0;    neigh.reserved = 0;
   neigh.target = *client;    neigh.target = *client;
    /* RFC4443 section-2.3: checksum has to be zero to be calculated */
   neigh.checksum = 0;
    
   memset(&addr, 0, sizeof(addr));    memset(&addr, 0, sizeof(addr));
 #ifdef HAVE_SOCKADDR_SA_LEN  #ifdef HAVE_SOCKADDR_SA_LEN
  addr.sin6_len = sizeof(struct sockaddr_in6);  addr.in6.sin6_len = sizeof(struct sockaddr_in6);
 #endif  #endif
  addr.sin6_family = AF_INET6;  addr.in6.sin6_family = AF_INET6;
  addr.sin6_port = htons(IPPROTO_ICMPV6);  addr.in6.sin6_port = htons(IPPROTO_ICMPV6);
  addr.sin6_addr = *client;  addr.in6.sin6_addr = *client;
  addr.sin6_scope_id = iface;  addr.in6.sin6_scope_id = iface;
       
   mac_param.target = client;  
   mac_param.maclen = 0;  
   mac_param.mac = mac;  
     
   for (i = 0; i < 5; i++)    for (i = 0; i < 5; i++)
     {      {
       struct timespec ts;        struct timespec ts;
               
      iface_enumerate(AF_UNSPEC, &mac_param, find_mac);      if ((maclen = find_mac(&addr, mac, 0, now)) != 0)
       
      if (mac_param.maclen != 0) 
         break;          break;
             
         sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr));
               
       sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, (struct sockaddr *)&addr, sizeof(addr));  
         
       ts.tv_sec = 0;        ts.tv_sec = 0;
       ts.tv_nsec = 100000000; /* 100ms */        ts.tv_nsec = 100000000; /* 100ms */
       nanosleep(&ts, NULL);        nanosleep(&ts, NULL);
     }      }
   
  *maclenp = mac_param.maclen;  *maclenp = maclen;
   *mactypep = ARPHRD_ETHER;    *mactypep = ARPHRD_ETHER;
 }  }
           
 static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)  
 {  
   struct mac_param *parm = parmv;  
     
   if (family == AF_INET6 && IN6_ARE_ADDR_EQUAL(parm->target, (struct in6_addr *)addrp))  
     {  
       if (maclen <= DHCP_CHADDR_MAX)  
         {  
           parm->maclen = maclen;  
           memcpy(parm->mac, mac, maclen);  
         }  
         
       return 0; /* found, abort */  
     }  
     
   return 1;  
 }  
   
 static int complete_context6(struct in6_addr *local,  int prefix,  static int complete_context6(struct in6_addr *local,  int prefix,
                              int scope, int if_index, int flags, unsigned int preferred,                                int scope, int if_index, int flags, unsigned int preferred, 
                              unsigned int valid, void *vparam)                               unsigned int valid, void *vparam)
Line 424  struct dhcp_context *address6_allocate(struct dhcp_con Line 420  struct dhcp_context *address6_allocate(struct dhcp_con
     j = rand64();      j = rand64();
   else    else
     for (j = iaid, i = 0; i < clid_len; i++)      for (j = iaid, i = 0; i < clid_len; i++)
      j += clid[i] + (j << 6) + (j << 16) - j;      j = clid[i] + (j << 6) + (j << 16) - j;
       
   for (pass = 0; pass <= plain_range ? 1 : 0; pass++)    for (pass = 0; pass <= plain_range ? 1 : 0; pass++)
     for (c = context; c; c = c->current)      for (c = context; c; c = c->current)
Line 438  struct dhcp_context *address6_allocate(struct dhcp_con Line 434  struct dhcp_context *address6_allocate(struct dhcp_con
             /* seed is largest extant lease addr in this context */              /* seed is largest extant lease addr in this context */
             start = lease_find_max_addr6(c) + serial;              start = lease_find_max_addr6(c) + serial;
           else            else
            start = addr6part(&c->start6) + ((j + c->addr_epoch) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));            {
               u64 range = 1 + addr6part(&c->end6) - addr6part(&c->start6);
               u64 offset = j + c->addr_epoch;
   
                 /* don't divide by zero if range is whole 2^64 */
                 if (range != 0)
                   offset = offset % range;
   
                 start = addr6part(&c->start6) + offset;
               }
   
           /* iterate until we find a free address. */            /* iterate until we find a free address. */
           addr = start;            addr = start;
                       
Line 727  void dhcp_construct_contexts(time_t now) Line 732  void dhcp_construct_contexts(time_t now)
             
       if (context->flags & CONTEXT_GC && !(context->flags & CONTEXT_OLD))        if (context->flags & CONTEXT_GC && !(context->flags & CONTEXT_OLD))
         {          {
          if ((context->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) ||          if ((context->flags & CONTEXT_RA) || option_bool(OPT_RA))
              option_bool(OPT_RA)) 
             {              {
               /* previously constructed context has gone. advertise it's demise */                /* previously constructed context has gone. advertise it's demise */
               context->flags |= CONTEXT_OLD;                context->flags |= CONTEXT_OLD;

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


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