This commit is contained in:
roy 2015-05-02 15:18:36 +00:00
parent 372b3c16e6
commit 4d6391b4f4
24 changed files with 964 additions and 505 deletions

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: arp.c,v 1.11 2015/03/27 18:53:15 christos Exp $");
__RCSID("$NetBSD: arp.c,v 1.12 2015/05/02 15:18:36 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -44,6 +44,7 @@
#define ELOOP_QUEUE 5
#include "config.h"
#include "arp.h"
#include "if.h"
#include "ipv4.h"
#include "common.h"
#include "dhcp.h"
@ -57,7 +58,7 @@
(sizeof(struct arphdr) + (2 * sizeof(uint32_t)) + (2 * HWADDR_LEN))
static ssize_t
arp_send(const struct interface *ifp, int op, in_addr_t sip, in_addr_t tip)
arp_request(const struct interface *ifp, in_addr_t sip, in_addr_t tip)
{
uint8_t arp_buffer[ARP_LEN];
struct arphdr ar;
@ -68,7 +69,7 @@ arp_send(const struct interface *ifp, int op, in_addr_t sip, in_addr_t tip)
ar.ar_pro = htons(ETHERTYPE_IP);
ar.ar_hln = ifp->hwlen;
ar.ar_pln = sizeof(sip);
ar.ar_op = htons((uint16_t)op);
ar.ar_op = htons(ARPOP_REQUEST);
p = arp_buffer;
len = 0;
@ -99,12 +100,20 @@ eexit:
void
arp_report_conflicted(const struct arp_state *astate, const struct arp_msg *amsg)
{
char buf[HWADDR_LEN * 3];
logger(astate->iface->ctx, LOG_ERR, "%s: hardware address %s claims %s",
astate->iface->name,
hwaddr_ntoa(amsg->sha, astate->iface->hwlen, buf, sizeof(buf)),
inet_ntoa(astate->failed));
if (amsg) {
char buf[HWADDR_LEN * 3];
logger(astate->iface->ctx, LOG_ERR,
"%s: hardware address %s claims %s",
astate->iface->name,
hwaddr_ntoa(amsg->sha, astate->iface->hwlen,
buf, sizeof(buf)),
inet_ntoa(astate->failed));
} else
logger(astate->iface->ctx, LOG_ERR,
"%s: DAD detected %s",
astate->iface->name, inet_ntoa(astate->failed));
}
static void
@ -226,8 +235,7 @@ arp_announce1(void *arg)
"%s: ARP announcing %s (%d of %d)",
ifp->name, inet_ntoa(astate->addr),
astate->claims, ANNOUNCE_NUM);
if (arp_send(ifp, ARPOP_REQUEST,
astate->addr.s_addr, astate->addr.s_addr) == -1)
if (arp_request(ifp, astate->addr.s_addr, astate->addr.s_addr) == -1)
logger(ifp->ctx, LOG_ERR, "send_arp: %m");
eloop_timeout_add_sec(ifp->ctx->eloop, ANNOUNCE_WAIT,
astate->claims < ANNOUNCE_NUM ? arp_announce1 : arp_announced,
@ -274,7 +282,7 @@ arp_probe1(void *arg)
ifp->name, inet_ntoa(astate->addr),
astate->probes ? astate->probes : PROBE_NUM, PROBE_NUM,
timespec_to_double(&tv));
if (arp_send(ifp, ARPOP_REQUEST, 0, astate->addr.s_addr) == -1)
if (arp_request(ifp, 0, astate->addr.s_addr) == -1)
logger(ifp->ctx, LOG_ERR, "send_arp: %m");
}
@ -289,19 +297,38 @@ arp_probe(struct arp_state *astate)
arp_probe1(astate);
}
struct arp_state *
arp_new(struct interface *ifp) {
static struct arp_state *
arp_find(struct interface *ifp, const struct in_addr *addr)
{
struct arp_state *astate;
struct dhcp_state *state;
astate = calloc(1, sizeof(*astate));
if (astate == NULL) {
state = D_STATE(ifp);
TAILQ_FOREACH(astate, &state->arp_states, next) {
if (astate->addr.s_addr == addr->s_addr && astate->iface == ifp)
return astate;
}
errno = ESRCH;
return NULL;
}
struct arp_state *
arp_new(struct interface *ifp, const struct in_addr *addr)
{
struct arp_state *astate;
struct dhcp_state *state;
if (addr && (astate = arp_find(ifp, addr)))
return astate;
if ((astate = calloc(1, sizeof(*astate))) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %s: %m", ifp->name, __func__);
return NULL;
}
astate->iface = ifp;
state = D_STATE(ifp);
astate->iface = ifp;
if (addr)
astate->addr = *addr;
TAILQ_INSERT_TAIL(&state->arp_states, astate, next);
return astate;
}
@ -366,3 +393,33 @@ arp_close(struct interface *ifp)
#endif
}
}
void
arp_handleifa(int cmd, struct interface *ifp, const struct in_addr *addr,
int flags)
{
#ifdef IN_IFF_DUPLICATED
struct dhcp_state *state = D_STATE(ifp);
struct arp_state *astate, *asn;
if (cmd != RTM_NEWADDR || (state = D_STATE(ifp)) == NULL)
return;
TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, asn) {
if (astate->addr.s_addr == addr->s_addr) {
if (flags & IN_IFF_DUPLICATED) {
if (astate->conflicted_cb)
astate->conflicted_cb(astate, NULL);
} else if (!(flags & IN_IFF_NOTUSEABLE)) {
if (astate->probed_cb)
astate->probed_cb(astate);
}
}
}
#else
UNUSED(cmd);
UNUSED(ifp);
UNUSED(addr);
UNUSED(flags);
#endif
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: arp.h,v 1.8 2015/01/30 09:47:05 roy Exp $ */
/* $NetBSD: arp.h,v 1.9 2015/05/02 15:18:36 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -71,11 +71,13 @@ TAILQ_HEAD(arp_statehead, arp_state);
void arp_report_conflicted(const struct arp_state *, const struct arp_msg *);
void arp_announce(struct arp_state *);
void arp_probe(struct arp_state *);
struct arp_state *arp_new(struct interface *);
struct arp_state *arp_new(struct interface *, const struct in_addr *);
void arp_cancel(struct arp_state *);
void arp_free(struct arp_state *);
void arp_free_but(struct arp_state *);
void arp_close(struct interface *);
void arp_handleifa(int, struct interface *, const struct in_addr *, int);
#else
#define arp_close(a) {}
#endif

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: common.c,v 1.11 2015/03/31 18:01:09 christos Exp $");
__RCSID("$NetBSD: common.c,v 1.12 2015/05/02 15:18:36 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -28,11 +28,6 @@
* SUCH DAMAGE.
*/
/* Needed define to get at getline for glibc and FreeBSD */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#ifdef __APPLE__
# include <mach/mach_time.h>
# include <mach/kern_return.h>
@ -196,8 +191,8 @@ logger(struct dhcpcd_ctx *ctx, int pri, const char *fmt, ...)
return;
serrno = errno;
va_start(va, fmt);
#ifndef HAVE_PRINTF_M
/* Print strerrno(errno) in place of %m */
if (ctx == NULL || !(ctx->options & DHCPCD_QUIET) || ctx->log_fd != -1)

View File

