Annotation of embedaddon/dnsmasq/src/slaac.c, revision 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>