Annotation of embedaddon/dnsmasq/src/slaac.c, revision 1.1.1.1

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

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