File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / slaac.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:02:07 2023 UTC (9 months, 1 week ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v8_2p1, HEAD
Version 8.2p1

    1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
    2: 
    3:    This program is free software; you can redistribute it and/or modify
    4:    it under the terms of the GNU General Public License as published by
    5:    the Free Software Foundation; version 2 dated June, 1991, or
    6:    (at your option) version 3 dated 29 June, 2007.
    7:  
    8:    This program is distributed in the hope that it will be useful,
    9:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   10:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11:    GNU General Public License for more details.
   12:      
   13:    You should have received a copy of the GNU General Public License
   14:    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   15: */
   16: 
   17: #include "dnsmasq.h"
   18: 
   19: #ifdef HAVE_DHCP6
   20: 
   21: #include <netinet/icmp6.h>
   22: 
   23: static int ping_id = 0;
   24: 
   25: void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
   26: {
   27:   struct slaac_address *slaac, *old, **up;
   28:   struct dhcp_context *context;
   29:   int dns_dirty = 0;
   30:   
   31:   if (!(lease->flags & LEASE_HAVE_HWADDR) || 
   32:       (lease->flags & (LEASE_TA | LEASE_NA)) ||
   33:       lease->last_interface == 0 ||
   34:       !lease->hostname)
   35:     return ;
   36:   
   37:   old = lease->slaac_address;
   38:   lease->slaac_address = NULL;
   39: 
   40:   for (context = daemon->dhcp6; context; context = context->next) 
   41:     if ((context->flags & CONTEXT_RA_NAME) && 
   42: 	!(context->flags & CONTEXT_OLD) &&
   43: 	lease->last_interface == context->if_index)
   44:       {
   45: 	struct in6_addr addr = context->start6;
   46: 	if (lease->hwaddr_len == 6 &&
   47: 	    (lease->hwaddr_type == ARPHRD_ETHER || lease->hwaddr_type == ARPHRD_IEEE802))
   48: 	  {
   49: 	    /* convert MAC address to EUI-64 */
   50: 	    memcpy(&addr.s6_addr[8], lease->hwaddr, 3);
   51: 	    memcpy(&addr.s6_addr[13], &lease->hwaddr[3], 3);
   52: 	    addr.s6_addr[11] = 0xff;
   53: 	    addr.s6_addr[12] = 0xfe;
   54: 	  }
   55: #if defined(ARPHRD_EUI64)
   56: 	else if (lease->hwaddr_len == 8 &&
   57: 		 lease->hwaddr_type == ARPHRD_EUI64)
   58: 	  memcpy(&addr.s6_addr[8], lease->hwaddr, 8);
   59: #endif
   60: #if defined(ARPHRD_IEEE1394) && defined(ARPHRD_EUI64)
   61: 	else if (lease->clid_len == 9 && 
   62: 		 lease->clid[0] ==  ARPHRD_EUI64 &&
   63: 		 lease->hwaddr_type == ARPHRD_IEEE1394)
   64: 	  /* firewire has EUI-64 identifier as clid */
   65: 	  memcpy(&addr.s6_addr[8], &lease->clid[1], 8);
   66: #endif
   67: 	else
   68: 	  continue;
   69: 	
   70: 	addr.s6_addr[8] ^= 0x02;
   71: 	
   72: 	/* check if we already have this one */
   73: 	for (up = &old, slaac = old; slaac; slaac = slaac->next)
   74: 	  {
   75: 	    if (IN6_ARE_ADDR_EQUAL(&addr, &slaac->addr))
   76: 	      {
   77: 		*up = slaac->next;
   78: 		/* recheck when DHCPv4 goes through init-reboot */
   79: 		if (force)
   80: 		  {
   81: 		    slaac->ping_time = now;
   82: 		    slaac->backoff = 1;
   83: 		    dns_dirty = 1;
   84: 		  }
   85: 		break;
   86: 	      }
   87: 	    up = &slaac->next;
   88: 	  }
   89: 	    
   90: 	/* No, make new one */
   91: 	if (!slaac && (slaac = whine_malloc(sizeof(struct slaac_address))))
   92: 	  {
   93: 	    slaac->ping_time = now;
   94: 	    slaac->backoff = 1;
   95: 	    slaac->addr = addr;
   96: 	    /* Do RA's to prod it */
   97: 	    ra_start_unsolicited(now, context);
   98: 	  }
   99: 	
  100: 	if (slaac)
  101: 	  {
  102: 	    slaac->next = lease->slaac_address;
  103: 	    lease->slaac_address = slaac;
  104: 	  }
  105:       }
  106:   
  107:   if (old || dns_dirty)
  108:     lease_update_dns(1);
  109:   
  110:   /* Free any no reused */
  111:   for (; old; old = slaac)
  112:     {
  113:       slaac = old->next;
  114:       free(old);
  115:     }
  116: }
  117: 
  118: 
  119: time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
  120: {
  121:   struct dhcp_context *context;
  122:   struct dhcp_lease *lease;
  123:   struct slaac_address *slaac;
  124:   time_t next_event = 0;
  125:   
  126:   for (context = daemon->dhcp6; context; context = context->next)
  127:     if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
  128:       break;
  129: 
  130:   /* nothing configured */
  131:   if (!context)
  132:     return 0;
  133: 
  134:   while (ping_id == 0)
  135:     ping_id = rand16();
  136: 
  137:   for (lease = leases; lease; lease = lease->next)
  138:     for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
  139:       {
  140: 	/* confirmed or given up? */
  141: 	if (slaac->backoff == 0 || slaac->ping_time == 0)
  142: 	  continue;
  143: 	
  144: 	if (difftime(slaac->ping_time, now) <= 0.0)
  145: 	  {
  146: 	    struct ping_packet *ping;
  147: 	    struct sockaddr_in6 addr;
  148:  
  149: 	    reset_counter();
  150: 
  151: 	    if (!(ping = expand(sizeof(struct ping_packet))))
  152: 	      continue;
  153: 
  154: 	    ping->type = ICMP6_ECHO_REQUEST;
  155: 	    ping->code = 0;
  156: 	    ping->identifier = ping_id;
  157: 	    ping->sequence_no = slaac->backoff;
  158: 	    
  159: 	    memset(&addr, 0, sizeof(addr));
  160: #ifdef HAVE_SOCKADDR_SA_LEN
  161: 	    addr.sin6_len = sizeof(struct sockaddr_in6);
  162: #endif
  163: 	    addr.sin6_family = AF_INET6;
  164: 	    addr.sin6_port = htons(IPPROTO_ICMPV6);
  165: 	    addr.sin6_addr = slaac->addr;
  166: 	    
  167: 	    if (sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(-1), 0,
  168: 		       (struct sockaddr *)&addr,  sizeof(addr)) == -1 &&
  169: 		errno == EHOSTUNREACH &&
  170: 		slaac->backoff == 12)
  171: 	      slaac->ping_time = 0; /* Give up */ 
  172: 	    else
  173: 	      {
  174: 		slaac->ping_time += (1 << (slaac->backoff - 1)) + (rand16()/21785); /* 0 - 3 */
  175: 		if (slaac->backoff > 4)
  176: 		  slaac->ping_time += rand16()/4000; /* 0 - 15 */
  177: 		if (slaac->backoff < 12)
  178: 		  slaac->backoff++;
  179: 	      }
  180: 	  }
  181: 	
  182: 	if (slaac->ping_time != 0 &&
  183: 	    (next_event == 0 || difftime(next_event, slaac->ping_time) >= 0.0))
  184: 	  next_event = slaac->ping_time;
  185:       }
  186: 
  187:   return next_event;
  188: }
  189: 
  190: 
  191: void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface, struct dhcp_lease *leases)
  192: {
  193:   struct dhcp_lease *lease;
  194:   struct slaac_address *slaac;
  195:   struct ping_packet *ping = (struct ping_packet *)packet;
  196:   int gotone = 0;
  197:   
  198:   if (ping->identifier == ping_id)
  199:     for (lease = leases; lease; lease = lease->next)
  200:       for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
  201: 	if (slaac->backoff != 0 && IN6_ARE_ADDR_EQUAL(sender, &slaac->addr))
  202: 	  {
  203: 	    slaac->backoff = 0;
  204: 	    gotone = 1;
  205: 	    inet_ntop(AF_INET6, sender, daemon->addrbuff, ADDRSTRLEN);
  206: 	    if (!option_bool(OPT_QUIET_DHCP6))
  207: 	      my_syslog(MS_DHCP | LOG_INFO, "SLAAC-CONFIRM(%s) %s %s", interface, daemon->addrbuff, lease->hostname); 
  208: 	  }
  209:   
  210:   lease_update_dns(gotone);
  211: }
  212: 	
  213: #endif

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