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>