@ -1,4 +1,4 @@
/* $NetBSD: defs.h,v 1.16 2015/03/27 11:33:46 roy Exp $ */
/* $NetBSD: defs.h,v 1.17 2015/05/02 15:18:36 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -30,7 +30,7 @@
#define CONFIG_H
#define PACKAGE "dhcpcd"
#define VERSION "6.8.1"
#define VERSION "6.8.2"
#ifndef CONFIG
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: dhcp.c,v 1.29 2015/03/28 14:16:52 christos Exp $");
__RCSID("$NetBSD: dhcp.c,v 1.30 2015/05/02 15:18:36 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -163,6 +163,12 @@ get_option(struct dhcpcd_ctx *ctx,
const uint8_t *op = NULL;
size_t bl = 0;
/* Check we have the magic cookie */
if (dhcp->cookie != htonl(MAGIC_COOKIE)) {
errno = ENOTSUP;
return NULL;
}
while (p < e) {
o = *p++;
if (o == opt) {
@ -621,11 +627,11 @@ get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
p = get_option(ifp->ctx, dhcp, DHO_STATICROUTE, &len);
else
p = NULL;
if (p) {
/* RFC 2131 Section 5.8 states length MUST be in multiples of 8 */
if (p && len % 8 == 0) {
e = p + len;
while (p < e) {
route = calloc(1, sizeof(*route));
if (route == NULL) {
if ((route = calloc(1, sizeof(*route))) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
ipv4_freeroutes(routes);
return NULL;
@ -634,6 +640,13 @@ get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
p += 4;
memcpy(&route->gate.s_addr, p, 4);
p += 4;
/* RFC 2131 Section 5.8 states default route is
* illegal */
if (route->dest.s_addr == htonl(INADDR_ANY)) {
errno = EINVAL;
free(route);
continue;
}
route->net.s_addr = route_netmask(route->dest.s_addr);
TAILQ_INSERT_TAIL(routes, route, next);
}
@ -647,8 +660,7 @@ get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
if (p) {
e = p + len;
while (p < e) {
route = calloc(1, sizeof(*route));
if (route == NULL) {
if ((route = calloc(1, sizeof(*route))) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
ipv4_freeroutes(routes);
return NULL;
@ -701,10 +713,10 @@ make_message(struct dhcp_message **message,
{
struct dhcp_message *dhcp;
uint8_t *m, *lp, *p, *auth;
uint8_t *n_params = NULL;
uint8_t *n_params = NULL, auth_len;
uint32_t ul;
uint16_t sz;
size_t len, i, auth_len;
size_t len, i;
const struct dhcp_opt *opt;
struct if_options *ifo = ifp->options;
const struct dhcp_state *state = D_CSTATE(ifp);
@ -757,9 +769,11 @@ make_message(struct dhcp_message **message,
dhcp->xid = htonl(state->xid);
dhcp->cookie = htonl(MAGIC_COOKIE);
*p++ = DHO_MESSAGETYPE;
*p++ = 1;
*p++ = type;
if (!(ifo->options & DHCPCD_BOOTP)) {
*p++ = DHO_MESSAGETYPE;
*p++ = 1;
*p++ = type;
}
if (state->clientid) {
*p++ = DHO_CLIENTID;
@ -814,23 +828,25 @@ make_message(struct dhcp_message **message,
type == DHCP_INFORM ||
type == DHCP_REQUEST)
{
int mtu;
if (!(ifo->options & DHCPCD_BOOTP)) {
int mtu;
*p++ = DHO_MAXMESSAGESIZE;
*p++ = 2;
mtu = if_getmtu(ifp->name);
if (mtu < MTU_MIN) {
if (if_setmtu(ifp->name, MTU_MIN) == 0)
sz = MTU_MIN;
} else if (mtu > MTU_MAX) {
/* Even though our MTU could be greater than
* MTU_MAX (1500) dhcpcd does not presently
* handle DHCP packets any bigger. */
mtu = MTU_MAX;
*p++ = DHO_MAXMESSAGESIZE;
*p++ = 2;
mtu = if_getmtu(ifp->name);
if (mtu < MTU_MIN) {
if (if_setmtu(ifp->name, MTU_MIN) == 0)
sz = MTU_MIN;
} else if (mtu > MTU_MAX) {
/* Even though our MTU could be greater than
* MTU_MAX (1500) dhcpcd does not presently
* handle DHCP packets any bigger. */
mtu = MTU_MAX;
}
sz = htons((uint16_t)mtu);
memcpy(p, &sz, 2);
p += 2;
}
sz = htons((uint16_t)mtu);
memcpy(p, &sz, 2);
p += 2;
if (ifo->userclass[0]) {
*p++ = DHO_USERCLASS;
@ -1004,19 +1020,23 @@ make_message(struct dhcp_message **message,
auth = NULL;
if (ifo->auth.options & DHCPCD_AUTH_SEND) {
auth_len = (size_t)dhcp_auth_encode(&ifo->auth,
ssize_t alen = dhcp_auth_encode(&ifo->auth,
state->auth.token,
NULL, 0, 4, type, NULL, 0);
if ((ssize_t)auth_len == -1) {
if (alen != -1 && alen > UINT8_MAX) {
errno = ERANGE;
alen = -1;
}
if (alen == -1)
logger(ifp->ctx, LOG_ERR,
"%s: dhcp_auth_encode: %m", ifp->name);
auth_len = 0;
} else if (auth_len != 0) {
len = (size_t)((p + auth_len) - m);
if (auth_len > 255 || len > sizeof(*dhcp))
else if (alen != 0) {
auth_len = (uint8_t)alen;
len = (size_t)((p + alen) - m);
if (len > sizeof(*dhcp))
goto toobig;
*p++ = DHO_AUTHENTICATION;
*p++ = (uint8_t)auth_len;
*p++ = auth_len;
auth = p;
p += auth_len;
}
@ -1024,13 +1044,10 @@ make_message(struct dhcp_message **message,
*p++ = DHO_END;
#ifdef BOOTP_MESSAGE_LENTH_MIN
/* Some crappy DHCP servers think they have to obey the BOOTP minimum
* message length.
* They are wrong, but we should still cater for them. */
/* Pad out to the BOOTP minimum message length.
* Some DHCP servers incorrectly require this. */
while (p - m < BOOTP_MESSAGE_LENTH_MIN)
*p++ = DHO_PAD;
#endif
len = (size_t)(p - m);
if (ifo->auth.options & DHCPCD_AUTH_SEND && auth_len != 0)
@ -1058,7 +1075,7 @@ write_lease(const struct interface *ifp, const struct dhcp_message *dhcp)
const struct dhcp_state *state = D_CSTATE(ifp);
/* We don't write BOOTP leases */
if (is_bootp(ifp, dhcp)) {
if (IS_BOOTP(ifp, dhcp)) {
unlink(state->leasefile);
return 0;
}
@ -1126,6 +1143,7 @@ read_lease(struct interface *ifp)
/* We may have found a BOOTP server */
if (get_option_uint8(ifp->ctx, &type, dhcp, DHO_MESSAGETYPE) == -1)
type = 0;
/* Authenticate the message */
auth = get_option(ifp->ctx, dhcp, DHO_AUTHENTICATION, &auth_len);
if (auth) {
@ -1497,18 +1515,18 @@ checksum(const void *data, unsigned int len)
uint32_t sum = 0;
while (len > 1) {
sum += (uint32_t)addr[0] * 256 + (uint32_t)addr[1];
sum += (uint32_t)(addr[0] * 256 + addr[1]);
addr += 2;
len -= 2;
}
if (len == 1)
sum += (uint32_t)*addr * 256;
sum += (uint32_t)(*addr * 256);
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return (uint16_t)~htons(sum);
return (uint16_t)~htons((uint16_t)sum);
}
static struct udp_dhcp_packet *
@ -1574,10 +1592,15 @@ send_message(struct interface *ifp, uint8_t type,
in_addr_t a = INADDR_ANY;
struct timespec tv;
int s;
#ifdef IN_IFF_NOTUSEABLE
struct ipv4_addr *ia;
#endif
if (!callback)
logger(ifp->ctx, LOG_DEBUG, "%s: sending %s with xid 0x%x",
ifp->name, get_dhcp_op(type), state->xid);
ifp->name,
ifo->options & DHCPCD_BOOTP ? "BOOTP" : get_dhcp_op(type),
state->xid);
else {
if (state->interval == 0)
state->interval = 4;
@ -1592,7 +1615,9 @@ send_message(struct interface *ifp, uint8_t type,
timespecnorm(&tv);
logger(ifp->ctx, LOG_DEBUG,
"%s: sending %s (xid 0x%x), next in %0.1f seconds",
ifp->name, get_dhcp_op(type), state->xid,
ifp->name,
ifo->options & DHCPCD_BOOTP ? "BOOTP" : get_dhcp_op(type),
state->xid,
timespec_to_double(&tv));
}
@ -1602,6 +1627,10 @@ send_message(struct interface *ifp, uint8_t type,
if (state->added && !(state->added & STATE_FAKE) &&
state->addr.s_addr != INADDR_ANY &&
state->new != NULL &&
#ifdef IN_IFF_NOTUSEABLE
((ia = ipv4_iffindaddr(ifp, &state->addr, NULL)) &&
!(ia->addr_flags & IN_IFF_NOTUSEABLE)) &&
#endif
(state->new->cookie == htonl(MAGIC_COOKIE) ||
ifp->options->options & DHCPCD_INFORM))
{
@ -1618,7 +1647,7 @@ send_message(struct interface *ifp, uint8_t type,
* Also, we should not unicast from a BOOTP lease. */
if (s == -1 ||
(!(ifo->options & DHCPCD_INFORM) &&
is_bootp(ifp, state->new)))
IS_BOOTP(ifp, state->new)))
{
a = state->addr.s_addr;
state->addr.s_addr = INADDR_ANY;
@ -1751,7 +1780,8 @@ dhcp_discover(void *arg)
ifp->name, inet_ntoa(ifo->req_addr));
else
logger(ifp->ctx, LOG_INFO,
"%s: soliciting a DHCP lease", ifp->name);
"%s: soliciting a %s lease",
ifp->name, ifo->options & DHCPCD_BOOTP ? "BOOTP" : "DHCP");
send_discover(ifp);
}
@ -1779,7 +1809,7 @@ dhcp_expire(void *arg)
dhcp_discover(ifp);
}
void
static void
dhcp_decline(struct interface *ifp)
{
@ -1804,12 +1834,14 @@ dhcp_renew(void *arg)
send_renew(ifp);
}
#ifndef IN_IFF_TENTATIVE
static void
dhcp_arp_announced(struct arp_state *astate)
{
arp_close(astate->iface);
}
#endif
static void
dhcp_rebind(void *arg)
@ -1958,13 +1990,18 @@ dhcp_bind(struct interface *ifp, struct arp_state *astate)
applyaddr:
ipv4_applyaddr(ifp);
if (dhcpcd_daemonise(ifp->ctx))
return;
if (ifo->options & DHCPCD_ARP) {
if (ifo->options & DHCPCD_ARP &&
!(ifp->ctx->options & DHCPCD_FORKED))
{
#ifdef IN_IFF_TENTATIVE
if (astate)
arp_free_but(astate);
else if (!ipv4ll)
arp_close(ifp);
#else
if (state->added) {
if (astate == NULL) {
astate = arp_new(ifp);
astate->addr = state->addr;
astate = arp_new(ifp, &state->addr);
astate->announced_cb =
dhcp_arp_announced;
}
@ -1975,6 +2012,7 @@ applyaddr:
}
} else if (!ipv4ll)
arp_close(ifp);
#endif
}
}
@ -2328,7 +2366,12 @@ dhcp_arp_probed(struct arp_state *astate)
}
dhcp_close(astate->iface);
eloop_timeout_delete(astate->iface->ctx->eloop, NULL, astate->iface);
#ifdef IN_IFF_TENTATIVE
ipv4_finaliseaddr(astate->iface);
arp_close(astate->iface);
#else
dhcp_bind(astate->iface, astate);
#endif
}
static void
@ -2341,6 +2384,7 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
ifo = astate->iface->options;
if (state->arping_index &&
state->arping_index <= ifo->arping_len &&
amsg &&
(amsg->sip.s_addr == ifo->arping[state->arping_index - 1] ||
(amsg->sip.s_addr == 0 &&
amsg->tip.s_addr == ifo->arping[state->arping_index - 1])))
@ -2367,18 +2411,30 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
dhcpcd_startinterface(astate->iface);
}
if (state->offer == NULL)
return;
/* RFC 2131 3.1.5, Client-server interaction */
if (amsg->sip.s_addr == state->offer->yiaddr ||
(amsg->sip.s_addr == 0 && amsg->tip.s_addr == state->offer->yiaddr))
/* RFC 2131 3.1.5, Client-server interaction
* NULL amsg means IN_IFF_DUPLICATED */
if (amsg == NULL || (state->offer &&
(amsg->sip.s_addr == state->offer->yiaddr ||
(amsg->sip.s_addr == 0 &&
amsg->tip.s_addr == state->offer->yiaddr))))
{
astate->failed.s_addr = state->offer->yiaddr;
#ifdef IN_IFF_DUPLICATED
struct ipv4_addr *ia;
#endif
if (amsg)
astate->failed.s_addr = state->offer->yiaddr;
else
astate->failed = astate->addr;
arp_report_conflicted(astate, amsg);
unlink(state->leasefile);
if (!state->lease.frominfo)
dhcp_decline(astate->iface);
#ifdef IN_IFF_DUPLICATED
ia = ipv4_iffindaddr(astate->iface, &astate->addr, NULL);
if (ia)
ipv4_deladdr(astate->iface, &ia->addr, &ia->net);
#endif
eloop_timeout_delete(astate->iface->ctx->eloop, NULL,
astate->iface);
eloop_timeout_add_sec(astate->iface->ctx->eloop,
@ -2386,23 +2442,6 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
}
}
void
dhcp_probe(struct interface *ifp)
{
const struct dhcp_state *state;
struct arp_state *astate;
astate = arp_new(ifp);
if (astate) {
state = D_CSTATE(ifp);
astate->addr = state->addr;
astate->probed_cb = dhcp_arp_probed;
astate->conflicted_cb = dhcp_arp_conflicted;
astate->announced_cb = dhcp_arp_announced;
arp_probe(astate);
}
}
static void
dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
const struct in_addr *from)
@ -2417,10 +2456,18 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
unsigned int i;
size_t auth_len;
char *msg;
struct arp_state *astate;
struct ipv4_addr *ia;
/* We may have found a BOOTP server */
if (get_option_uint8(ifp->ctx, &type, dhcp, DHO_MESSAGETYPE) == -1)
type = 0;
else if (ifo->options & DHCPCD_BOOTP) {
logger(ifp->ctx, LOG_DEBUG,
"%s: ignoring DHCP reply (excpecting BOOTP)",
ifp->name);
return;
}
/* Authenticate the message */
auth = get_option(ifp->ctx, dhcp, DHO_AUTHENTICATION, &auth_len);
@ -2553,9 +2600,9 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
if (has_option_mask(ifo->requiremask, i) &&
get_option_uint8(ifp->ctx, &tmp, dhcp, (uint8_t)i) != 0)
{
/* If we are bootp, then ignore the need for serverid.
* To ignore bootp, require dhcp_message_type.
* However, nothing really stops bootp from providing
/* If we are BOOTP, then ignore the need for serverid.
* To ignore BOOTP, require dhcp_message_type.
* However, nothing really stops BOOTP from providing
* DHCP style options as well so the above isn't
* always true. */
if (type == 0 && i == DHO_SERVERID)
@ -2621,6 +2668,21 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
return;
}
#ifdef IN_IFF_DUPLICATED
ia = ipv4_iffindaddr(ifp, &lease->addr, NULL);
if (ia && ia->addr_flags & IN_IFF_DUPLICATED) {
log_dhcp(LOG_WARNING, "declined duplicate address",
ifp, dhcp, from);
if (type)
dhcp_decline(ifp);
ipv4_deladdr(ifp, &ia->addr, &ia->net);
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
eloop_timeout_add_sec(ifp->ctx->eloop,
DHCP_RAND_MAX, dhcp_discover, ifp);
return;
}
#endif
if ((type == 0 || type == DHCP_OFFER) &&
(state->state == DHS_DISCOVER || state->state == DHS_IPV4LL_BOUND))
{
@ -2695,28 +2757,35 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
lease->frominfo = 0;
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
astate = NULL;
if (ifo->options & DHCPCD_ARP &&
state->addr.s_addr != state->offer->yiaddr)
#ifndef IN_IFF_TENTATIVE
if (ifo->options & DHCPCD_ARP
&& state->addr.s_addr != state->offer->yiaddr)
#endif
{
addr.s_addr = state->offer->yiaddr;
#ifndef IN_IFF_TENTATIVE
/* If the interface already has the address configured
* then we can't ARP for duplicate detection. */
addr.s_addr = state->offer->yiaddr;
if (!ipv4_iffindaddr(ifp, &addr, NULL)) {
struct arp_state *astate;
astate = arp_new(ifp);
ia = ipv4_findaddr(ifp->ctx, &addr);
if (ia) {
#endif
astate = arp_new(ifp, &addr);
if (astate) {
astate->addr = addr;
astate->probed_cb = dhcp_arp_probed;
astate->conflicted_cb = dhcp_arp_conflicted;
#ifndef IN_IFF_TENTATIVE
arp_probe(astate);
#endif
}
#ifndef IN_IFF_TENTATIVE
return;
}
#endif
}
dhcp_bind(ifp, NULL);
dhcp_bind(ifp, astate);
}
static size_t
@ -2939,9 +3008,8 @@ dhcp_dump(struct interface *ifp)
AF_INET, ifp, "");
state->new = read_lease(ifp);
if (state->new == NULL) {
if (errno == ENOENT)
logger(ifp->ctx, LOG_ERR,
"%s: no lease to dump", ifp->name);
logger(ifp->ctx, LOG_ERR, "%s: %s: %m",
*ifp->name ? ifp->name : state->leasefile, __func__);
return -1;
}
state->reason = "DUMP";
@ -3098,7 +3166,8 @@ dhcp_start1(void *arg)
/* Don't log an error if some other process
* is handling this. */
if (errno != EADDRINUSE)
logger(ifp->ctx, LOG_ERR, "dhcp_openudp: %m");
logger(ifp->ctx, LOG_ERR,
"%s: dhcp_openudp: %m", __func__);
} else
eloop_event_add(ifp->ctx->eloop,
ifp->ctx->udp_fd, dhcp_handleudp,
@ -3118,7 +3187,7 @@ dhcp_start1(void *arg)
if (state->arping_index < ifo->arping_len) {
struct arp_state *astate;
astate = arp_new(ifp);
astate = arp_new(ifp, NULL);
if (astate) {
astate->probed_cb = dhcp_arp_probed;
astate->conflicted_cb = dhcp_arp_conflicted;
@ -3148,8 +3217,31 @@ dhcp_start1(void *arg)
}
/* We don't want to read the old lease if we NAK an old test */
nolease = state->offer && ifp->ctx->options & DHCPCD_TEST;
if (!nolease)
if (!nolease) {
state->offer = read_lease(ifp);
/* Check the saved lease matches the type we want */
if (state->offer) {
#ifdef IN_IFF_DUPLICATED
struct in_addr addr;
struct ipv4_addr *ia;
addr.s_addr = state->offer->yiaddr;
ia = ipv4_iffindaddr(ifp, &addr, NULL);
#endif
if ((IS_BOOTP(ifp, state->offer) &&
!(ifo->options & DHCPCD_BOOTP)) ||
#ifdef IN_IFF_DUPLICATED
(ia && ia->addr_flags & IN_IFF_DUPLICATED) ||
#endif
(!IS_BOOTP(ifp, state->offer) &&
ifo->options & DHCPCD_BOOTP))
{
free(state->offer);
state->offer = NULL;
}
}
}
if (state->offer) {
get_lease(ifp->ctx, &state->lease, state->offer);
state->lease.frominfo = 1;
@ -3253,10 +3345,11 @@ dhcp_start(struct interface *ifp)
}
void
dhcp_handleifa(int type, struct interface *ifp,
dhcp_handleifa(int cmd, struct interface *ifp,
const struct in_addr *addr,
const struct in_addr *net,
const struct in_addr *dst)
const struct in_addr *dst,
__unused int flags)
{
struct dhcp_state *state;
struct if_options *ifo;
@ -3266,22 +3359,20 @@ dhcp_handleifa(int type, struct interface *ifp,
if (state == NULL)
return;
if (type == RTM_DELADDR) {
if (state->new &&
(state->new->yiaddr == addr->s_addr ||
(state->new->yiaddr == INADDR_ANY &&
state->new->ciaddr == addr->s_addr)))
if (cmd == RTM_DELADDR) {
if (state->addr.s_addr == addr->s_addr &&
state->net.s_addr == net->s_addr)
{
logger(ifp->ctx, LOG_INFO,
"%s: removing IP address %s/%d",
ifp->name, inet_ntoa(state->lease.addr),
inet_ntocidr(state->lease.net));
ifp->name, inet_ntoa(state->addr),
inet_ntocidr(state->net));
dhcp_drop(ifp, "EXPIRE");
}
return;
}
if (type != RTM_NEWADDR)
if (cmd != RTM_NEWADDR)
return;
ifo = ifp->options;

View File

@ -1,4 +1,4 @@
/* $NetBSD: dhcp.h,v 1.8 2015/03/26 10:26:37 roy Exp $ */
/* $NetBSD: dhcp.h,v 1.9 2015/05/02 15:18:36 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -259,8 +259,8 @@ void dhcp_printoptions(const struct dhcpcd_ctx *,
const struct dhcp_opt *, size_t);
int get_option_addr(struct dhcpcd_ctx *,struct in_addr *,
const struct dhcp_message *, uint8_t);
#define is_bootp(i, m) ((m) && \
!IN_LINKLOCAL(htonl((m)->yiaddr)) && \
#define IS_BOOTP(i, m) ((m) && \
!IN_LINKLOCAL(htonl((m)->yiaddr)) && \
get_option_uint8((i)->ctx, NULL, (m), DHO_MESSAGETYPE) == -1)
struct rt_head *get_option_routes(struct interface *,
const struct dhcp_message *);
@ -276,15 +276,14 @@ ssize_t make_message(struct dhcp_message **, const struct interface *,
int valid_dhcp_packet(unsigned char *);
void dhcp_handleifa(int, struct interface *,
const struct in_addr *, const struct in_addr *, const struct in_addr *);
const struct in_addr *, const struct in_addr *, const struct in_addr *,
int);
void dhcp_drop(struct interface *, const char *);
void dhcp_start(struct interface *);
void dhcp_stop(struct interface *);
void dhcp_decline(struct interface *);
void dhcp_discover(void *);
void dhcp_inform(struct interface *);
void dhcp_probe(struct interface *);
void dhcp_bind(struct interface *, struct arp_state *);
void dhcp_reboot_newopts(struct interface *, unsigned long long);
void dhcp_close(struct interface *);

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: dhcp6.c,v 1.11 2015/03/28 14:16:52 christos Exp $");
__RCSID("$NetBSD: dhcp6.c,v 1.12 2015/05/02 15:18:36 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -219,7 +219,7 @@ dhcp6_makevendor(struct dhcp6_option *o, const struct interface *ifp)
}
static const struct dhcp6_option *
dhcp6_findoption(unsigned int code, const uint8_t *d, size_t len)
dhcp6_findoption(uint16_t code, const uint8_t *d, size_t len)
{
const struct dhcp6_option *o;
size_t ol;
@ -283,7 +283,7 @@ dhcp6_getoption(struct dhcpcd_ctx *ctx,
}
static const struct dhcp6_option *
dhcp6_getmoption(unsigned int code, const struct dhcp6_message *m, size_t len)
dhcp6_getmoption(uint16_t code, const struct dhcp6_message *m, size_t len)
{
if (len < sizeof(*m)) {
@ -490,6 +490,21 @@ dhcp6_delegateaddr(struct in6_addr *addr, struct interface *ifp,
return sla->prefix_len;
}
int
dhcp6_has_public_addr(const struct interface *ifp)
{
const struct dhcp6_state *state = D6_CSTATE(ifp);
const struct ipv6_addr *ia;
if (state == NULL)
return 0;
TAILQ_FOREACH(ia, &state->addrs, next) {
if (ipv6_publicaddr(ia))
return 1;
}
return 0;
}
static int
dhcp6_makemessage(struct interface *ifp)
{
@ -497,9 +512,9 @@ dhcp6_makemessage(struct interface *ifp)
struct dhcp6_message *m;
struct dhcp6_option *o, *so, *eo;
const struct dhcp6_option *si, *unicast;
size_t l, n, len, ml, auth_len;
size_t l, n, len, ml;
uint8_t u8, type;
uint16_t u16, n_options;
uint16_t u16, n_options, auth_len;
struct if_options *ifo;
const struct dhcp_opt *opt, *opt2;
uint8_t IA, *p;
@ -704,17 +719,22 @@ dhcp6_makemessage(struct interface *ifp)
return -1;
}
auth_len = 0;
if (ifo->auth.options & DHCPCD_AUTH_SEND) {
auth_len = (size_t)dhcp_auth_encode(&ifo->auth,
ssize_t alen = dhcp_auth_encode(&ifo->auth,
state->auth.token, NULL, 0, 6, type, NULL, 0);
if ((ssize_t)auth_len == -1) {
if (alen != -1 && alen > UINT16_MAX) {
errno = ERANGE;
alen = -1;
}
if (alen == -1)
logger(ifp->ctx, LOG_ERR,
"%s: dhcp_auth_encode: %m", ifp->name);
auth_len = 0;
} else if (auth_len != 0)
else if (alen != 0) {
auth_len = (uint16_t)alen;
len += sizeof(*o) + auth_len;
} else
auth_len = 0; /* appease GCC */
}
}
state->send = malloc(len);
if (state->send == NULL)
@ -816,9 +836,9 @@ dhcp6_makemessage(struct interface *ifp)
eo->len = htons(eo->len);
}
u32 = (uint32_t)(ntohs(o->len) + sizeof(*so)
u16 = (uint16_t)(ntohs(o->len) + sizeof(*so)
+ ntohs(so->len));
o->len = htons((uint16_t)u32);
o->len = htons(u16);
} else {
so->code = htons(D6_OPTION_IA_ADDR);
so->len = sizeof(ap->addr) +
@ -1134,7 +1154,7 @@ logsend:
cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(pi));
memset(&pi, 0, sizeof(pi));
pi.ipi6_ifindex = CAST_IPI6_IFINDEX(ifp->index);
pi.ipi6_ifindex = ifp->index;
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
if (sendmsg(ctx->dhcp_fd, &ctx->sndhdr, 0) == -1) {
@ -1241,9 +1261,6 @@ dhcp6_dadcompleted(const struct interface *ifp)
const struct ipv6_addr *ap;
state = D6_CSTATE(ifp);
if (!TAILQ_FIRST(&state->addrs))
return 0;
TAILQ_FOREACH(ap, &state->addrs, next) {
if (ap->flags & IPV6_AF_ADDED &&
!(ap->flags & IPV6_AF_DADCOMPLETED))
@ -2126,7 +2143,7 @@ dhcp6_writelease(const struct interface *ifp)
}
static int
dhcp6_readlease(struct interface *ifp)
dhcp6_readlease(struct interface *ifp, int validate)
{
struct dhcp6_state *state;
struct stat st;
@ -2135,43 +2152,37 @@ dhcp6_readlease(struct interface *ifp)
const struct dhcp6_option *o;
struct timespec acquired;
time_t now;
int retval;
state = D6_STATE(ifp);
if (stat(state->leasefile, &st) == -1) {
if (errno == ENOENT)
return 0;
logger(ifp->ctx, LOG_ERR, "%s: %s: %m", ifp->name, __func__);
if (stat(state->leasefile, &st) == -1)
return -1;
}
logger(ifp->ctx, LOG_DEBUG, "%s: reading lease `%s'",
ifp->name, state->leasefile);
if (st.st_size > UINT32_MAX) {
logger(ifp->ctx, LOG_ERR, "%s: file too big", ifp->name);
errno = E2BIG;
return -1;
}
state->new = malloc((size_t)st.st_size);
if (state->new == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
if ((fd = open(state->leasefile, O_RDONLY)) == -1)
return -1;
}
if ((state->new = malloc((size_t)st.st_size)) == NULL)
return -1;
retval = -1;
state->new_len = (size_t)st.st_size;
fd = open(state->leasefile, O_RDONLY);
if (fd == -1) {
logger(ifp->ctx, LOG_ERR, "%s: %s: %s: %m",
ifp->name, __func__, state->leasefile);
return -1;
}
bytes = read(fd, state->new, state->new_len);
close(fd);
if (bytes != (ssize_t)state->new_len) {
logger(ifp->ctx, LOG_ERR, "%s: read: %m", __func__);
if (bytes != (ssize_t)state->new_len)
goto ex;
/* If not validating IA's and if they have expired,
* skip to the auth check. */
if (!validate) {
fd = 0;
goto auth;
}
if ((now = time(NULL)) == -1) {
logger(ifp->ctx, LOG_ERR, "%s: time: %m", __func__);
if ((now = time(NULL)) == -1)
goto ex;
}
get_monotonic(&acquired);
acquired.tv_sec -= now - st.st_mtime;
@ -2189,10 +2200,14 @@ dhcp6_readlease(struct interface *ifp)
logger(ifp->ctx,
LOG_DEBUG,"%s: discarding expired lease",
ifp->name);
retval = 0;
goto ex;
}
}
auth:
retval = 0;
/* Authenticate the message */
o = dhcp6_getmoption(D6_OPTION_AUTH, state->new, state->new_len);
if (o) {
@ -2228,10 +2243,9 @@ ex:
state->new_len = 0;
if (!(ifp->ctx->options & DHCPCD_DUMPLEASE))
unlink(state->leasefile);
return 0;
return retval;
}
static void
dhcp6_startinit(struct interface *ifp)
{
@ -2261,11 +2275,13 @@ dhcp6_startinit(struct interface *ifp)
!(has_ta && !has_non_ta) &&
ifp->options->reboot != 0)
{
r = dhcp6_readlease(ifp);
if (r == -1)
logger(ifp->ctx, LOG_ERR, "%s: dhcp6_readlease: %s: %m",
ifp->name, state->leasefile);
else if (r != 0) {
r = dhcp6_readlease(ifp, 1);
if (r == -1) {
if (errno != ENOENT)
logger(ifp->ctx, LOG_ERR,
"%s: dhcp6_readlease: %s: %m",
ifp->name, state->leasefile);
} else if (r != 0) {
/* RFC 3633 section 12.1 */
if (dhcp6_hasprefixdelegation(ifp))
dhcp6_startrebind(ifp);
@ -2355,9 +2371,6 @@ dhcp6_script_try_run(struct interface *ifp, int delegated)
int completed;
state = D6_STATE(ifp);
if (!TAILQ_FIRST(&state->addrs))
return;
completed = 1;
/* If all addresses have completed DAD run the script */
TAILQ_FOREACH(ap, &state->addrs, next) {
@ -2409,7 +2422,7 @@ dhcp6_delegate_prefix(struct interface *ifp)
if (strcmp(sla->ifname, ia->sla[j].ifname) == 0)
break;
if (j >= i &&
if_find(ifp->ctx, sla->ifname) == NULL)
if_find(ifp->ctx->ifaces, sla->ifname) == NULL)
{
logger(ifp->ctx, LOG_INFO,
"%s: loading for delegation", sla->ifname);
@ -2717,7 +2730,7 @@ dhcp6_handledata(void *arg)
i++, opt++)
{
if (has_option_mask(ifo->requiremask6, opt->option) &&
dhcp6_getmoption(opt->option, r, len) == NULL)
dhcp6_getmoption((uint16_t)opt->option, r, len) == NULL)
{
logger(ifp->ctx, LOG_WARNING,
"%s: reject DHCPv6 (no option %s) from %s",
@ -2725,7 +2738,7 @@ dhcp6_handledata(void *arg)
return;
}
if (has_option_mask(ifo->rejectmask6, opt->option) &&
dhcp6_getmoption(opt->option, r, len))
dhcp6_getmoption((uint16_t)opt->option, r, len))
{
logger(ifp->ctx, LOG_WARNING,
"%s: reject DHCPv6 (option %s) from %s",
@ -2767,6 +2780,8 @@ dhcp6_handledata(void *arg)
case DHCP6_REPLY:
switch(state->state) {
case DH6S_INFORM:
if (dhcp6_checkstatusok(ifp, r, NULL, len) == -1)
return;
/* RFC4242 */
o = dhcp6_getmoption(D6_OPTION_INFO_REFRESH_TIME,
r, len);
@ -3027,6 +3042,7 @@ recv:
eloop_timeout_add_sec(ifp->ctx->eloop,
(time_t)state->expire, dhcp6_startexpire, ifp);
ipv6nd_runignoredra(ifp);
ipv6_addaddrs(&state->addrs);
dhcp6_delegate_prefix(ifp);
@ -3567,7 +3583,6 @@ int
dhcp6_dump(struct interface *ifp)
{
struct dhcp6_state *state;
int r;
ifp->if_data[IF_DATA_DHCP6] = state = calloc(1, sizeof(*state));
if (state == NULL) {
@ -3578,14 +3593,9 @@ dhcp6_dump(struct interface *ifp)
dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
AF_INET6, ifp,
ifp->options->options & DHCPCD_PFXDLGONLY ? ".pd" : "");
r = dhcp6_readlease(ifp);
if (r == -1) {
if (errno == ENOENT)
logger(ifp->ctx, LOG_ERR,
"%s: no lease to dump", ifp->name);
else
logger(ifp->ctx, LOG_ERR,
"%s: dhcp6_readlease: %m", ifp->name);
if (dhcp6_readlease(ifp, 0) == -1) {
logger(ifp->ctx, LOG_ERR, "%s: %s: %m",
*ifp->name ? ifp->name : state->leasefile, __func__);
return -1;
}
state->reason = "DUMP6";

View File

@ -1,4 +1,4 @@
/* $NetBSD: dhcp6.h,v 1.8 2015/03/26 10:26:37 roy Exp $ */
/* $NetBSD: dhcp6.h,v 1.9 2015/05/02 15:18:36 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -237,6 +237,7 @@ void dhcp6_printoptions(const struct dhcpcd_ctx *,
struct ipv6_addr *dhcp6_findaddr(struct dhcpcd_ctx *, const struct in6_addr *,
short);
size_t dhcp6_find_delegates(struct interface *);
int dhcp6_has_public_addr(const struct interface *);
int dhcp6_start(struct interface *, enum DH6S);
void dhcp6_reboot(struct interface *);
ssize_t dhcp6_env(char **, const char *, const struct interface *,

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: dhcpcd.c,v 1.23 2015/03/26 10:26:37 roy Exp $");
__RCSID("$NetBSD: dhcpcd.c,v 1.24 2015/05/02 15:18:36 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -315,6 +315,17 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
#endif
}
static void
dhcpcd_drop(struct interface *ifp, int stop)
{
dhcp6_drop(ifp, stop ? NULL : "EXPIRE6");
ipv6nd_drop(ifp);
ipv6_drop(ifp);
dhcp_drop(ifp, stop ? "STOP" : "EXPIRE");
arp_close(ifp);
}
static void
stop_interface(struct interface *ifp)
{
@ -324,11 +335,7 @@ stop_interface(struct interface *ifp)
logger(ctx, LOG_INFO, "%s: removing interface", ifp->name);
ifp->options->options |= DHCPCD_STOPPING;
dhcp6_drop(ifp, NULL);
ipv6nd_drop(ifp);
ipv6_drop(ifp);
dhcp_drop(ifp, "STOP");
arp_close(ifp);
dhcpcd_drop(ifp, 1);
if (ifp->options->options & DHCPCD_DEPARTED)
script_runreason(ifp, "DEPARTED");
else
@ -381,7 +388,7 @@ configure_interface1(struct interface *ifp)
ifo->options &= ~(DHCPCD_IPV6RS | DHCPCD_DHCP6);
if (ifo->options & DHCPCD_SLAACPRIVATE &&
!(ifp->ctx->options & DHCPCD_TEST))
!(ifp->ctx->options & (DHCPCD_DUMPLEASE | DHCPCD_TEST)))
ifo->options |= DHCPCD_IPV6RA_OWN;
/* If we're a psuedo interface, ensure we disable as much as we can */
@ -389,7 +396,9 @@ configure_interface1(struct interface *ifp)
ifp->options->options &= ~(DHCPCD_IPV4 | DHCPCD_IPV6RS);
/* We want to disable kernel interface RA as early as possible. */
if (ifo->options & DHCPCD_IPV6RS) {
if (ifo->options & DHCPCD_IPV6RS &&
!(ifp->ctx->options & DHCPCD_DUMPLEASE))
{
/* If not doing any DHCP, disable the RDNSS requirement. */
if (!(ifo->options & (DHCPCD_DHCP | DHCPCD_DHCP6)))
ifo->options &= ~DHCPCD_IPV6RA_REQRDNSS;
@ -399,7 +408,8 @@ configure_interface1(struct interface *ifp)
ifp->options->options & DHCPCD_IPV6RA_OWN ? 1 : 0);
if (ra_global == -1 || ra_iface == -1)
ifo->options &= ~DHCPCD_IPV6RS;
else if (ra_iface == 0 && !(ifp->ctx->options & DHCPCD_TEST))
else if (ra_iface == 0 &&
!(ifp->ctx->options & DHCPCD_TEST))
ifo->options |= DHCPCD_IPV6RA_OWN;
}
@ -541,6 +551,7 @@ dhcpcd_selectprofile(struct interface *ifp, const char *profile)
ifp->name, profile);
} else
*ifp->profile = '\0';
free_options(ifp->options);
ifp->options = ifo;
if (profile)
@ -552,11 +563,20 @@ static void
configure_interface(struct interface *ifp, int argc, char **argv,
unsigned long long options)
{
time_t old;
old = ifp->options ? ifp->options->mtime : 0;
dhcpcd_selectprofile(ifp, NULL);
add_options(ifp->ctx, ifp->name, ifp->options, argc, argv);
ifp->options->options |= options;
configure_interface1(ifp);
/* If the mtime has changed drop any old lease */
if (ifp->options && old != 0 && ifp->options->mtime != old) {
logger(ifp->ctx, LOG_WARNING,
"%s: confile file changed, expiring leases", ifp->name);
dhcpcd_drop(ifp, 0);
}
}
static void
@ -584,7 +604,7 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags,
{
struct interface *ifp;
ifp = if_find(ctx, ifname);
ifp = if_find(ctx->ifaces, ifname);
if (ifp == NULL || !(ifp->options->options & DHCPCD_LINK))
return;
@ -617,18 +637,22 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags,
} else if (carrier == LINK_DOWN || (ifp->flags & IFF_UP) == 0) {
if (ifp->carrier != LINK_DOWN) {
if (ifp->carrier == LINK_UP)
logger(ctx, LOG_INFO, "%s: carrier lost", ifp->name);
logger(ctx, LOG_INFO, "%s: carrier lost",
ifp->name);
ifp->carrier = LINK_DOWN;
script_runreason(ifp, "NOCARRIER");
dhcp6_drop(ifp, "EXPIRE6");
ipv6nd_drop(ifp);
ipv6_drop(ifp);
dhcp_drop(ifp, "EXPIRE");
#ifdef NOCARRIER_PRESERVE_IP
arp_close(ifp);
ipv4_buildroutes(ifp->ctx);
ipv6nd_expire(ifp, 0);
#else
dhcpcd_drop(ifp, 0);
#endif
}
} else if (carrier == LINK_UP && ifp->flags & IFF_UP) {
if (ifp->carrier != LINK_UP) {
logger(ctx, LOG_INFO, "%s: carrier acquired", ifp->name);
logger(ctx, LOG_INFO, "%s: carrier acquired",
ifp->name);
ifp->carrier = LINK_UP;
#if !defined(__linux__) && !defined(__NetBSD__)
/* BSD does not emit RTM_NEWADDR or RTM_CHGADDR when the
@ -636,10 +660,30 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx *ctx, int carrier, unsigned int flags,
* through the disovery process to work it out. */
dhcpcd_handleinterface(ctx, 0, ifp->name);
#endif
if (ifp->wireless)
if (ifp->wireless) {
uint8_t ossid[IF_SSIDSIZE];
#ifdef NOCARRIER_PRESERVE_IP
size_t olen;
olen = ifp->ssid_len;
#endif
memcpy(ossid, ifp->ssid, ifp->ssid_len);
if_getssid(ifp);
#ifdef NOCARRIER_PRESERVE_IP
/* If we changed SSID network, drop leases */
if (ifp->ssid_len != olen ||
memcmp(ifp->ssid, ossid, ifp->ssid_len))
dhcpcd_drop(ifp, 0);
#endif
}
dhcpcd_initstate(ifp, 0);
script_runreason(ifp, "CARRIER");
#ifdef NOCARRIER_PRESERVE_IP
/* Set any IPv6 Routers we remembered to expire
* faster than they would normally as we
* maybe on a new network. */
ipv6nd_expire(ifp, RTR_CARRIER_EXPIRE);
#endif
/* RFC4941 Section 3.5 */
if (ifp->options->options & DHCPCD_IPV6RA_OWN)
ipv6_gentempifid(ifp);
@ -900,7 +944,7 @@ dhcpcd_handleinterface(void *arg, int action, const char *ifname)
ctx = arg;
if (action == -1) {
ifp = if_find(ctx, ifname);
ifp = if_find(ctx->ifaces, ifname);
if (ifp == NULL) {
errno = ESRCH;
return -1;
@ -931,7 +975,7 @@ dhcpcd_handleinterface(void *arg, int action, const char *ifname)
continue;
i = 0;
/* Check if we already have the interface */
iff = if_find(ctx, ifp->name);
iff = if_find(ctx->ifaces, ifp->name);
if (iff) {
logger(ctx, LOG_DEBUG, "%s: interface updated", iff->name);
/* The flags and hwaddr could have changed */
@ -970,7 +1014,7 @@ dhcpcd_handlehwaddr(struct dhcpcd_ctx *ctx, const char *ifname,
struct interface *ifp;
char buf[sizeof(ifp->hwaddr) * 3];
ifp = if_find(ctx, ifname);
ifp = if_find(ctx->ifaces, ifname);
if (ifp == NULL)
return;
@ -1033,7 +1077,7 @@ reconf_reboot(struct dhcpcd_ctx *ctx, int action, int argc, char **argv, int oi)
while ((ifp = TAILQ_FIRST(ifs))) {
TAILQ_REMOVE(ifs, ifp, next);
ifn = if_find(ctx, ifp->name);
ifn = if_find(ctx->ifaces, ifp->name);
if (ifn) {
if (action)
if_reboot(ifn, argc, argv);
@ -1286,7 +1330,7 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd,
return 0;
}
for (oi = optind; oi < argc; oi++) {
if ((ifp = if_find(ctx, argv[oi])) == NULL)
if ((ifp = if_find(ctx->ifaces, argv[oi])) == NULL)
continue;
if (do_release) {
ifp->options->options |= DHCPCD_RELEASE;
@ -1687,7 +1731,6 @@ main(int argc, char **argv)
}
}
if (ctx.options & DHCPCD_MASTER) {
if (control_start(&ctx, NULL) == -1)
logger(&ctx, LOG_ERR, "control_start: %m");
@ -1740,7 +1783,7 @@ main(int argc, char **argv)
goto exit_failure;
}
for (i = 0; i < ctx.ifc; i++) {
if (if_find(&ctx, ctx.ifv[i]) == NULL)
if (if_find(ctx.ifaces, ctx.ifv[i]) == NULL)
logger(&ctx, LOG_ERR,
"%s: interface not found or invalid",
ctx.ifv[i]);

View File

@ -1,4 +1,4 @@
.\" $NetBSD: dhcpcd.conf.5.in,v 1.19 2015/03/26 10:26:37 roy Exp $
.\" $NetBSD: dhcpcd.conf.5.in,v 1.20 2015/05/02 15:18:37 roy Exp $
.\" Copyright (c) 2006-2015 Roy Marples
.\" All rights reserved
.\"
@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd March 17, 2015
.Dd April 6, 2015
.Dt DHCPCD.CONF 5
.Os
.Sh NAME
@ -111,6 +111,11 @@ Only accept packets from
is ignored if
.Ic whitelist
is set.
.It Ic bootp
Be a BOOTP client.
Basically, this just doesn't send a DHCP Message Type option and will only
interact with a BOOTP server.
All other DHCP options still work.
.It Ic broadcast
Instructs the DHCP server to broadcast replies back to the client.
Normally this is only set for non Ethernet interfaces,
@ -369,6 +374,12 @@ Each time dhcpcd receives an IPv6 Router Adveristment, dhcpcd will manage
the default route only.
This allows dhcpcd to prefer an interface for outbound traffic based on metric
and/or user selection rather than the kernel.
.It Ic ipv6ra_accept_nopublic
Some IPv6 routers advertise themselves as a default router without any
public prefixes or managed addresses.
Generally, this is incorrect behaviour and
.Nm dhcpcd
will ignore the advertisement unless this option is turned on.
.It Ic ipv6rs
Enables IPv6 Router Advertisment solicitation.
This is on by default, but is documented here in the case where it is disabled

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: eloop.c,v 1.9 2015/03/26 10:26:37 roy Exp $");
__RCSID("$NetBSD: eloop.c,v 1.10 2015/05/02 15:18:37 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -28,9 +28,6 @@
* SUCH DAMAGE.
*/
/* Needed for ppoll(2) */
#define _GNU_SOURCE
#include <sys/time.h>
#include <errno.h>

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: if-bsd.c,v 1.19 2015/03/27 18:51:08 christos Exp $");
__RCSID("$NetBSD: if-bsd.c,v 1.20 2015/05/02 15:18:37 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -284,7 +284,7 @@ if_findsdl(struct dhcpcd_ctx *ctx, struct sockaddr_dl *sdl)
char ifname[IF_NAMESIZE];
memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen);
ifname[sdl->sdl_nlen] = '\0';
return if_find(ctx, ifname);
return if_find(ctx->ifaces, ifname);
}
return NULL;
}
@ -294,7 +294,7 @@ if_findsdl(struct dhcpcd_ctx *ctx, struct sockaddr_dl *sdl)
const char *if_pfname = "Berkley Packet Filter";
int
if_openrawsocket(struct interface *ifp, int protocol)
if_openrawsocket(struct interface *ifp, uint16_t protocol)
{
struct dhcp_state *state;
int fd = -1;
@ -378,7 +378,7 @@ eexit:
}
ssize_t
if_sendrawpacket(const struct interface *ifp, int protocol,
if_sendrawpacket(const struct interface *ifp, uint16_t protocol,
const void *data, size_t len)
{
struct iovec iov[2];
@ -388,7 +388,7 @@ if_sendrawpacket(const struct interface *ifp, int protocol,
memset(&hw, 0, ETHER_HDR_LEN);
memset(&hw.ether_dhost, 0xff, ETHER_ADDR_LEN);
hw.ether_type = htons((uint16_t)protocol);
hw.ether_type = htons(protocol);
iov[0].iov_base = &hw;
iov[0].iov_len = ETHER_HDR_LEN;
iov[1].iov_base = UNCONST(data);
@ -404,7 +404,7 @@ if_sendrawpacket(const struct interface *ifp, int protocol,
/* BPF requires that we read the entire buffer.
* So we pass the buffer in the API so we can loop on >1 packet. */
ssize_t
if_readrawpacket(struct interface *ifp, int protocol,
if_readrawpacket(struct interface *ifp, uint16_t protocol,
void *data, size_t len, int *flags)
{
int fd;
@ -520,7 +520,7 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct rt_msghdr *rtm)
COPYOUT(rt->gate, rti_info[RTAX_GATEWAY]);
if (rtm->rtm_index)
rt->iface = if_findindex(ctx, rtm->rtm_index);
rt->iface = if_findindex(ctx->ifaces, rtm->rtm_index);
else if (rtm->rtm_addrs & RTA_IFP) {
struct sockaddr_dl *sdl;
@ -549,7 +549,6 @@ if_route(unsigned char cmd, const struct rt *rt)
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_dl sdl;
struct sockaddr_storage ss;
} su;
struct rtm
{
@ -609,8 +608,8 @@ if_route(unsigned char cmd, const struct rt *rt)
#endif
}
}
if (rt->dest.s_addr == rt->gate.s_addr &&
rt->net.s_addr == INADDR_BROADCAST)
if (rt->net.s_addr == htonl(INADDR_BROADCAST) &&
rt->gate.s_addr == htonl(INADDR_ANY))
{
#ifdef RTF_CLONING
/* We add a cloning network route for a single host.
@ -625,7 +624,7 @@ if_route(unsigned char cmd, const struct rt *rt)
rtm.hdr.rtm_flags |= RTF_HOST;
#endif
} else if (rt->gate.s_addr == htonl(INADDR_LOOPBACK) &&
rt->net.s_addr == INADDR_BROADCAST)
rt->net.s_addr == htonl(INADDR_BROADCAST))
{
rtm.hdr.rtm_flags |= RTF_HOST | RTF_GATEWAY;
/* Going via lo0 so remove the interface flags */
@ -717,7 +716,40 @@ if_initrt(struct interface *ifp)
free(buf);
return 0;
}
#ifdef SIOCGIFAFLAG_IN
int
if_addrflags(const struct in_addr *addr, const struct interface *ifp)
{
int s, flags;
struct ifreq ifr;
struct sockaddr_in *sin;
s = socket(PF_INET, SOCK_DGRAM, 0);
flags = -1;
if (s != -1) {
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
sin = (struct sockaddr_in *)(void *)&ifr.ifr_addr;
sin->sin_family = AF_INET;
sin->sin_addr = *addr;
if (ioctl(s, SIOCGIFAFLAG_IN, &ifr) != -1)
flags = ifr.ifr_addrflags;
close(s);
}
return flags;
}
#else
int
if_addrflags(__unused const struct in_addr *addr,
__unused const struct interface *ifp)
{
errno = ENOTSUP;
return 0;
}
#endif
#endif /* INET */
#ifdef INET6
static void
@ -877,7 +909,7 @@ if_copyrt6(struct dhcpcd_ctx *ctx, struct rt6 *rt, struct rt_msghdr *rtm)
COPYOUT6(rt->gate, rti_info[RTAX_GATEWAY]);
if (rtm->rtm_index)
rt->iface = if_findindex(ctx, rtm->rtm_index);
rt->iface = if_findindex(ctx->ifaces, rtm->rtm_index);
else if (rtm->rtm_addrs & RTA_IFP) {
struct sockaddr_dl *sdl;
@ -905,7 +937,6 @@ if_route6(unsigned char cmd, const struct rt6 *rt)
struct sockaddr sa;
struct sockaddr_in6 sin;
struct sockaddr_dl sdl;
struct sockaddr_storage ss;
} su;
struct rtm
{
@ -1132,6 +1163,8 @@ if_managelink(struct dhcpcd_ctx *ctx)
struct rt6 rt6;
struct in6_addr ia6, net6;
struct sockaddr_in6 *sin6;
#endif
#if (defined(INET) && defined(IN_IFF_TENTATIVE)) || defined(INET6)
int ifa_flags;
#endif
@ -1161,7 +1194,8 @@ if_managelink(struct dhcpcd_ctx *ctx)
#endif
case RTM_IFINFO:
ifm = (struct if_msghdr *)(void *)p;
if ((ifp = if_findindex(ctx, ifm->ifm_index)) == NULL)
ifp = if_findindex(ctx->ifaces, ifm->ifm_index);
if (ifp == NULL)
break;
switch (ifm->ifm_data.ifi_link_state) {
case LINK_STATE_DOWN:
@ -1237,7 +1271,8 @@ if_managelink(struct dhcpcd_ctx *ctx)
case RTM_DELADDR: /* FALLTHROUGH */
case RTM_NEWADDR:
ifam = (struct ifa_msghdr *)(void *)p;
if ((ifp = if_findindex(ctx, ifam->ifam_index)) == NULL)
ifp = if_findindex(ctx->ifaces, ifam->ifam_index);
if (ifp == NULL)
break;
cp = (char *)(void *)(ifam + 1);
get_addrs(ifam->ifam_addrs, cp, rti_info);
@ -1264,9 +1299,15 @@ if_managelink(struct dhcpcd_ctx *ctx)
COPYOUT(rt.dest, rti_info[RTAX_IFA]);
COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
COPYOUT(rt.gate, rti_info[RTAX_BRD]);
if (rtm->rtm_type == RTM_NEWADDR) {
ifa_flags = if_addrflags(&rt.dest, ifp);
if (ifa_flags == -1)
break;
} else
ifa_flags = 0;
ipv4_handleifa(ctx, rtm->rtm_type,
NULL, ifp->name,
&rt.dest, &rt.net, &rt.gate);
&rt.dest, &rt.net, &rt.gate, ifa_flags);
break;
#endif
#ifdef INET6

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: if-options.c,v 1.22 2015/03/27 11:33:46 roy Exp $");
__RCSID("$NetBSD: if-options.c,v 1.23 2015/05/02 15:18:37 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -31,6 +31,7 @@
#define _WITH_GETLINE /* Stop FreeBSD bitching */
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <arpa/inet.h>
@ -100,6 +101,8 @@
#define O_IPV6RA_AUTOCONF O_BASE + 38
#define O_IPV6RA_NOAUTOCONF O_BASE + 39
#define O_REJECT O_BASE + 40
#define O_IPV6RA_ACCEPT_NOPUBLIC O_BASE + 41
#define O_BOOTP O_BASE + 42
const struct option cf_options[] = {
{"background", no_argument, NULL, 'b'},
@ -159,6 +162,7 @@ const struct option cf_options[] = {
{"ipv6ra_fork", no_argument, NULL, O_IPV6RA_FORK},
{"ipv6ra_own", no_argument, NULL, O_IPV6RA_OWN},
{"ipv6ra_own_default", no_argument, NULL, O_IPV6RA_OWN_D},
{"ipv6ra_accept_nopublic", no_argument, NULL, O_IPV6RA_ACCEPT_NOPUBLIC},
{"ipv4only", no_argument, NULL, '4'},
{"ipv6only", no_argument, NULL, '6'},
{"ipv4", no_argument, NULL, O_IPV4},
@ -191,6 +195,7 @@ const struct option cf_options[] = {
{"gateway", no_argument, NULL, O_GATEWAY},
{"ia_pd_mix", no_argument, NULL, O_PFXDLGMIX},
{"reject", required_argument, NULL, O_REJECT},
{"bootp", no_argument, NULL, O_BOOTP},
{NULL, 0, NULL, '\0'}
};
@ -1237,6 +1242,9 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
case O_IPV6RA_OWN_D:
ifo->options |= DHCPCD_IPV6RA_OWN_DEFAULT;
break;
case O_IPV6RA_ACCEPT_NOPUBLIC:
ifo->options |= DHCPCD_IPV6RA_ACCEPT_NOPUBLIC;
break;
case O_IPV6RA_AUTOCONF:
ifo->options |= DHCPCD_IPV6RA_AUTOCONF;
break;
@ -1955,6 +1963,9 @@ err_sla:
case O_PFXDLGMIX:
ifo->options |= DHCPCD_PFXDLGMIX;
break;
case O_BOOTP:
ifo->options |= DHCPCD_BOOTP;
break;
default:
return 0;
}
@ -2033,6 +2044,7 @@ read_config(struct dhcpcd_ctx *ctx,
{
struct if_options *ifo;
FILE *fp;
struct stat sb;
char *line, *buf, *option, *p;
size_t buflen;
ssize_t vlen;
@ -2189,6 +2201,8 @@ read_config(struct dhcpcd_ctx *ctx,
free(buf);
return ifo;
}
if (stat(ctx->cffile, &sb) == 0)
ifo->mtime = sb.st_mtime;
ldop = edop = NULL;
while ((line = get_line(&buf, &buflen, fp))) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: if-options.h,v 1.9 2015/03/26 10:26:37 roy Exp $ */
/* $NetBSD: if-options.h,v 1.10 2015/05/02 15:18:37 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -111,6 +111,12 @@
#define DHCPCD_PFXDLGMIX (1ULL << 53)
#define DHCPCD_IPV6RA_AUTOCONF (1ULL << 54)
#define DHCPCD_ROUTER_HOST_ROUTE_WARNED (1ULL << 55)
#define DHCPCD_IPV6RA_ACCEPT_NOPUBLIC (1ULL << 56)
#define DHCPCD_BOOTP (1ULL << 57)
#define DHCPCD_WARNINGS (DHCPCD_CSR_WARNED | \
DHCPCD_ROUTER_HOST_ROUTE_WARNED)
#define DHCPCD_CONF (DHCPCD_NOPFXDLG | DHCPCD_PFXDLGONLY)
extern const struct option cf_options[];
@ -140,6 +146,7 @@ struct vivco {
};
struct if_options {
time_t mtime;
uint8_t iaid[4];
int metric;
uint8_t requestmask[256 / NBBY];

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: if.c,v 1.12 2015/03/26 10:26:37 roy Exp $");
__RCSID("$NetBSD: if.c,v 1.13 2015/05/02 15:18:37 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -163,6 +163,67 @@ if_hasconf(struct dhcpcd_ctx *ctx, const char *ifname)
return 0;
}
static void if_learnaddrs1(struct dhcpcd_ctx *ctx, struct if_head *ifs,
struct ifaddrs *ifaddrs)
{
struct ifaddrs *ifa;
struct interface *ifp;
#ifdef INET
const struct sockaddr_in *addr, *net, *dst;
#endif
#ifdef INET6
struct sockaddr_in6 *sin6, *net6;
#endif
int ifa_flags;
for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
if ((ifp = if_find(ifs, ifa->ifa_name)) == NULL)
continue;
switch(ifa->ifa_addr->sa_family) {
#ifdef INET
case AF_INET:
addr = (const struct sockaddr_in *)
(void *)ifa->ifa_addr;
net = (const struct sockaddr_in *)
(void *)ifa->ifa_netmask;
if (ifa->ifa_flags & IFF_POINTOPOINT)
dst = (const struct sockaddr_in *)
(void *)ifa->ifa_dstaddr;
else
dst = NULL;
ifa_flags = if_addrflags(&addr->sin_addr, ifp);
ipv4_handleifa(ctx, RTM_NEWADDR, ifs, ifa->ifa_name,
&addr->sin_addr,
&net->sin_addr,
dst ? &dst->sin_addr : NULL, ifa_flags);
break;
#endif
#ifdef INET6
case AF_INET6:
sin6 = (struct sockaddr_in6 *)(void *)ifa->ifa_addr;
net6 = (struct sockaddr_in6 *)(void *)ifa->ifa_netmask;
#ifdef __KAME__
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
/* Remove the scope from the address */
sin6->sin6_addr.s6_addr[2] =
sin6->sin6_addr.s6_addr[3] = '\0';
#endif
ifa_flags = if_addrflags6(&sin6->sin6_addr, ifp);
if (ifa_flags != -1)
ipv6_handleifa(ctx, RTM_NEWADDR, ifs,
ifa->ifa_name,
&sin6->sin6_addr,
ipv6_prefixlen(&net6->sin6_addr),
ifa_flags);
break;
#endif
}
}
}
struct if_head *
if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
{
@ -174,15 +235,6 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
#ifdef __linux__
char ifn[IF_NAMESIZE];
#endif
#ifdef INET
const struct sockaddr_in *addr;
const struct sockaddr_in *net;
const struct sockaddr_in *dst;
#endif
#ifdef INET6
struct sockaddr_in6 *sin6, *net6;
int ifa_flags;
#endif
#ifdef AF_LINK
const struct sockaddr_dl *sdl;
#ifdef SIOCGIFPRIORITY
@ -478,55 +530,7 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
TAILQ_INSERT_TAIL(ifs, ifp, next);
}
for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
switch(ifa->ifa_addr->sa_family) {
#ifdef INET
case AF_INET:
addr = (const struct sockaddr_in *)
(void *)ifa->ifa_addr;
net = (const struct sockaddr_in *)
(void *)ifa->ifa_netmask;
if (ifa->ifa_flags & IFF_POINTOPOINT)
dst = (const struct sockaddr_in *)
(void *)ifa->ifa_dstaddr;
else
dst = NULL;
ipv4_handleifa(ctx, RTM_NEWADDR, ifs, ifa->ifa_name,
&addr->sin_addr,
&net->sin_addr,
dst ? &dst->sin_addr : NULL);
break;
#endif
#ifdef INET6
case AF_INET6:
TAILQ_FOREACH(ifp, ifs, next) {
if (strcmp(ifp->name, ifa->ifa_name) == 0)
break;
}
if (ifp == NULL)
break; /* Should be impossible */
sin6 = (struct sockaddr_in6 *)(void *)ifa->ifa_addr;
net6 = (struct sockaddr_in6 *)(void *)ifa->ifa_netmask;
#ifdef __KAME__
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
/* Remove the scope from the address */
sin6->sin6_addr.s6_addr[2] =
sin6->sin6_addr.s6_addr[3] = '\0';
#endif
ifa_flags = if_addrflags6(&sin6->sin6_addr, ifp);
if (ifa_flags != -1)
ipv6_handleifa(ctx, RTM_NEWADDR, ifs,
ifa->ifa_name,
&sin6->sin6_addr,
ipv6_prefixlen(&net6->sin6_addr),
ifa_flags);
break;
#endif
}
}
if_learnaddrs1(ctx, ifs, ifaddrs);
freeifaddrs(ifaddrs);
#ifdef SIOCGIFPRIORITY
@ -540,12 +544,13 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
}
static struct interface *
if_findindexname(struct dhcpcd_ctx *ctx, unsigned int idx, const char *name)
if_findindexname(struct if_head *ifaces, unsigned int idx, const char *name)
{
struct interface *ifp;
if (ctx != NULL && ctx->ifaces != NULL) {
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
if (ifaces != NULL) {
struct interface *ifp;
TAILQ_FOREACH(ifp, ifaces, next) {
if ((ifp->options == NULL ||
!(ifp->options->options & DHCPCD_PFXDLGONLY)) &&
((name && strcmp(ifp->name, name) == 0) ||
@ -556,21 +561,23 @@ if_findindexname(struct dhcpcd_ctx *ctx, unsigned int idx, const char *name)
return ifp;
}
}
errno = ESRCH;
return NULL;
}
struct interface *
if_find(struct dhcpcd_ctx *ctx, const char *name)
if_find(struct if_head *ifaces, const char *name)
{
return if_findindexname(ctx, 0, name);
return if_findindexname(ifaces, 0, name);
}
struct interface *
if_findindex(struct dhcpcd_ctx *ctx, unsigned int idx)
if_findindex(struct if_head *ifaces, unsigned int idx)
{
return if_findindexname(ctx, idx, NULL);
return if_findindexname(ifaces, idx, NULL);
}
int
@ -607,6 +614,12 @@ if_cmp(const struct interface *si, const struct interface *ti)
!(ti->options->options & DHCPCD_PFXDLGONLY))
return 1;
/* Check carrier status first */
if (si->carrier > ti->carrier)
return -1;
if (si->carrier < ti->carrier)
return 1;
if (D_STATE_RUNNING(si) && !D_STATE_RUNNING(ti))
return -1;
if (!D_STATE_RUNNING(si) && D_STATE_RUNNING(ti))
@ -621,16 +634,11 @@ if_cmp(const struct interface *si, const struct interface *ti)
return 1;
#ifdef INET
/* Special attention needed hereto due take states and IPv4LL. */
/* Special attention needed here due to states and IPv4LL. */
if ((r = ipv4_ifcmp(si, ti)) != 0)
return r;
#endif
/* Then carrier status. */
if (si->carrier > ti->carrier)
return -1;
if (si->carrier < ti->carrier)
return 1;
/* Finally, metric */
if (si->metric < ti->metric)
return -1;

View File

@ -1,4 +1,4 @@
/* $NetBSD: if.h,v 1.9 2015/03/26 10:26:37 roy Exp $ */
/* $NetBSD: if.h,v 1.10 2015/05/02 15:18:37 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -31,8 +31,14 @@
#define INTERFACE_H
#include <net/if.h>
#ifdef __FreeBSD__
#include <net/if_var.h>
#endif
#include <net/route.h> /* for RTM_ADD et all */
#include <netinet/in.h>
#ifdef BSD
#include <netinet/in_var.h> /* for IN_IFF_TENTATIVE et all */
#endif
/* Some systems have route metrics.
* OpenBSD route priority is not this. */
@ -42,6 +48,14 @@
# endif
#endif
/* Some systems have in-built IPv4 DAD.
* However, we need them to do DAD at carrier up as well. */
#ifdef IN_IFF_TENTATIVE
# ifdef __NetBSD__
# define NOCARRIER_PRESERVE_IP
# endif
#endif
#include "config.h"
#include "dhcpcd.h"
#include "ipv4.h"
@ -85,8 +99,8 @@
int if_setflag(struct interface *ifp, short flag);
#define if_up(ifp) if_setflag((ifp), (IFF_UP | IFF_RUNNING))
struct if_head *if_discover(struct dhcpcd_ctx *, int, char * const *);
struct interface *if_find(struct dhcpcd_ctx *, const char *);
struct interface *if_findindex(struct dhcpcd_ctx *, unsigned int);
struct interface *if_find(struct if_head *, const char *);
struct interface *if_findindex(struct if_head *, unsigned int);
void if_sortinterfaces(struct dhcpcd_ctx *);
void if_free(struct interface *);
int if_domtu(const char *, short int);
@ -114,10 +128,10 @@ int if_managelink(struct dhcpcd_ctx *);
#ifdef INET
extern const char *if_pfname;
int if_openrawsocket(struct interface *, int);
int if_openrawsocket(struct interface *, uint16_t);
ssize_t if_sendrawpacket(const struct interface *,
int, const void *, size_t);
ssize_t if_readrawpacket(struct interface *, int, void *, size_t, int *);
uint16_t, const void *, size_t);
ssize_t if_readrawpacket(struct interface *, uint16_t, void *, size_t, int *);
int if_address(const struct interface *,
const struct in_addr *, const struct in_addr *,
@ -127,6 +141,8 @@ int if_address(const struct interface *,
#define if_deladdress(ifp, addr, net) \
if_address(ifp, addr, net, NULL, -1)
int if_addrflags(const struct in_addr *, const struct interface *);
int if_route(unsigned char, const struct rt *rt);
int if_initrt(struct interface *);
#endif

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: ipv4.c,v 1.13 2015/03/27 11:33:46 roy Exp $");
__RCSID("$NetBSD: ipv4.c,v 1.14 2015/05/02 15:18:37 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -255,8 +255,8 @@ find_route(struct rt_head *rts, const struct rt *r, const struct rt *srt)
TAILQ_FOREACH(rt, rts, next) {
if (rt->dest.s_addr == r->dest.s_addr &&
#ifdef HAVE_ROUTE_METRIC
(srt || (!rt->iface ||
rt->iface->metric == r->iface->metric)) &&
(srt || (r->iface == NULL || rt->iface == NULL ||
rt->iface->metric == r->iface->metric)) &&
#endif
(!srt || srt != rt) &&
rt->net.s_addr == r->net.s_addr)
@ -273,18 +273,18 @@ desc_route(const char *cmd, const struct rt *rt)
const char *ifname = rt->iface ? rt->iface->name : NULL;
strlcpy(addr, inet_ntoa(rt->dest), sizeof(addr));
if (rt->gate.s_addr == INADDR_ANY)
logger(ctx, LOG_INFO, "%s: %s route to %s/%d",
ifname, cmd, addr, inet_ntocidr(rt->net));
else if (rt->gate.s_addr == rt->dest.s_addr &&
rt->net.s_addr == INADDR_BROADCAST)
if (rt->net.s_addr == htonl(INADDR_BROADCAST) &&
rt->gate.s_addr == htonl(INADDR_ANY))
logger(ctx, LOG_INFO, "%s: %s host route to %s",
ifname, cmd, addr);
else if (rt->gate.s_addr == htonl(INADDR_LOOPBACK) &&
rt->net.s_addr == INADDR_BROADCAST)
else if (rt->net.s_addr == htonl(INADDR_BROADCAST))
logger(ctx, LOG_INFO, "%s: %s host route to %s via %s",
ifname, cmd, addr, inet_ntoa(rt->gate));
else if (rt->dest.s_addr == INADDR_ANY && rt->net.s_addr == INADDR_ANY)
else if (rt->gate.s_addr == htonl(INADDR_ANY))
logger(ctx, LOG_INFO, "%s: %s route to %s/%d",
ifname, cmd, addr, inet_ntocidr(rt->net));
else if (rt->dest.s_addr == htonl(INADDR_ANY) &&
rt->net.s_addr == htonl(INADDR_ANY))
logger(ctx, LOG_INFO, "%s: %s default route via %s",
ifname, cmd, inet_ntoa(rt->gate));
else
@ -335,12 +335,6 @@ ipv4_handlert(struct dhcpcd_ctx *ctx, int cmd, struct rt *rt)
if (ctx->ipv4_kroutes == NULL)
return 0;
/* DHCP host routes have a gateway of the destination.
* We need to emulate that */
if (rt->gate.s_addr == INADDR_ANY &&
rt->net.s_addr == INADDR_BROADCAST)
rt->gate = rt->dest;
f = ipv4_findrt(ctx, rt, 1);
switch (cmd) {
case RTM_ADD:
@ -443,38 +437,34 @@ d_route(struct rt *rt)
return retval;
}
static struct rt *
make_subnet_route(const struct interface *ifp)
{
const struct dhcp_state *s;
struct rt *r;
s = D_CSTATE(ifp);
if (s->net.s_addr == INADDR_BROADCAST ||
s->net.s_addr == INADDR_ANY)
return NULL;
r = malloc(sizeof(*r));
if (r == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
return NULL;
}
r->dest.s_addr = s->addr.s_addr & s->net.s_addr;
r->net.s_addr = s->net.s_addr;
r->gate.s_addr = INADDR_ANY;
return r;
}
static struct rt_head *
add_subnet_route(struct rt_head *rt, const struct interface *ifp)
{
const struct dhcp_state *s;
struct rt *r;
if (rt == NULL) /* earlier malloc failed */
return NULL;
if ((r = make_subnet_route(ifp)) == NULL)
s = D_CSTATE(ifp);
/* Don't create a subnet route for these addresses */
if (s->net.s_addr == INADDR_ANY)
return rt;
#ifndef BSD
/* BSD adds a route in this instance */
if (s->net.s_addr == INADDR_BROADCAST)
return rt;
#endif
if ((r = malloc(sizeof(*r))) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
ipv4_freeroutes(rt);
return NULL;
}
r->dest.s_addr = s->addr.s_addr & s->net.s_addr;
r->net.s_addr = s->net.s_addr;
r->gate.s_addr = INADDR_ANY;
TAILQ_INSERT_HEAD(rt, r, next);
return rt;
}
@ -535,8 +525,8 @@ get_routes(struct interface *ifp)
}
/* Some DHCP servers add set host routes by setting the gateway
* to the assinged IP address. This differs from our notion of a host route
* where the gateway is the destination address, so we fix it. */
* to the assigned IP address or the destination address.
* We need to change this. */
static struct rt_head *
massage_host_routes(struct rt_head *rt, const struct interface *ifp)
{
@ -544,14 +534,18 @@ massage_host_routes(struct rt_head *rt, const struct interface *ifp)
if (rt) {
TAILQ_FOREACH(r, rt, next) {
if (r->gate.s_addr == D_CSTATE(ifp)->addr.s_addr &&
r->net.s_addr == INADDR_BROADCAST)
r->gate.s_addr = r->dest.s_addr;
if (r->gate.s_addr == D_CSTATE(ifp)->addr.s_addr ||
r->gate.s_addr == r->dest.s_addr)
{
r->gate.s_addr = htonl(INADDR_ANY);
r->net.s_addr = htonl(INADDR_BROADCAST);
}
}
}
return rt;
}
static struct rt_head *
add_destination_route(struct rt_head *rt, const struct interface *ifp)
{
@ -641,8 +635,8 @@ add_router_host_route(struct rt_head *rt, const struct interface *ifp)
return NULL;
}
rtn->dest.s_addr = rtp->gate.s_addr;
rtn->net.s_addr = INADDR_BROADCAST;
rtn->gate.s_addr = rtp->gate.s_addr;
rtn->net.s_addr = htonl(INADDR_BROADCAST);
rtn->gate.s_addr = htonl(INADDR_ANY);
TAILQ_INSERT_BEFORE(rtp, rtn, next);
}
return rt;
@ -729,32 +723,45 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx)
}
/* Remove old routes we used to manage */
TAILQ_FOREACH(rt, ctx->ipv4_routes, next) {
if (find_route(nrs, rt, NULL) == NULL &&
(rt->iface->options->options &
(DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
(DHCPCD_EXITING | DHCPCD_PERSISTENT))
d_route(rt);
if (ctx->ipv4_routes) {
TAILQ_FOREACH(rt, ctx->ipv4_routes, next) {
if (find_route(nrs, rt, NULL) == NULL &&
(rt->iface->options->options &
(DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
(DHCPCD_EXITING | DHCPCD_PERSISTENT))
d_route(rt);
}
}
ipv4_freeroutes(ctx->ipv4_routes);
ctx->ipv4_routes = nrs;
}
static int
delete_address1(struct interface *ifp,
int
ipv4_deladdr(struct interface *ifp,
const struct in_addr *addr, const struct in_addr *net)
{
struct dhcp_state *dstate;
int r;
struct ipv4_state *state;
struct ipv4_addr *ap;
logger(ifp->ctx, LOG_DEBUG, "%s: deleting IP address %s/%d",
ifp->name, inet_ntoa(*addr), inet_ntocidr(*net));
r = if_deladdress(ifp, addr, net);
if (r == -1 && errno != EADDRNOTAVAIL && errno != ENXIO &&
errno != ENODEV)
logger(ifp->ctx, LOG_ERR, "%s: %s: %m", ifp->name, __func__);
dstate = D_STATE(ifp);
if (dstate->addr.s_addr == addr->s_addr &&
dstate->net.s_addr == net->s_addr)
{
dstate->added = 0;
dstate->addr.s_addr = 0;
dstate->net.s_addr = 0;
}
state = IPV4_STATE(ifp);
TAILQ_FOREACH(ap, &state->addrs, next) {
if (ap->addr.s_addr == addr->s_addr &&
@ -780,10 +787,7 @@ delete_address(struct interface *ifp)
if (ifo->options & DHCPCD_INFORM ||
(ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
return 0;
r = delete_address1(ifp, &state->addr, &state->net);
state->added = 0;
state->addr.s_addr = 0;
state->net.s_addr = 0;
r = ipv4_deladdr(ifp, &state->addr, &state->net);
return r;
}
@ -809,26 +813,82 @@ ipv4_getstate(struct interface *ifp)
static int
ipv4_addaddr(struct interface *ifp, const struct dhcp_lease *lease)
{
int r;
struct ipv4_state *state;
struct ipv4_addr *ia;
if ((state = ipv4_getstate(ifp)) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: ipv4_getstate: %m", __func__);
return -1;
}
if (ifp->options->options & DHCPCD_NOALIAS) {
struct ipv4_state *state;
struct ipv4_addr *ap, *apn;
struct ipv4_addr *ian;
state = IPV4_STATE(ifp);
TAILQ_FOREACH_SAFE(ap, &state->addrs, next, apn) {
if (ap->addr.s_addr != lease->addr.s_addr)
delete_address1(ifp, &ap->addr, &ap->net);
TAILQ_FOREACH_SAFE(ia, &state->addrs, next, ian) {
if (ia->addr.s_addr != lease->addr.s_addr)
ipv4_deladdr(ifp, &ia->addr, &ia->net);
}
}
if ((ia = malloc(sizeof(*ia))) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
return -1;
}
logger(ifp->ctx, LOG_DEBUG, "%s: adding IP address %s/%d",
ifp->name, inet_ntoa(lease->addr),
inet_ntocidr(lease->net));
r = if_addaddress(ifp, &lease->addr, &lease->net, &lease->brd);
if (r == -1 && errno != EEXIST)
logger(ifp->ctx, LOG_ERR, "%s: if_addaddress: %m", __func__);
return r;
if (if_addaddress(ifp, &lease->addr, &lease->net, &lease->brd) == -1) {
if (errno != EEXIST)
logger(ifp->ctx, LOG_ERR, "%s: if_addaddress: %m",
__func__);
free(ia);
return -1;
}
ia->iface = ifp;
ia->addr = lease->addr;
ia->net = lease->net;
#ifdef IN_IFF_TENTATIVE
ia->addr_flags = IN_IFF_TENTATIVE;
#endif
TAILQ_INSERT_TAIL(&state->addrs, ia, next);
return 0;
}
static void
ipv4_finalisert(struct interface *ifp)
{
const struct dhcp_state *state = D_CSTATE(ifp);
/* Find any freshly added routes, such as the subnet route.
* We do this because we cannot rely on recieving the kernel
* notification right now via our link socket. */
if_initrt(ifp);
ipv4_buildroutes(ifp->ctx);
script_runreason(ifp, state->reason);
dhcpcd_daemonise(ifp->ctx);
}
void
ipv4_finaliseaddr(struct interface *ifp)
{
struct dhcp_state *state = D_STATE(ifp);
struct dhcp_lease *lease;
lease = &state->lease;
/* Delete the old address if different */
if (state->addr.s_addr != lease->addr.s_addr &&
state->addr.s_addr != 0 &&
ipv4_iffindaddr(ifp, &lease->addr, NULL))
delete_address(ifp);
state->added = STATE_ADDED;
state->defend = 0;
state->addr.s_addr = lease->addr.s_addr;
state->net.s_addr = lease->net.s_addr;
ipv4_finalisert(ifp);
}
void
@ -840,7 +900,6 @@ ipv4_applyaddr(void *arg)
struct dhcp_lease *lease;
struct if_options *ifo = ifp->options;
struct ipv4_addr *ap;
struct ipv4_state *istate = NULL;
int r;
if (state == NULL)
@ -902,13 +961,13 @@ ipv4_applyaddr(void *arg)
ifn->name);
state->addr.s_addr = lease->addr.s_addr;
state->net.s_addr = lease->net.s_addr;
goto routes;
ipv4_finalisert(ifp);
}
logger(ifp->ctx, LOG_INFO, "%s: preferring %s on %s",
ifn->name,
inet_ntoa(lease->addr),
ifp->name);
delete_address1(ifn, &nstate->addr, &nstate->net);
ipv4_deladdr(ifn, &nstate->addr, &nstate->net);
nstate->added = 0;
break;
}
@ -921,14 +980,14 @@ ipv4_applyaddr(void *arg)
continue;
ap = ipv4_iffindaddr(ifn, &lease->addr, NULL);
if (ap)
delete_address1(ifn, &ap->addr, &ap->net);
ipv4_deladdr(ifn, &ap->addr, &ap->net);
}
}
/* If the netmask is different, delete the addresss */
ap = ipv4_iffindaddr(ifp, &lease->addr, NULL);
if (ap && ap->net.s_addr != lease->net.s_addr)
delete_address1(ifp, &ap->addr, &ap->net);
ipv4_deladdr(ifp, &ap->addr, &ap->net);
if (ipv4_iffindaddr(ifp, &lease->addr, &lease->net))
logger(ifp->ctx, LOG_DEBUG,
@ -939,40 +998,26 @@ ipv4_applyaddr(void *arg)
r = ipv4_addaddr(ifp, lease);
if (r == -1 && errno != EEXIST)
return;
istate = ipv4_getstate(ifp);
ap = malloc(sizeof(*ap));
ap->iface = ifp;
ap->addr = lease->addr;
ap->net = lease->net;
ap->dst.s_addr = INADDR_ANY;
TAILQ_INSERT_TAIL(&istate->addrs, ap, next);
}
/* Now delete the old address if different */
if (state->addr.s_addr != lease->addr.s_addr &&
state->addr.s_addr != 0 &&
ipv4_iffindaddr(ifp, &lease->addr, NULL))
delete_address(ifp);
#ifdef IN_IFF_NOTUSEABLE
ap = ipv4_iffindaddr(ifp, &lease->addr, NULL);
if (ap == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: added address vanished",
ifp->name);
return;
} else if (ap->addr_flags & IN_IFF_NOTUSEABLE)
return;
#endif
state->added = STATE_ADDED;
state->defend = 0;
state->addr.s_addr = lease->addr.s_addr;
state->net.s_addr = lease->net.s_addr;
routes:
/* Find any freshly added routes, such as the subnet route.
* We do this because we cannot rely on recieving the kernel
* notification right now via our link socket. */
if_initrt(ifp);
ipv4_buildroutes(ifp->ctx);
script_runreason(ifp, state->reason);
ipv4_finaliseaddr(ifp);
}
void
ipv4_handleifa(struct dhcpcd_ctx *ctx,
int type, struct if_head *ifs, const char *ifname,
int cmd, struct if_head *ifs, const char *ifname,
const struct in_addr *addr, const struct in_addr *net,
const struct in_addr *dst)
const struct in_addr *dst, int flags)
{
struct interface *ifp;
struct ipv4_state *state;
@ -988,44 +1033,39 @@ ipv4_handleifa(struct dhcpcd_ctx *ctx,
errno = EINVAL;
return;
}
TAILQ_FOREACH(ifp, ifs, next) {
if (strcmp(ifp->name, ifname) == 0)
break;
}
if (ifp == NULL) {
errno = ESRCH;
if ((ifp = if_find(ifs, ifname)) == NULL)
return;
}
state = ipv4_getstate(ifp);
if (state == NULL) {
if ((state = ipv4_getstate(ifp)) == NULL) {
errno = ENOENT;
return;
}
ap = ipv4_iffindaddr(ifp, addr, net);
if (type == RTM_NEWADDR && ap == NULL) {
ap = malloc(sizeof(*ap));
if (cmd == RTM_NEWADDR) {
if (ap == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
return;
if ((ap = malloc(sizeof(*ap))) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
return;
}
ap->iface = ifp;
ap->addr = *addr;
ap->net = *net;
if (dst)
ap->dst.s_addr = dst->s_addr;
else
ap->dst.s_addr = INADDR_ANY;
TAILQ_INSERT_TAIL(&state->addrs, ap, next);
}
ap->addr_flags = flags;
} else if (cmd == RTM_DELADDR) {
if (ap) {
TAILQ_REMOVE(&state->addrs, ap, next);
free(ap);
}
ap->iface = ifp;
ap->addr.s_addr = addr->s_addr;
ap->net.s_addr = net->s_addr;
if (dst)
ap->dst.s_addr = dst->s_addr;
else
ap->dst.s_addr = INADDR_ANY;
TAILQ_INSERT_TAIL(&state->addrs, ap, next);
} else if (type == RTM_DELADDR) {
if (ap == NULL)
return;
TAILQ_REMOVE(&state->addrs, ap, next);
free(ap);
}
dhcp_handleifa(type, ifp, addr, net, dst);
dhcp_handleifa(cmd, ifp, addr, net, dst, flags);
arp_handleifa(cmd, ifp, addr, flags);
}
void

View File

@ -1,4 +1,4 @@
/* $NetBSD: ipv4.h,v 1.9 2015/03/26 10:26:37 roy Exp $ */
/* $NetBSD: ipv4.h,v 1.10 2015/05/02 15:18:37 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -32,6 +32,11 @@
#include "dhcpcd.h"
#ifdef IN_IFF_TENTATIVE
#define IN_IFF_NOTUSEABLE \
(IN_IFF_TENTATIVE | IN_IFF_DUPLICATED | IN_IFF_DETACHED)
#endif
struct rt {
TAILQ_ENTRY(rt) next;
struct in_addr dest;
@ -42,7 +47,7 @@ struct rt {
unsigned int metric;
#endif
struct in_addr src;
uint8_t flags;
unsigned int flags;
};
TAILQ_HEAD(rt_head, rt);
@ -52,6 +57,7 @@ struct ipv4_addr {
struct in_addr net;
struct in_addr dst;
struct interface *iface;
int addr_flags;
};
TAILQ_HEAD(ipv4_addrhead, ipv4_addr);
@ -77,6 +83,9 @@ int ipv4_addrexists(struct dhcpcd_ctx *, const struct in_addr *);
#define STATE_FAKE 0x02
void ipv4_buildroutes(struct dhcpcd_ctx *);
void ipv4_finaliseaddr(struct interface *);
int ipv4_deladdr(struct interface *ifp, const struct in_addr *,
const struct in_addr *);
void ipv4_applyaddr(void *);
int ipv4_handlert(struct dhcpcd_ctx *, int, struct rt *);
void ipv4_freerts(struct rt_head *);
@ -86,7 +95,8 @@ struct ipv4_addr *ipv4_iffindaddr(struct interface *,
struct ipv4_addr *ipv4_iffindlladdr(struct interface *);
struct ipv4_addr *ipv4_findaddr(struct dhcpcd_ctx *, const struct in_addr *);
void ipv4_handleifa(struct dhcpcd_ctx *, int, struct if_head *, const char *,
const struct in_addr *, const struct in_addr *, const struct in_addr *);
const struct in_addr *, const struct in_addr *, const struct in_addr *,
int);
void ipv4_freeroutes(struct rt_head *);

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: ipv4ll.c,v 1.9 2015/03/26 10:26:37 roy Exp $");
__RCSID("$NetBSD: ipv4ll.c,v 1.10 2015/05/02 15:18:37 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -108,11 +108,17 @@ static void
ipv4ll_probed(struct arp_state *astate)
{
struct dhcp_state *state = D_STATE(astate->iface);
struct dhcp_message *offer;
if (state->state == DHS_IPV4LL_BOUND) {
ipv4_finaliseaddr(astate->iface);
return;
}
if (state->state != DHS_BOUND) {
struct dhcp_message *offer;
/* A DHCP lease could have already been offered.
* Backup and replace once the IPv4LL addres is bound */
* Backup and replace once the IPv4LL address is bound */
offer = state->offer;
state->offer = ipv4ll_make_lease(astate->addr.s_addr);
if (state->offer == NULL)
@ -136,7 +142,11 @@ static void
ipv4ll_probe(void *arg)
{
#ifdef IN_IFF_TENTATIVE
ipv4ll_probed(arg);
#else
arp_probe(arg);
#endif
}
static void
@ -147,13 +157,14 @@ ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
fail = 0;
/* RFC 3927 2.2.1, Probe Conflict Detection */
if (amsg->sip.s_addr == astate->addr.s_addr ||
(amsg->sip.s_addr == 0 && amsg->tip.s_addr == astate->addr.s_addr))
if (amsg == NULL ||
(amsg->sip.s_addr == astate->addr.s_addr ||
(amsg->sip.s_addr == 0 && amsg->tip.s_addr == astate->addr.s_addr)))
fail = astate->addr.s_addr;
/* RFC 3927 2.5, Conflict Defense */
if (IN_LINKLOCAL(htonl(state->addr.s_addr)) &&
amsg->sip.s_addr == state->addr.s_addr)
amsg && amsg->sip.s_addr == state->addr.s_addr)
fail = state->addr.s_addr;
if (fail == 0)
@ -221,7 +232,7 @@ ipv4ll_start(void *arg)
initstate(seed, state->randomstate, sizeof(state->randomstate));
}
if ((astate = arp_new(ifp)) == NULL)
if ((astate = arp_new(ifp, NULL)) == NULL)
return;
state->arp_ipv4ll = astate;
@ -257,7 +268,11 @@ ipv4ll_start(void *arg)
}
if (astate->addr.s_addr == INADDR_ANY)
astate->addr.s_addr = ipv4ll_pick_addr(astate);
#ifdef IN_IFF_TENTATIVE
ipv4ll_probed(astate);
#else
arp_probe(astate);
#endif
}
void

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: ipv6.c,v 1.10 2015/03/27 11:33:46 roy Exp $");
__RCSID("$NetBSD: ipv6.c,v 1.11 2015/05/02 15:18:37 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -748,6 +748,14 @@ ipv6_addaddr(struct ipv6_addr *ap, const struct timespec *now)
return 0;
}
int
ipv6_publicaddr(const struct ipv6_addr *ia)
{
return (ia->prefix_pltime &&
(ia->addr.s6_addr[0] & 0xfe) != 0xc &&
!(ia->addr_flags & IN6_IFF_NOTUSEABLE));
}
struct ipv6_addr *
ipv6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr, short flags)
{
@ -1963,7 +1971,7 @@ static void
ipv6_build_ra_routes(struct ipv6_ctx *ctx, struct rt6_head *dnr, int expired)
{
struct rt6 *rt;
const struct ra *rap;
struct ra *rap;
const struct ipv6_addr *addr;
TAILQ_FOREACH(rap, ctx->ra_routers, next) {
@ -1977,7 +1985,8 @@ ipv6_build_ra_routes(struct ipv6_ctx *ctx, struct rt6_head *dnr, int expired)
}
}
if (rap->lifetime && rap->iface->options->options &
(DHCPCD_IPV6RA_OWN | DHCPCD_IPV6RA_OWN_DEFAULT))
(DHCPCD_IPV6RA_OWN | DHCPCD_IPV6RA_OWN_DEFAULT) &&
!rap->no_public_warned)
{
rt = make_router(rap);
if (rt)

View File

@ -1,4 +1,4 @@
/* $NetBSD: ipv6.h,v 1.11 2015/03/26 10:26:37 roy Exp $ */
/* $NetBSD: ipv6.h,v 1.12 2015/05/02 15:18:37 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -31,14 +31,8 @@
#define IPV6_H
#include <sys/uio.h>
#include <netinet/in.h>
#if defined(__linux__) && defined(__GLIBC__)
# define _LINUX_IN6_H
# include <linux/ipv6.h>
#endif
#include "config.h"
#include "dhcpcd.h"
@ -198,13 +192,6 @@ struct ipv6_state {
CMSG_SPACE(sizeof(int)))
/* ipi6.ifiindex differes between OS's so have a cast function */
#ifdef __linux__
#define CAST_IPI6_IFINDEX(idx) (int)(idx)
#else
#define CAST_IPI6_IFINDEX(idx) (idx)
#endif
#ifdef INET6
struct ipv6_ctx {
struct sockaddr_in6 from;
@ -248,6 +235,7 @@ void ipv6_handleifa(struct dhcpcd_ctx *ctx, int, struct if_head *,
const char *, const struct in6_addr *, uint8_t, int);
int ipv6_handleifa_addrs(int, struct ipv6_addrhead *,
const struct in6_addr *, int);
int ipv6_publicaddr(const struct ipv6_addr *);
const struct ipv6_addr *ipv6_iffindaddr(const struct interface *,
const struct in6_addr *);
struct ipv6_addr *ipv6_findaddr(struct dhcpcd_ctx *,

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: ipv6nd.c,v 1.22 2015/03/28 14:16:52 christos Exp $");
__RCSID("$NetBSD: ipv6nd.c,v 1.23 2015/05/02 15:18:37 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -57,9 +57,6 @@
/* Debugging Router Solicitations is a lot of spam, so disable it */
//#define DEBUG_RS
#define RTR_SOLICITATION_INTERVAL 4 /* seconds */
#define MAX_RTR_SOLICITATIONS 3 /* times */
#ifndef ND_OPT_RDNSS
#define ND_OPT_RDNSS 25
struct nd_opt_rdnss { /* RDNSS option RFC 6106 */
@ -298,7 +295,7 @@ ipv6nd_sendrsprobe(void *arg)
cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(pi));
memset(&pi, 0, sizeof(pi));
pi.ipi6_ifindex = CAST_IPI6_IFINDEX(ifp->index);
pi.ipi6_ifindex = ifp->index;
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
logger(ifp->ctx, LOG_DEBUG,
@ -314,9 +311,48 @@ ipv6nd_sendrsprobe(void *arg)
if (state->rsprobes++ < MAX_RTR_SOLICITATIONS)
eloop_timeout_add_sec(ifp->ctx->eloop,
RTR_SOLICITATION_INTERVAL, ipv6nd_sendrsprobe, ifp);
else
else {
logger(ifp->ctx, LOG_WARNING,
"%s: no IPv6 Routers available", ifp->name);
ipv6nd_drop(ifp);
dhcp6_drop(ifp, "EXPIRE6");
}
}
void
ipv6nd_expire(struct interface *ifp, uint32_t seconds)
{
struct ra *rap;
struct timespec now;
get_monotonic(&now);
TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
if (rap->iface == ifp) {
rap->received = now;
rap->expired = seconds ? 0 : 1;
if (seconds) {
struct ra_opt *rao;
struct ipv6_addr *ap;
rap->lifetime = seconds;
TAILQ_FOREACH(ap, &rap->addrs, next) {
if (ap->prefix_vltime) {
ap->prefix_vltime = seconds;
ap->prefix_pltime = seconds / 2;
}
}
ipv6_addaddrs(&rap->addrs);
TAILQ_FOREACH(rao, &rap->options, next) {
timespecclear(&rao->expire);
}
}
}
}
if (seconds)
ipv6nd_expirera(ifp);
else
ipv6_buildroutes(ifp->ctx);
}
static void
@ -410,7 +446,6 @@ void ipv6nd_freedrop_ra(struct ra *rap, int drop)
ipv6nd_free_opts(rap);
free(rap->data);
free(rap);
}
ssize_t
@ -676,6 +711,19 @@ try_script:
}
}
static int
ipv6nd_ra_has_public_addr(const struct ra *rap)
{
const struct ipv6_addr *ia;
TAILQ_FOREACH(ia, &rap->addrs, next) {
if (ia->flags & IPV6_AF_AUTOCONF &&
ipv6_publicaddr(ia))
return 1;
}
return 0;
}
static void
ipv6nd_handlera(struct dhcpcd_ctx *dctx, struct interface *ifp,
struct icmp6_hdr *icp, size_t len)
@ -763,6 +811,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *dctx, struct interface *ifp,
if (rap) {
free(rap->data);
rap->data_len = 0;
rap->no_public_warned = 0;
}
new_data = 1;
} else
@ -836,7 +885,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *dctx, struct interface *ifp,
}
if (olen > len) {
logger(ifp->ctx, LOG_ERR,
"%s: Option length exceeds message", ifp->name);
"%s: option length exceeds message", ifp->name);
break;
}
@ -1061,8 +1110,8 @@ ipv6nd_handlera(struct dhcpcd_ctx *dctx, struct interface *ifp,
STRING | ARRAY | DOMAIN,
(const uint8_t *)tmp, l);
} else
logger(ifp->ctx, LOG_ERR, "%s: %m",
__func__);
logger(ifp->ctx, LOG_ERR,
"%s: %m", __func__);
free(tmp);
}
}
@ -1123,6 +1172,19 @@ extra_opt:
if (new_rap)
add_router(ifp->ctx->ipv6, rap);
if (!ipv6nd_ra_has_public_addr(rap) &&
!(rap->iface->options->options & DHCPCD_IPV6RA_ACCEPT_NOPUBLIC) &&
(!(rap->flags & ND_RA_FLAG_MANAGED) ||
!dhcp6_has_public_addr(rap->iface)))
{
logger(rap->iface->ctx,
rap->no_public_warned ? LOG_DEBUG : LOG_WARNING,
"%s: ignoring RA from %s"
" (no public prefix, no managed address)",
rap->iface->name, rap->sfrom);
rap->no_public_warned = 1;
return;
}
if (ifp->ctx->options & DHCPCD_TEST) {
script_runreason(ifp, "TEST");
goto handle_flag;
@ -1170,6 +1232,34 @@ nodhcp6:
ipv6nd_expirera(ifp);
}
/* Run RA's we ignored becuase they had no public addresses
* This should only be called when DHCPv6 applies a public address */
void
ipv6nd_runignoredra(struct interface *ifp)
{
struct ra *rap;
TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
if (rap->iface == ifp &&
!rap->expired &&
rap->no_public_warned)
{
rap->no_public_warned = 0;
logger(rap->iface->ctx, LOG_INFO,
"%s: applying ignored RA from %s",
rap->iface->name, rap->sfrom);
if (ifp->ctx->options & DHCPCD_TEST) {
script_runreason(ifp, "TEST");
continue;
}
if (ipv6nd_scriptrun(rap))
return;
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
eloop_timeout_delete(ifp->ctx->eloop, NULL, rap);
}
}
}
int
ipv6nd_hasra(const struct interface *ifp)
{
@ -1336,13 +1426,14 @@ ipv6nd_expirera(void *arg)
struct ra *rap, *ran;
struct ra_opt *rao, *raon;
struct timespec now, lt, expire, next;
int expired, valid;
uint8_t expired, valid, validone;
ifp = arg;
get_monotonic(&now);
expired = 0;
timespecclear(&next);
validone = 0;
TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) {
if (rap->iface != ifp)
continue;
@ -1358,6 +1449,7 @@ ipv6nd_expirera(void *arg)
"%s: %s: router expired",
ifp->name, rap->sfrom);
rap->expired = expired = 1;
rap->lifetime = 0;
}
} else {
valid = 1;
@ -1410,6 +1502,8 @@ ipv6nd_expirera(void *arg)
* as well punt it. */
if (!valid && TAILQ_FIRST(&rap->addrs) == NULL)
ipv6nd_free_ra(rap);
else
validone = 1;
}
if (timespecisset(&next))
@ -1419,13 +1513,17 @@ ipv6nd_expirera(void *arg)
ipv6_buildroutes(ifp->ctx);
script_runreason(ifp, "ROUTERADVERT");
}
/* No valid routers? Kill any DHCPv6. */
if (!validone)
dhcp6_drop(ifp, "EXPIRE6");
}
void
ipv6nd_drop(struct interface *ifp)
{
struct ra *rap;
int expired = 0;
uint8_t expired = 0;
TAILQ_HEAD(rahead, ra) rtrs;
if (ifp->ctx->ipv6 == NULL)

View File

@ -1,4 +1,4 @@
/* $NetBSD: ipv6nd.h,v 1.10 2015/03/26 10:26:37 roy Exp $ */
/* $NetBSD: ipv6nd.h,v 1.11 2015/05/02 15:18:37 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -58,7 +58,8 @@ struct ra {
uint32_t mtu;
struct ipv6_addrhead addrs;
TAILQ_HEAD(, ra_opt) options;
int expired;
uint8_t expired;
uint8_t no_public_warned;
};
TAILQ_HEAD(ra_head, ra);
@ -74,6 +75,14 @@ struct rs_state {
#define MAX_RTR_SOLICITATION_DELAY 1 /* seconds */
#define MAX_UNICAST_SOLICIT 3 /* 3 transmissions */
#define RTR_SOLICITATION_INTERVAL 4 /* seconds */
#define MAX_RTR_SOLICITATIONS 3 /* times */
/* On carrier up, expire known routers after RTR_CARRIER_EXPIRE seconds. */
#define RTR_CARRIER_EXPIRE \
(MAX_RTR_SOLICITATION_DELAY + \
(MAX_RTR_SOLICITATIONS + 1) * \
RTR_SOLICITATION_INTERVAL)
#define MAX_REACHABLE_TIME 3600000 /* milliseconds */
#define REACHABLE_TIME 30000 /* milliseconds */
@ -95,9 +104,11 @@ ssize_t ipv6nd_free(struct interface *);
void ipv6nd_expirera(void *arg);
int ipv6nd_hasra(const struct interface *);
int ipv6nd_hasradhcp(const struct interface *);
void ipv6nd_runignoredra(struct interface *);
void ipv6nd_handleifa(struct dhcpcd_ctx *, int,
const char *, const struct in6_addr *, int);
int ipv6nd_dadcompleted(const struct interface *);
void ipv6nd_expire(struct interface *, uint32_t);
void ipv6nd_drop(struct interface *);
void ipv6nd_neighbour(struct dhcpcd_ctx *, struct in6_addr *, int);
#else

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: script.c,v 1.18 2015/03/26 10:26:37 roy Exp $");
__RCSID("$NetBSD: script.c,v 1.19 2015/05/02 15:18:37 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -89,14 +89,8 @@ if_printoptions(void)
printf(" - %s\n", *p);
}
#ifdef USE_SIGNALS
#define U
#else
#define U __unused
#endif
static int
exec_script(U const struct dhcpcd_ctx *ctx, char *const *argv, char *const *env)
#undef U
exec_script(const struct dhcpcd_ctx *ctx, char *const *argv, char *const *env)
{
pid_t pid;
posix_spawnattr_t attr;
@ -104,6 +98,8 @@ exec_script(U const struct dhcpcd_ctx *ctx, char *const *argv, char *const *env)
#ifdef USE_SIGNALS
short flags;
sigset_t defsigs;
#else
UNUSED(ctx);
#endif
/* posix_spawn is a safe way of executing another image