Annotation of embedaddon/dnsmasq/src/slaac.c, revision 1.1.1.5
1.1.1.5 ! misho 1: /* dnsmasq is Copyright (c) 2000-2022 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>