Home | History | Annotate | Download | only in dhcpcd-6.8.2
      1 /*
      2  * dhcpcd - DHCP client daemon
      3  * Copyright (c) 2006-2015 Roy Marples <roy (at) 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 
     44 static struct dhcp_message *
     45 ipv4ll_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 
     72 static in_addr_t
     73 ipv4ll_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 
    104 static void
    105 ipv4ll_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 
    129 static void
    130 ipv4ll_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 
    138 static void
    139 ipv4ll_probe(void *arg)
    140 {
    141 
    142 #ifdef IN_IFF_TENTATIVE
    143 	ipv4ll_probed(arg);
    144 #else
    145 	arp_probe(arg);
    146 #endif
    147 }
    148 
    149 static void
    150 ipv4ll_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 
    205 void
    206 ipv4ll_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 
    275 void
    276 ipv4ll_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 }
    282