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

1.1.1.4 ! misho       1: /* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
1.1       misho       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) 
1.1.1.2   misho      41:     if ((context->flags & CONTEXT_RA_NAME) && 
                     42:        !(context->flags & CONTEXT_OLD) &&
                     43:        lease->last_interface == context->if_index)
1.1       misho      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 */
1.1.1.4 ! misho      97:            ra_start_unsolicited(now, context);
1.1       misho      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)
1.1.1.2   misho     127:     if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
1.1       misho     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:  
1.1.1.4 ! misho     149:            reset_counter();
        !           150: 
        !           151:            if (!(ping = expand(sizeof(struct ping_packet))))
        !           152:              continue;
        !           153: 
1.1       misho     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:            
1.1.1.4 ! misho     167:            if (sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(-1), 0,
1.1       misho     168:                       (struct sockaddr *)&addr,  sizeof(addr)) == -1 &&
1.1.1.4 ! misho     169:                errno == EHOSTUNREACH &&
        !           170:                slaac->backoff == 12)
1.1       misho     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);
1.1.1.2   misho     206:            if (!option_bool(OPT_QUIET_DHCP6))
                    207:              my_syslog(MS_DHCP | LOG_INFO, "SLAAC-CONFIRM(%s) %s %s", interface, daemon->addrbuff, lease->hostname); 
1.1       misho     208:          }
                    209:   
                    210:   lease_update_dns(gotone);
                    211: }
                    212:        
                    213: #endif

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