blob: 5f08980eee2bb631bdb6c6e0b7de9027957b9e71 [file] [log] [blame]
Samuel Tand7ed8512015-08-13 16:11:35 -07001/*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
4 * All rights reserved
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <errno.h>
29#include <signal.h>
30#include <stdlib.h>
31#include <string.h>
32#include <unistd.h>
33
34#define ELOOP_QUEUE 6
35#include "config.h"
36#include "arp.h"
37#include "common.h"
38#include "dhcp.h"
39#include "eloop.h"
40#include "if.h"
41#include "if-options.h"
42#include "ipv4ll.h"
43
44static struct dhcp_message *
45ipv4ll_make_lease(uint32_t addr)
46{
47 uint32_t u32;
48 struct dhcp_message *dhcp;
49 uint8_t *p;
50
51 dhcp = calloc(1, sizeof(*dhcp));
52 if (dhcp == NULL)
53 return NULL;
54 /* Put some LL options in */
55 dhcp->yiaddr = addr;
56 p = dhcp->options;
57 *p++ = DHO_SUBNETMASK;
58 *p++ = sizeof(u32);
59 u32 = htonl(LINKLOCAL_MASK);
60 memcpy(p, &u32, sizeof(u32));
61 p += sizeof(u32);
62 *p++ = DHO_BROADCAST;
63 *p++ = sizeof(u32);
64 u32 = htonl(LINKLOCAL_BRDC);
65 memcpy(p, &u32, sizeof(u32));
66 p += sizeof(u32);
67 *p++ = DHO_END;
68
69 return dhcp;
70}
71
72static in_addr_t
73ipv4ll_pick_addr(const struct arp_state *astate)
74{
75 in_addr_t addr;
76 struct interface *ifp;
77 const struct dhcp_state *state;
78
79 for (;;) {
80 /* RFC 3927 Section 2.1 states that the first 256 and
81 * last 256 addresses are reserved for future use.
82 * See ipv4ll_start for why we don't use arc4_random. */
83 addr = ntohl(LINKLOCAL_ADDR |
84 ((uint32_t)(random() % 0xFD00) + 0x0100));
85
86 /* No point using a failed address */
87 if (addr == astate->failed.s_addr)
88 continue;
89
90 /* Ensure we don't have the address on another interface */
91 TAILQ_FOREACH(ifp, astate->iface->ctx->ifaces, next) {
92 state = D_CSTATE(ifp);
93 if (state && state->addr.s_addr == addr)
94 break;
95 }
96
97 /* Yay, this should be a unique and workable IPv4LL address */
98 if (ifp == NULL)
99 break;
100 }
101 return addr;
102}
103
104static void
105ipv4ll_probed(struct arp_state *astate)
106{
107 struct dhcp_state *state = D_STATE(astate->iface);
108
109 if (state->state == DHS_IPV4LL_BOUND) {
110 ipv4_finaliseaddr(astate->iface);
111 return;
112 }
113
114 if (state->state != DHS_BOUND) {
115 struct dhcp_message *offer;
116
117 /* A DHCP lease could have already been offered.
118 * Backup and replace once the IPv4LL address is bound */
119 offer = state->offer;
120 state->offer = ipv4ll_make_lease(astate->addr.s_addr);
121 if (state->offer == NULL)
122 logger(astate->iface->ctx, LOG_ERR, "%s: %m", __func__);
123 else
124 dhcp_bind(astate->iface, astate);
125 state->offer = offer;
126 }
127}
128
129static void
130ipv4ll_announced(struct arp_state *astate)
131{
132 struct dhcp_state *state = D_STATE(astate->iface);
133
134 state->conflicts = 0;
135 /* Need to keep the arp state so we can defend our IP. */
136}
137
138static void
139ipv4ll_probe(void *arg)
140{
141
142#ifdef IN_IFF_TENTATIVE
143 ipv4ll_probed(arg);
144#else
145 arp_probe(arg);
146#endif
147}
148
149static void
150ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
151{
152 struct dhcp_state *state = D_STATE(astate->iface);
153 in_addr_t fail;
154
155 fail = 0;
156 /* RFC 3927 2.2.1, Probe Conflict Detection */
157 if (amsg == NULL ||
158 (amsg->sip.s_addr == astate->addr.s_addr ||
159 (amsg->sip.s_addr == 0 && amsg->tip.s_addr == astate->addr.s_addr)))
160 fail = astate->addr.s_addr;
161
162 /* RFC 3927 2.5, Conflict Defense */
163 if (IN_LINKLOCAL(htonl(state->addr.s_addr)) &&
164 amsg && amsg->sip.s_addr == state->addr.s_addr)
165 fail = state->addr.s_addr;
166
167 if (fail == 0)
168 return;
169
170 astate->failed.s_addr = fail;
171 arp_report_conflicted(astate, amsg);
172
173 if (astate->failed.s_addr == state->addr.s_addr) {
174 time_t up;
175
176 /* RFC 3927 Section 2.5 */
177 up = uptime();
178 if (state->defend + DEFEND_INTERVAL > up) {
179 logger(astate->iface->ctx, LOG_WARNING,
180 "%s: IPv4LL %d second defence failed for %s",
181 astate->iface->name, DEFEND_INTERVAL,
182 inet_ntoa(state->addr));
183 dhcp_drop(astate->iface, "EXPIRE");
184 } else {
185 logger(astate->iface->ctx, LOG_DEBUG,
186 "%s: defended IPv4LL address %s",
187 astate->iface->name, inet_ntoa(state->addr));
188 state->defend = up;
189 return;
190 }
191 }
192
193 arp_cancel(astate);
194 if (++state->conflicts == MAX_CONFLICTS)
195 logger(astate->iface->ctx, LOG_ERR,
196 "%s: failed to acquire an IPv4LL address",
197 astate->iface->name);
198 astate->addr.s_addr = ipv4ll_pick_addr(astate);
199 eloop_timeout_add_sec(astate->iface->ctx->eloop,
200 state->conflicts >= MAX_CONFLICTS ?
201 RATE_LIMIT_INTERVAL : PROBE_WAIT,
202 ipv4ll_probe, astate);
203}
204
205void
206ipv4ll_start(void *arg)
207{
208 struct interface *ifp = arg;
209 struct dhcp_state *state = D_STATE(ifp);
210 struct arp_state *astate;
211 struct ipv4_addr *ap;
212
213 if (state->arp_ipv4ll)
214 return;
215
216 /* RFC 3927 Section 2.1 states that the random number generator
217 * SHOULD be seeded with a value derived from persistent information
218 * such as the IEEE 802 MAC address so that it usually picks
219 * the same address without persistent storage. */
220 if (state->conflicts == 0) {
221 unsigned int seed;
222
223 if (sizeof(seed) > ifp->hwlen) {
224 seed = 0;
225 memcpy(&seed, ifp->hwaddr, ifp->hwlen);
226 } else
227 memcpy(&seed, ifp->hwaddr + ifp->hwlen - sizeof(seed),
228 sizeof(seed));
229 initstate(seed, state->randomstate, sizeof(state->randomstate));
230 }
231
232 if ((astate = arp_new(ifp, NULL)) == NULL)
233 return;
234
235 state->arp_ipv4ll = astate;
236 astate->probed_cb = ipv4ll_probed;
237 astate->announced_cb = ipv4ll_announced;
238 astate->conflicted_cb = ipv4ll_conflicted;
239
240 if (IN_LINKLOCAL(htonl(state->addr.s_addr))) {
241 astate->addr = state->addr;
242 arp_announce(astate);
243 return;
244 }
245
246 if (state->offer && IN_LINKLOCAL(ntohl(state->offer->yiaddr))) {
247 astate->addr.s_addr = state->offer->yiaddr;
248 free(state->offer);
249 state->offer = NULL;
250 ap = ipv4_iffindaddr(ifp, &astate->addr, NULL);
251 } else
252 ap = ipv4_iffindlladdr(ifp);
253 if (ap) {
254 astate->addr = ap->addr;
255 ipv4ll_probed(astate);
256 return;
257 }
258
259 setstate(state->randomstate);
260 /* We maybe rebooting an IPv4LL address. */
261 if (!IN_LINKLOCAL(htonl(astate->addr.s_addr))) {
262 logger(ifp->ctx, LOG_INFO, "%s: probing for an IPv4LL address",
263 ifp->name);
264 astate->addr.s_addr = INADDR_ANY;
265 }
266 if (astate->addr.s_addr == INADDR_ANY)
267 astate->addr.s_addr = ipv4ll_pick_addr(astate);
268#ifdef IN_IFF_TENTATIVE
269 ipv4ll_probed(astate);
270#else
271 arp_probe(astate);
272#endif
273}
274
275void
276ipv4ll_stop(struct interface *ifp)
277{
278 struct dhcp_state *state = D_STATE(ifp);
279
280 eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp_ipv4ll);
281}