This commit is contained in:
roy 2015-07-09 10:15:34 +00:00
parent c4c68644a2
commit 76ccb05303
37 changed files with 1379 additions and 1125 deletions

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: arp.c,v 1.13 2015/05/16 23:31:32 roy Exp $");
__RCSID("$NetBSD: arp.c,v 1.14 2015/07/09 10:15:34 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -31,6 +31,8 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
@ -47,7 +49,6 @@
#include "if.h"
#include "ipv4.h"
#include "common.h"
#include "dhcp.h"
#include "dhcpcd.h"
#include "eloop.h"
#include "if.h"
@ -101,7 +102,7 @@ void
arp_report_conflicted(const struct arp_state *astate, const struct arp_msg *amsg)
{
if (amsg) {
if (amsg != NULL) {
char buf[HWADDR_LEN * 3];
logger(astate->iface->ctx, LOG_ERR,
@ -125,12 +126,12 @@ arp_packet(void *arg)
struct arphdr ar;
struct arp_msg arm;
ssize_t bytes;
struct dhcp_state *state;
struct iarp_state *state;
struct arp_state *astate, *astaten;
unsigned char *hw_s, *hw_t;
int flags;
state = D_STATE(ifp);
state = ARP_STATE(ifp);
flags = 0;
while (!(flags & RAW_EOF)) {
bytes = if_readrawpacket(ifp, ETHERTYPE_ARP,
@ -138,7 +139,7 @@ arp_packet(void *arg)
if (bytes == -1) {
logger(ifp->ctx, LOG_ERR,
"%s: arp if_readrawpacket: %m", ifp->name);
dhcp_close(ifp);
arp_close(ifp);
return;
}
/* We must have a full ARP header */
@ -189,17 +190,17 @@ arp_packet(void *arg)
static void
arp_open(struct interface *ifp)
{
struct dhcp_state *state;
struct iarp_state *state;
state = D_STATE(ifp);
if (state->arp_fd == -1) {
state->arp_fd = if_openrawsocket(ifp, ETHERTYPE_ARP);
if (state->arp_fd == -1) {
state = ARP_STATE(ifp);
if (state->fd == -1) {
state->fd = if_openrawsocket(ifp, ETHERTYPE_ARP);
if (state->fd == -1) {
logger(ifp->ctx, LOG_ERR, "%s: %s: %m",
__func__, ifp->name);
return;
}
eloop_event_add(ifp->ctx->eloop, state->arp_fd,
eloop_event_add(ifp->ctx->eloop, state->fd,
arp_packet, ifp, NULL, NULL);
}
}
@ -300,10 +301,10 @@ arp_probe(struct arp_state *astate)
struct arp_state *
arp_find(struct interface *ifp, const struct in_addr *addr)
{
struct iarp_state *state;
struct arp_state *astate;
struct dhcp_state *state;
if ((state = D_STATE(ifp)) == NULL)
if ((state = ARP_STATE(ifp)) == NULL)
goto out;
TAILQ_FOREACH(astate, &state->arp_states, next) {
if (astate->addr.s_addr == addr->s_addr && astate->iface == ifp)
@ -317,20 +318,31 @@ out:
struct arp_state *
arp_new(struct interface *ifp, const struct in_addr *addr)
{
struct iarp_state *state;
struct arp_state *astate;
struct dhcp_state *state;
if (addr && (astate = arp_find(ifp, addr)))
return astate;
if ((state = ARP_STATE(ifp)) == NULL) {
ifp->if_data[IF_DATA_ARP] = malloc(sizeof(*state));
state = ARP_STATE(ifp);
if (state == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
return NULL;
}
state->fd = -1;
TAILQ_INIT(&state->arp_states);
} else {
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;
}
state = D_STATE(ifp);
astate->iface = ifp;
if (addr)
astate->addr = *addr;
state = ARP_STATE(ifp);
TAILQ_INSERT_TAIL(&state->arp_states, astate, next);
return astate;
}
@ -345,27 +357,38 @@ arp_cancel(struct arp_state *astate)
void
arp_free(struct arp_state *astate)
{
struct dhcp_state *state;
if (astate) {
eloop_timeout_delete(astate->iface->ctx->eloop, NULL, astate);
state = D_STATE(astate->iface);
if (astate != NULL) {
struct interface *ifp;
struct iarp_state *state;
ifp = astate->iface;
eloop_timeout_delete(ifp->ctx->eloop, NULL, astate);
state = ARP_STATE(ifp);
TAILQ_REMOVE(&state->arp_states, astate, next);
if (state->arp_ipv4ll == astate) {
ipv4ll_stop(astate->iface);
state->arp_ipv4ll = NULL;
}
if (astate->free_cb)
astate->free_cb(astate);
free(astate);
/* If there are no more ARP states, close the socket. */
if (state->fd != -1 &&
TAILQ_FIRST(&state->arp_states) == NULL)
{
eloop_event_delete(ifp->ctx->eloop, state->fd);
close(state->fd);
free(state);
ifp->if_data[IF_DATA_ARP] = NULL;
}
}
}
void
arp_free_but(struct arp_state *astate)
{
struct iarp_state *state;
struct arp_state *p, *n;
struct dhcp_state *state;
state = D_STATE(astate->iface);
state = ARP_STATE(astate->iface);
TAILQ_FOREACH_SAFE(p, &state->arp_states, next, n) {
if (p != astate)
arp_free(p);
@ -375,24 +398,16 @@ arp_free_but(struct arp_state *astate)
void
arp_close(struct interface *ifp)
{
struct dhcp_state *state = D_STATE(ifp);
struct iarp_state *state;
struct arp_state *astate;
if (state == NULL)
return;
if (state->arp_fd != -1) {
eloop_event_delete(ifp->ctx->eloop, state->arp_fd);
close(state->arp_fd);
state->arp_fd = -1;
}
while ((astate = TAILQ_FIRST(&state->arp_states))) {
#ifndef __clang_analyzer__
/* clang guard needed for a more compex variant on this bug:
* http://llvm.org/bugs/show_bug.cgi?id=18222 */
/* Freeing the last state will also free the main state,
* so test for both. */
for (;;) {
if ((state = ARP_STATE(ifp)) == NULL ||
(astate = TAILQ_FIRST(&state->arp_states)) == NULL)
break;
arp_free(astate);
#endif
}
}
@ -401,10 +416,10 @@ 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 iarp_state *state;
struct arp_state *astate, *asn;
if (cmd != RTM_NEWADDR || (state = D_STATE(ifp)) == NULL)
if (cmd != RTM_NEWADDR || (state = ARP_STATE(ifp)) == NULL)
return;
TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, asn) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: arp.h,v 1.10 2015/05/16 23:31:32 roy Exp $ */
/* $NetBSD: arp.h,v 1.11 2015/07/09 10:15:34 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -59,6 +59,7 @@ struct arp_state {
void (*probed_cb)(struct arp_state *);
void (*announced_cb)(struct arp_state *);
void (*conflicted_cb)(struct arp_state *, const struct arp_msg *);
void (*free_cb)(struct arp_state *);
struct in_addr addr;
int probes;
@ -67,6 +68,16 @@ struct arp_state {
};
TAILQ_HEAD(arp_statehead, arp_state);
struct iarp_state {
int fd;
struct arp_statehead arp_states;
};
#define ARP_STATE(ifp) \
((struct iarp_state *)(ifp)->if_data[IF_DATA_ARP])
#define ARP_CSTATE(ifp) \
((const struct iarp_state *)(ifp)->if_data[IF_DATA_ARP])
#ifdef INET
void arp_report_conflicted(const struct arp_state *, const struct arp_msg *);
void arp_announce(struct arp_state *);

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: auth.c,v 1.9 2015/03/26 10:26:37 roy Exp $");
__RCSID("$NetBSD: auth.c,v 1.10 2015/07/09 10:15:34 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -418,7 +418,8 @@ get_next_rdm_monotonic_counter(struct auth *auth)
rdm++;
if (fseek(fp, 0, SEEK_SET) == -1 ||
ftruncate(fileno(fp), 0) == -1 ||
fprintf(fp, "0x%016" PRIu64 "\n", rdm) != 19)
fprintf(fp, "0x%016" PRIu64 "\n", rdm) != 19 ||
fflush(fp) == EOF)
{
if (!auth->last_replay_set) {
auth->last_replay = rdm;
@ -427,7 +428,6 @@ get_next_rdm_monotonic_counter(struct auth *auth)
rdm = ++auth->last_replay;
/* report error? */
}
fflush(fp);
#ifdef LOCK_EX
if (flocked == 0)
flock(fileno(fp), LOCK_UN);

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: common.c,v 1.13 2015/05/16 23:31:32 roy Exp $");
__RCSID("$NetBSD: common.c,v 1.14 2015/07/09 10:15:34 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -257,17 +257,6 @@ addvard(struct dhcpcd_ctx *ctx,
return addvar(ctx, e, prefix, var, buffer);
}
time_t
uptime(void)
{
struct timespec tv;
if (clock_gettime(CLOCK_MONOTONIC, &tv) == -1)
return -1;
return tv.tv_sec;
}
char *
hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen, char *buf, size_t buflen)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: common.h,v 1.9 2015/05/16 23:31:32 roy Exp $ */
/* $NetBSD: common.h,v 1.10 2015/07/09 10:15:34 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -58,6 +58,8 @@
#define NSEC_PER_SEC 1000000000L
#define NSEC_PER_MSEC 1000000L
#define MSEC_PER_SEC 1000L
#define CSEC_PER_SEC 100L
#define NSEC_PER_CSEC 10000000L
/* Some systems don't define timespec macros */
#ifndef timespecclear
@ -193,7 +195,6 @@ ssize_t addvar(struct dhcpcd_ctx *,
char ***, const char *, const char *, const char *);
ssize_t addvard(struct dhcpcd_ctx *,
char ***, const char *, const char *, size_t);
time_t uptime(void);
char *hwaddr_ntoa(const unsigned char *, size_t, char *, size_t);
size_t hwaddr_aton(unsigned char *, const char *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: defs.h,v 1.18 2015/05/16 23:31:32 roy Exp $ */
/* $NetBSD: defs.h,v 1.19 2015/07/09 10:15:34 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -30,7 +30,7 @@
#define CONFIG_H
#define PACKAGE "dhcpcd"
#define VERSION "6.9.0"
#define VERSION "6.9.1"
#ifndef CONFIG
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"
@ -48,7 +48,7 @@
# define SECRET SYSCONFDIR "/" PACKAGE ".secret"
#endif
#ifndef LEASEFILE
# define LEASEFILE DBDIR "/" PACKAGE "-%s%s%s.lease"
# define LEASEFILE DBDIR "/" PACKAGE "-%s%s.lease"
#endif
#ifndef LEASEFILE6
# define LEASEFILE6 LEASEFILE "6"

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: dhcp-common.c,v 1.9 2015/05/16 23:31:32 roy Exp $");
__RCSID("$NetBSD: dhcp-common.c,v 1.10 2015/07/09 10:15:34 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -30,6 +30,8 @@
#include <sys/utsname.h>
#include <arpa/nameser.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@ -46,6 +48,13 @@
#include "if.h"
#include "ipv6.h"
/* Support very old arpa/nameser.h as found in OpenBSD */
#ifndef NS_MAXDNAME
#define NS_MAXCDNAME MAXCDNAME
#define NS_MAXDNAME MAXDNAME
#define NS_MAXLABEL MAXLABEL
#endif
void
dhcp_print_option_encoding(const struct dhcp_opt *opt, int cols)
{
@ -81,7 +90,7 @@ dhcp_print_option_encoding(const struct dhcp_opt *opt, int cols)
printf(" flag");
else if (opt->type & BITFLAG)
printf(" bitflags");
else if (opt->type & RFC3397)
else if (opt->type & RFC1035)
printf(" domain");
else if (opt->type & DOMAIN)
printf(" dname");
@ -267,12 +276,12 @@ encode_rfc1035(const char *src, uint8_t *dst)
return len;
}
/* Decode an RFC3397 DNS search order option into a space
/* Decode an RFC1035 DNS search order option into a space
* separated string. Returns length of string (including
* terminating zero) or zero on error. out may be NULL
* to just determine output length. */
ssize_t
decode_rfc3397(char *out, size_t len, const uint8_t *p, size_t pl)
decode_rfc1035(char *out, size_t len, const uint8_t *p, size_t pl)
{
const char *start;
size_t start_len, l, count;
@ -280,6 +289,11 @@ decode_rfc3397(char *out, size_t len, const uint8_t *p, size_t pl)
int hops;
uint8_t ltype;
if (pl > NS_MAXCDNAME) {
errno = E2BIG;
return -1;
}
count = 0;
start = out;
start_len = len;
@ -292,8 +306,13 @@ decode_rfc3397(char *out, size_t len, const uint8_t *p, size_t pl)
* the name isn't fully qualified (ie, not terminated) */
while (q < e && (l = (size_t)*q++)) {
ltype = l & 0xc0;
if (ltype == 0x80 || ltype == 0x40)
if (ltype == 0x80 || ltype == 0x40) {
/* Currently reserved for future use as noted
* in RFC1035 4.1.4 as the 10 and 01
* combinations. */
errno = ENOTSUP;
return -1;
}
else if (ltype == 0xc0) { /* pointer */
if (q == e) {
errno = ERANGE;
@ -326,6 +345,10 @@ decode_rfc3397(char *out, size_t len, const uint8_t *p, size_t pl)
errno = ENOBUFS;
return -1;
}
if (l + 1 > NS_MAXLABEL) {
errno = EINVAL;
return -1;
}
memcpy(out, q, l);
out += l;
*out++ = '.';
@ -353,6 +376,10 @@ decode_rfc3397(char *out, size_t len, const uint8_t *p, size_t pl)
if (count)
/* Don't count the trailing NUL */
count--;
if (count > NS_MAXDNAME) {
errno = E2BIG;
return -1;
}
return (ssize_t)count;
}
@ -402,7 +429,7 @@ valid_domainname(char *lbl, int type)
!start && *lbl != ' ' && *lbl != '\0') ||
isalnum(c))
{
if (++len > 63) {
if (++len > NS_MAXLABEL) {
errno = ERANGE;
errset = 1;
break;
@ -529,35 +556,32 @@ print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl)
#define ADDRSZ 4
#define ADDR6SZ 16
static size_t
static ssize_t
dhcp_optlen(const struct dhcp_opt *opt, size_t dl)
{
size_t sz;
if (dl == 0)
return 0;
if (opt->type == 0 ||
opt->type & (STRING | BINHEX | RFC3442 | RFC5969))
{
if (opt->len) {
if ((size_t)opt->len > dl)
return 0;
return (size_t)opt->len;
return -1;
return (ssize_t)opt->len;
}
return dl;
return (ssize_t)dl;
}
if ((opt->type & (ADDRIPV4 | ARRAY)) == (ADDRIPV4 | ARRAY)) {
if (dl < ADDRSZ)
return 0;
return dl - (dl % ADDRSZ);
return -1;
return (ssize_t)(dl - (dl % ADDRSZ));
}
if ((opt->type & (ADDRIPV6 | ARRAY)) == (ADDRIPV6 | ARRAY)) {
if (dl < ADDR6SZ)
return 0;
return dl - (dl % ADDR6SZ);
return -1;
return (ssize_t)(dl - (dl % ADDR6SZ));
}
if (opt->type & (UINT32 | ADDRIPV4))
@ -570,8 +594,8 @@ dhcp_optlen(const struct dhcp_opt *opt, size_t dl)
sz = ADDR6SZ;
else
/* If we don't know the size, assume it's valid */
return dl;
return (dl < sz ? 0 : sz);
return (ssize_t)dl;
return dl < sz ? -1 : (ssize_t)sz;
}
static ssize_t
@ -592,15 +616,15 @@ print_option(char *s, size_t len, const struct dhcp_opt *opt,
UNUSED(ifname);
#endif
if (opt->type & RFC3397) {
sl = decode_rfc3397(NULL, 0, data, dl);
if (opt->type & RFC1035) {
sl = decode_rfc1035(NULL, 0, data, dl);
if (sl == 0 || sl == -1)
return sl;
l = (size_t)sl + 1;
tmp = malloc(l);
if (tmp == NULL)
return -1;
decode_rfc3397(tmp, l, data, dl);
decode_rfc1035(tmp, l, data, dl);
sl = print_string(s, len, opt->type, (uint8_t *)tmp, l - 1);
free(tmp);
return sl;
@ -758,7 +782,7 @@ print_option(char *s, size_t len, const struct dhcp_opt *opt,
int
dhcp_set_leasefile(char *leasefile, size_t len, int family,
const struct interface *ifp, const char *extra)
const struct interface *ifp)
{
char ssid[len];
@ -785,7 +809,7 @@ dhcp_set_leasefile(char *leasefile, size_t len, int family,
ssid[0] = '\0';
return snprintf(leasefile, len,
family == AF_INET ? LEASEFILE : LEASEFILE6,
ifp->name, ssid, extra);
ifp->name, ssid);
}
static size_t
@ -834,6 +858,7 @@ dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
const uint8_t *od, size_t ol)
{
size_t e, i, n, eos, eol;
ssize_t eo;
unsigned int eoc;
const uint8_t *eod;
int ov;
@ -877,21 +902,42 @@ dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
* is a fixed layout */
n = 0;
for (i = 0, eopt = opt->embopts; i < opt->embopts_len; i++, eopt++) {
e = dhcp_optlen(eopt, ol);
if (e == 0)
/* Report error? */
return 0;
eo = dhcp_optlen(eopt, ol);
if (eo == -1) {
if (env == NULL)
logger(ctx, LOG_ERR,
"%s: %s: malformed embedded option %d:%d",
ifname, __func__, opt->option,
eopt->option);
goto out;
}
if (eo == 0) {
/* An option was expected, but there is no data
* data for it.
* This may not be an error as some options like
* DHCP FQDN in RFC4702 have a string as the last
* option which is optional.
* FIXME: Add an flag to the options to indicate
* wether this is allowable or not. */
if (env == NULL &&
(ol != 0 || i + 1 < opt->embopts_len))
logger(ctx, LOG_ERR,
"%s: %s: malformed embedded option %d:%d",
ifname, __func__, opt->option,
eopt->option);
goto out;
}
/* Use the option prefix if the embedded option
* name is different.
* This avoids new_fqdn_fqdn which would be silly. */
if (!(eopt->type & RESERVED)) {
ov = strcmp(opt->var, eopt->var);
if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[n],
pfx, eopt, ov, od, e, ifname))
pfx, eopt, ov, od, (size_t)eo, ifname))
n++;
}
od += e;
ol -= e;
od += (size_t)eo;
ol -= (size_t)eo;
}
/* Enumerate our encapsulated options */
@ -935,6 +981,7 @@ dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
}
}
out:
if (env)
free(pfx);

View File

@ -1,4 +1,4 @@
/* $NetBSD: dhcp-common.h,v 1.9 2015/05/16 23:31:32 roy Exp $ */
/* $NetBSD: dhcp-common.h,v 1.10 2015/07/09 10:15:34 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -52,7 +52,7 @@
#define STRING (1 << 7)
#define ARRAY (1 << 8)
#define RFC3361 (1 << 9)
#define RFC3397 (1 << 10)
#define RFC1035 (1 << 10)
#define RFC3442 (1 << 11)
#define RFC5969 (1 << 12)
#define ADDRIPV6 (1 << 13)
@ -106,10 +106,9 @@ int make_option_mask(const struct dhcp_opt *, size_t,
uint8_t *, const char *, int);
size_t encode_rfc1035(const char *src, uint8_t *dst);
ssize_t decode_rfc3397(char *, size_t, const uint8_t *, size_t);
ssize_t decode_rfc1035(char *, size_t, const uint8_t *, size_t);
ssize_t print_string(char *, size_t, int, const uint8_t *, size_t);
int dhcp_set_leasefile(char *, size_t, int,
const struct interface *, const char *);
int dhcp_set_leasefile(char *, size_t, int, const struct interface *);
size_t dhcp_envoption(struct dhcpcd_ctx *,
char **, const char *, const char *, struct dhcp_opt *,

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: dhcp.c,v 1.31 2015/05/16 23:31:32 roy Exp $");
__RCSID("$NetBSD: dhcp.c,v 1.32 2015/07/09 10:15:34 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -171,30 +171,9 @@ get_option(struct dhcpcd_ctx *ctx,
while (p < e) {
o = *p++;
if (o == opt) {
if (op) {
if (!ctx->opt_buffer) {
ctx->opt_buffer =
malloc(DHCP_OPTION_LEN +
BOOTFILE_LEN + SERVERNAME_LEN);
if (ctx->opt_buffer == NULL)
return NULL;
}
if (!bp)
bp = ctx->opt_buffer;
memcpy(bp, op, ol);
bp += ol;
}
ol = *p;
if (p + ol > e) {
errno = EINVAL;
return NULL;
}
op = p + 1;
bl += ol;
}
switch (o) {
case DHO_PAD:
/* No length to read */
continue;
case DHO_END:
if (overl & 1) {
@ -209,17 +188,48 @@ get_option(struct dhcpcd_ctx *ctx,
e = p + sizeof(dhcp->servername);
} else
goto exit;
break;
case DHO_OPTIONSOVERLOADED:
/* No length to read */
continue;
}
/* Check we can read the length */
if (p == e) {
errno = EINVAL;
return NULL;
}
l = *p++;
if (o == DHO_OPTIONSOVERLOADED) {
/* Ensure we only get this option once by setting
* the last bit as well as the value.
* This is valid because only the first two bits
* actually mean anything in RFC2132 Section 9.3 */
if (!overl)
overl = 0x80 | p[1];
break;
if (l == 1 && !overl)
overl = 0x80 | p[0];
}
if (o == opt) {
if (op) {
if (!ctx->opt_buffer) {
ctx->opt_buffer =
malloc(DHCP_OPTION_LEN +
BOOTFILE_LEN + SERVERNAME_LEN);
if (ctx->opt_buffer == NULL)
return NULL;
}
if (!bp)
bp = ctx->opt_buffer;
memcpy(bp, op, ol);
bp += ol;
}
ol = l;
if (p + ol >= e) {
errno = EINVAL;
return NULL;
}
op = p;
bl += ol;
}
l = *p++;
p += l;
}
@ -421,12 +431,12 @@ decode_rfc3361(const uint8_t *data, size_t dl)
dl--;
switch (enc) {
case 0:
if ((r = decode_rfc3397(NULL, 0, data, dl)) > 0) {
if ((r = decode_rfc1035(NULL, 0, data, dl)) > 0) {
l = (size_t)r;
sip = malloc(l);
if (sip == NULL)
return 0;
decode_rfc3397(sip, l, data, dl);
decode_rfc1035(sip, l, data, dl);
}
break;
case 1:
@ -647,6 +657,14 @@ get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
free(route);
continue;
}
/* A host route is normally set by having the
* gateway match the destination or assigned address */
if (route->gate.s_addr == route->dest.s_addr ||
route->gate.s_addr == dhcp->yiaddr)
{
route->gate.s_addr = htonl(INADDR_ANY);
route->net.s_addr = htonl(INADDR_BROADCAST);
}
route->net.s_addr = route_netmask(route->dest.s_addr);
TAILQ_INSERT_TAIL(routes, route, next);
}
@ -721,7 +739,6 @@ make_message(struct dhcp_message **message,
struct if_options *ifo = ifp->options;
const struct dhcp_state *state = D_CSTATE(ifp);
const struct dhcp_lease *lease = &state->lease;
time_t up = uptime() - state->start_uptime;
char hbuf[HOSTNAME_MAX_LEN + 1];
const char *hostname;
const struct vivco *vivco;
@ -761,10 +778,14 @@ make_message(struct dhcp_message **message,
dhcp->flags = htons(BROADCAST_FLAG);
if (type != DHCP_DECLINE && type != DHCP_RELEASE) {
if (up < 0 || up > (time_t)UINT16_MAX)
struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
timespecsub(&tv, &state->started, &tv);
if (tv.tv_sec < 0 || tv.tv_sec > (time_t)UINT16_MAX)
dhcp->secs = htons((uint16_t)UINT16_MAX);
else
dhcp->secs = htons((uint16_t)up);
dhcp->secs = htons((uint16_t)tv.tv_sec);
}
dhcp->xid = htonl(state->xid);
dhcp->cookie = htonl(MAGIC_COOKIE);
@ -1279,7 +1300,8 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
addr.s_addr = dhcp->yiaddr ? dhcp->yiaddr : dhcp->ciaddr;
addvar(ifp->ctx, &ep, prefix, "ip_address", inet_ntoa(addr));
if (get_option_addr(ifp->ctx, &net,
dhcp, DHO_SUBNETMASK) == -1) {
dhcp, DHO_SUBNETMASK) == -1)
{
net.s_addr = ipv4_getnetmask(addr.s_addr);
addvar(ifp->ctx, &ep, prefix,
"subnet_mask", inet_ntoa(net));
@ -1287,7 +1309,8 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net));
addvar(ifp->ctx, &ep, prefix, "subnet_cidr", cidr);
if (get_option_addr(ifp->ctx, &brd,
dhcp, DHO_BROADCAST) == -1) {
dhcp, DHO_BROADCAST) == -1)
{
brd.s_addr = addr.s_addr | ~net.s_addr;
addvar(ifp->ctx, &ep, prefix,
"broadcast_address", inet_ntoa(brd));
@ -1639,34 +1662,29 @@ send_message(struct interface *ifp, uint8_t type,
((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))
(state->lease.server.s_addr ||
ifp->options->options & DHCPCD_INFORM) &&
!IS_BOOTP(ifp, state->new))
{
s = dhcp_openudp(ifp);
if (s == -1 && errno != EADDRINUSE)
logger(ifp->ctx, LOG_ERR,
"%s: dhcp_openudp: %m", ifp->name);
if (s == -1) {
if (errno != EADDRINUSE)
logger(ifp->ctx, LOG_ERR,
"%s: dhcp_openudp: %m", ifp->name);
/* We cannot renew */
a = state->addr.s_addr;
state->addr.s_addr = INADDR_ANY;
}
}
/* If we couldn't open a UDP port for our IP address
* then we cannot renew.
* This could happen if our IP was pulled out from underneath us.
* Also, we should not unicast from a BOOTP lease. */
if (s == -1 ||
(!(ifo->options & DHCPCD_INFORM) &&
IS_BOOTP(ifp, state->new)))
{
a = state->addr.s_addr;
state->addr.s_addr = INADDR_ANY;
}
r = make_message(&dhcp, ifp, type);
if (a != INADDR_ANY)
state->addr.s_addr = a;
if (r == -1)
goto fail;
len = (size_t)r;
if (a)
state->addr.s_addr = a;
from.s_addr = dhcp->ciaddr;
if (from.s_addr)
if (s != -1 && from.s_addr != INADDR_ANY)
to.s_addr = state->lease.server.s_addr;
else
to.s_addr = INADDR_ANY;
@ -1777,8 +1795,7 @@ dhcp_discover(void *arg)
if (ifo->fallback)
eloop_timeout_add_sec(ifp->ctx->eloop,
ifo->reboot, dhcp_fallback, ifp);
else if (ifo->options & DHCPCD_IPV4LL &&
!IN_LINKLOCAL(htonl(state->addr.s_addr)))
else if (ifo->options & DHCPCD_IPV4LL)
eloop_timeout_add_sec(ifp->ctx->eloop,
ifo->reboot, ipv4ll_start, ifp);
if (ifo->options & DHCPCD_REQUEST)
@ -1841,14 +1858,12 @@ 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)
@ -1875,12 +1890,12 @@ dhcp_arp_probed(struct arp_state *astate)
struct dhcp_state *state;
struct if_options *ifo;
/* We didn't find a profile for this
* address or hwaddr, so move to the next
* arping profile */
state = D_STATE(astate->iface);
ifo = astate->iface->options;
if (state->arping_index < ifo->arping_len) {
/* We didn't find a profile for this
* address or hwaddr, so move to the next
* arping profile */
if (++state->arping_index < ifo->arping_len) {
astate->addr.s_addr =
ifo->arping[state->arping_index - 1];
@ -1889,24 +1904,26 @@ dhcp_arp_probed(struct arp_state *astate)
dhcpcd_startinterface(astate->iface);
return;
}
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
logger(astate->iface->ctx, LOG_DEBUG, "%s: DAD completed for %s",
astate->iface->name, inet_ntoa(astate->addr));
dhcp_bind(astate->iface);
arp_announce(astate);
/* Stop IPv4LL now we have a working DHCP address */
ipv4ll_drop(astate->iface);
}
static void
dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
{
struct interface *ifp;
struct dhcp_state *state;
struct if_options *ifo;
state = D_STATE(astate->iface);
ifo = astate->iface->options;
ifp = astate->iface;
ifo = ifp->options;
state = D_STATE(ifp);
if (state->arping_index &&
state->arping_index <= ifo->arping_len &&
amsg &&
@ -1918,9 +1935,9 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
astate->failed.s_addr = ifo->arping[state->arping_index - 1];
arp_report_conflicted(astate, amsg);
hwaddr_ntoa(amsg->sha, astate->iface->hwlen, buf, sizeof(buf));
if (dhcpcd_selectprofile(astate->iface, buf) == -1 &&
dhcpcd_selectprofile(astate->iface,
hwaddr_ntoa(amsg->sha, ifp->hwlen, buf, sizeof(buf));
if (dhcpcd_selectprofile(ifp, buf) == -1 &&
dhcpcd_selectprofile(ifp,
inet_ntoa(astate->failed)) == -1)
{
/* We didn't find a profile for this
@ -1929,11 +1946,10 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
dhcp_arp_probed(astate);
return;
}
dhcp_close(astate->iface);
arp_close(astate->iface);
eloop_timeout_delete(astate->iface->ctx->eloop, NULL,
astate->iface);
dhcpcd_startinterface(astate->iface);
dhcp_close(ifp);
arp_free(astate);
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
dhcpcd_startinterface(ifp);
}
/* RFC 2131 3.1.5, Client-server interaction
@ -1954,32 +1970,26 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
arp_report_conflicted(astate, amsg);
unlink(state->leasefile);
if (!state->lease.frominfo)
dhcp_decline(astate->iface);
dhcp_decline(ifp);
#ifdef IN_IFF_DUPLICATED
ia = ipv4_iffindaddr(astate->iface, &astate->addr, NULL);
ia = ipv4_iffindaddr(ifp, &astate->addr, NULL);
if (ia)
ipv4_deladdr(astate->iface, &ia->addr, &ia->net);
ipv4_deladdr(ifp, &ia->addr, &ia->net, 1);
#endif
eloop_timeout_delete(astate->iface->ctx->eloop, NULL,
astate->iface);
eloop_timeout_add_sec(astate->iface->ctx->eloop,
DHCP_RAND_MAX, dhcp_discover, astate->iface);
arp_free(astate);
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
eloop_timeout_add_sec(ifp->ctx->eloop,
DHCP_RAND_MAX, dhcp_discover, ifp);
}
}
void
dhcp_bind(struct interface *ifp, struct arp_state *astate)
dhcp_bind(struct interface *ifp)
{
struct dhcp_state *state = D_STATE(ifp);
struct if_options *ifo = ifp->options;
struct dhcp_lease *lease = &state->lease;
uint8_t ipv4ll = 0;
if (state->state == DHS_BOUND)
goto applyaddr;
#ifdef IN_IFF_TENTATIVE
state->added |= STATE_TENTATIVE;
#endif
state->reason = NULL;
free(state->old);
state->old = state->new;
@ -1992,12 +2002,6 @@ dhcp_bind(struct interface *ifp, struct arp_state *astate)
inet_ntocidr(lease->net));
lease->leasetime = ~0U;
state->reason = "STATIC";
} else if (state->new->cookie != htonl(MAGIC_COOKIE)) {
logger(ifp->ctx, LOG_INFO, "%s: using IPv4LL address %s",
ifp->name, inet_ntoa(lease->addr));
lease->leasetime = ~0U;
state->reason = "IPV4LL";
ipv4ll = 1;
} else if (ifo->options & DHCPCD_INFORM) {
if (ifo->req_addr.s_addr != 0)
lease->addr.s_addr = ifo->req_addr.s_addr;
@ -2085,53 +2089,14 @@ dhcp_bind(struct interface *ifp, struct arp_state *astate)
" seconds",
ifp->name, lease->renewaltime, lease->rebindtime);
}
if (!(ifo->options & DHCPCD_STATIC) &&
state->new->cookie != htonl(MAGIC_COOKIE))
state->state = DHS_IPV4LL_BOUND;
else
state->state = DHS_BOUND;
state->state = DHS_BOUND;
if (!state->lease.frominfo &&
!(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
if (write_lease(ifp, state->new) == -1)
logger(ifp->ctx, LOG_ERR,
"%s: write_lease: %m", __func__);
applyaddr:
#ifdef IN_IFF_TENTATIVE
if (astate == NULL) {
astate = arp_new(ifp, &lease->addr);
if (astate) {
astate->probed_cb = dhcp_arp_probed;
astate->conflicted_cb = dhcp_arp_conflicted;
}
}
#endif
ipv4_applyaddr(ifp);
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, &state->addr);
astate->announced_cb =
dhcp_arp_announced;
}
if (astate) {
arp_announce(astate);
if (!ipv4ll)
arp_free_but(astate);
}
} else if (!ipv4ll)
arp_close(ifp);
#endif
}
}
static void
@ -2140,7 +2105,7 @@ dhcp_timeout(void *arg)
struct interface *ifp = arg;
struct dhcp_state *state = D_STATE(ifp);
dhcp_bind(ifp, NULL);
dhcp_bind(ifp);
state->interval = 0;
dhcp_discover(ifp);
}
@ -2155,6 +2120,7 @@ dhcp_message_new(const struct in_addr *addr, const struct in_addr *mask)
if (dhcp == NULL)
return NULL;
dhcp->yiaddr = addr->s_addr;
dhcp->cookie = htonl(MAGIC_COOKIE);
p = dhcp->options;
if (mask && mask->s_addr != INADDR_ANY) {
*p++ = DHO_SUBNETMASK;
@ -2171,10 +2137,15 @@ dhcp_static(struct interface *ifp)
{
struct if_options *ifo;
struct dhcp_state *state;
struct ipv4_addr *ia;
state = D_STATE(ifp);
ifo = ifp->options;
if (ifo->req_addr.s_addr == INADDR_ANY) {
ia = NULL;
if (ifo->req_addr.s_addr == INADDR_ANY &&
(ia = ipv4_iffindaddr(ifp, NULL, NULL)) == NULL)
{
logger(ifp->ctx, LOG_INFO,
"%s: waiting for 3rd party to "
"configure IP address",
@ -2183,10 +2154,12 @@ dhcp_static(struct interface *ifp)
script_runreason(ifp, state->reason);
return;
}
state->offer = dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
state->offer = dhcp_message_new(ia ? &ia->addr : &ifo->req_addr,
ia ? &ia->net : &ifo->req_mask);
if (state->offer) {
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
dhcp_bind(ifp, NULL);
dhcp_bind(ifp);
}
}
@ -2222,7 +2195,7 @@ dhcp_inform(struct interface *ifp)
dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
if (state->offer) {
ifo->options |= DHCPCD_STATIC;
dhcp_bind(ifp, NULL);
dhcp_bind(ifp);
ifo->options &= ~DHCPCD_STATIC;
}
}
@ -2291,8 +2264,7 @@ dhcp_reboot(struct interface *ifp)
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
/* Need to add this before dhcp_expire and friends. */
if (!ifo->fallback && ifo->options & DHCPCD_IPV4LL &&
!IN_LINKLOCAL(htonl(state->addr.s_addr)))
if (!ifo->fallback && ifo->options & DHCPCD_IPV4LL)
eloop_timeout_add_sec(ifp->ctx->eloop,
ifo->reboot, ipv4ll_start, ifp);
@ -2323,22 +2295,18 @@ dhcp_drop(struct interface *ifp, const char *reason)
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
return;
}
/* Don't reset DHCP state if we have an IPv4LL address and link is up,
* unless the interface is departing. */
if (state->state != DHS_IPV4LL_BOUND ||
ifp->carrier != LINK_UP ||
ifp->options->options & DHCPCD_DEPARTED)
{
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
dhcp_auth_reset(&state->auth);
dhcp_close(ifp);
}
if (ifp->options->options & DHCPCD_RELEASE) {
/* Failure to send the release may cause this function to
* re-enter so guard by setting the state. */
if (state->state == DHS_RELEASE)
return;
state->state = DHS_RELEASE;
unlink(state->leasefile);
if (ifp->carrier != LINK_DOWN &&
state->new != NULL &&
state->new->cookie == htonl(MAGIC_COOKIE))
state->lease.server.s_addr != INADDR_ANY)
{
logger(ifp->ctx, LOG_INFO, "%s: releasing lease of %s",
ifp->name, inet_ntoa(state->lease.addr));
@ -2353,6 +2321,10 @@ dhcp_drop(struct interface *ifp, const char *reason)
}
}
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
dhcp_auth_reset(&state->auth);
dhcp_close(ifp);
free(state->old);
state->old = state->new;
state->new = NULL;
@ -2476,8 +2448,8 @@ 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;
struct arp_state *astate;
/* We may have found a BOOTP server */
if (get_option_uint8(ifp->ctx, &type, dhcp, DHO_MESSAGETYPE) == -1)
@ -2640,8 +2612,7 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
"%s: message: %s", ifp->name, msg);
free(msg);
}
if ((state->state == DHS_DISCOVER ||
state->state == DHS_IPV4LL_BOUND) &&
if (state->state == DHS_DISCOVER &&
get_option_uint8(ifp->ctx, &tmp, dhcp,
DHO_AUTOCONFIGURE) == 0)
{
@ -2649,24 +2620,13 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
case 0:
log_dhcp(LOG_WARNING, "IPv4LL disabled from",
ifp, dhcp, from);
dhcp_drop(ifp, "EXPIRE");
ipv4ll_drop(ifp);
arp_close(ifp);
eloop_timeout_delete(ifp->ctx->eloop,
NULL, ifp);
eloop_timeout_add_sec(ifp->ctx->eloop,
DHCP_MAX, dhcp_discover,
ifp);
break;
case 1:
log_dhcp(LOG_WARNING, "IPv4LL enabled from",
ifp, dhcp, from);
eloop_timeout_delete(ifp->ctx->eloop,
NULL, ifp);
if (IN_LINKLOCAL(htonl(state->addr.s_addr)))
eloop_timeout_add_sec(ifp->ctx->eloop,
DHCP_MAX, dhcp_discover, ifp);
else
ipv4ll_start(ifp);
ipv4ll_start(ifp);
break;
default:
logger(ifp->ctx, LOG_ERR,
@ -2674,6 +2634,9 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
ifp->name, tmp);
break;
}
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
eloop_timeout_add_sec(ifp->ctx->eloop,
DHCP_MAX, dhcp_discover, ifp);
}
return;
}
@ -2695,7 +2658,7 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
ifp, dhcp, from);
if (type)
dhcp_decline(ifp);
ipv4_deladdr(ifp, &ia->addr, &ia->net);
ipv4_deladdr(ifp, &ia->addr, &ia->net, 0);
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
eloop_timeout_add_sec(ifp->ctx->eloop,
DHCP_RAND_MAX, dhcp_discover, ifp);
@ -2703,9 +2666,7 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
}
#endif
if ((type == 0 || type == DHCP_OFFER) &&
(state->state == DHS_DISCOVER || state->state == DHS_IPV4LL_BOUND))
{
if ((type == 0 || type == DHCP_OFFER) && state->state == DHS_DISCOVER) {
lease->frominfo = 0;
lease->addr.s_addr = dhcp->yiaddr;
lease->cookie = dhcp->cookie;
@ -2761,7 +2722,6 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
ifo->options &= ~DHCPCD_STATIC;
}
/* No NAK, so reset the backoff
* We don't reset on an OFFER message because the server could
* potentially NAK the REQUEST. */
@ -2777,21 +2737,36 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
lease->frominfo = 0;
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
astate = NULL;
#ifndef IN_IFF_TENTATIVE
if (ifo->options & DHCPCD_ARP
&& state->addr.s_addr != state->offer->yiaddr)
{
addr.s_addr = state->offer->yiaddr;
/* If the interface already has the address configured
* then we can't ARP for duplicate detection. */
ia = ipv4_findaddr(ifp->ctx, &addr);
if (ia) {
astate = arp_new(ifp, &addr);
if (astate) {
addr.s_addr = state->offer->yiaddr;
/* If the interface already has the address configured
* then we can't ARP for duplicate detection. */
ia = ipv4_findaddr(ifp->ctx, &addr);
#ifdef IN_IFF_TENTATIVE
if (ia == NULL || ia->addr_flags & IN_IFF_NOTUSEABLE) {
if ((astate = arp_new(ifp, &addr)) != NULL) {
astate->probed_cb = dhcp_arp_probed;
astate->conflicted_cb = dhcp_arp_conflicted;
astate->announced_cb = dhcp_arp_announced;
}
if (ia == NULL) {
struct dhcp_lease l;
get_lease(ifp->ctx, &l, state->offer);
/* Add the address now, let the kernel handle DAD. */
ipv4_addaddr(ifp, &l.addr, &l.net, &l.brd);
}
return;
}
#else
if (ifo->options & DHCPCD_ARP) {
if (ia == NULL) {
if ((astate = arp_new(ifp, &addr)) != NULL) {
astate->probed_cb = dhcp_arp_probed;
astate->conflicted_cb = dhcp_arp_conflicted;
astate->announced_cb = dhcp_arp_announced;
/* We need to handle DAD. */
arp_probe(astate);
}
return;
@ -2799,7 +2774,7 @@ dhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
}
#endif
dhcp_bind(ifp, astate);
dhcp_bind(ifp);
}
static size_t
@ -3016,10 +2991,9 @@ dhcp_dump(struct interface *ifp)
ifp->if_data[IF_DATA_DHCP] = state = calloc(1, sizeof(*state));
if (state == NULL)
goto eexit;
state->raw_fd = state->arp_fd = -1;
TAILQ_INIT(&state->arp_states);
state->raw_fd = -1;
dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
AF_INET, ifp, "");
AF_INET, ifp);
state->new = read_lease(ifp);
if (state->new == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %s: %m",
@ -3046,7 +3020,6 @@ dhcp_free(struct interface *ifp)
free(state->old);
free(state->new);
free(state->offer);
free(state->buffer);
free(state->clientid);
free(state);
ifp->if_data[IF_DATA_DHCP] = NULL;
@ -3090,8 +3063,7 @@ dhcp_init(struct interface *ifp)
if (state == NULL)
return -1;
/* 0 is a valid fd, so init to -1 */
state->raw_fd = state->arp_fd = -1;
TAILQ_INIT(&state->arp_states);
state->raw_fd = -1;
/* Now is a good time to find IPv4 routes */
if_initrt(ifp);
@ -3101,7 +3073,7 @@ dhcp_init(struct interface *ifp)
state->reason = "PREINIT";
state->nakoff = 0;
dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
AF_INET, ifp, "");
AF_INET, ifp);
ifo = ifp->options;
/* We need to drop the leasefile so that dhcp_start
@ -3194,7 +3166,7 @@ dhcp_start1(void *arg)
}
state = D_STATE(ifp);
state->start_uptime = uptime();
clock_gettime(CLOCK_MONOTONIC, &state->started);
free(state->offer);
state->offer = NULL;
@ -3347,6 +3319,13 @@ dhcp_start(struct interface *ifp)
return;
/* No point in delaying a static configuration */
if (ifp->options->options & DHCPCD_STATIC ||
!(ifp->options->options & DHCPCD_INITIAL_DELAY))
{
dhcp_start1(ifp);
return;
}
tv.tv_sec = DHCP_MIN_DELAY;
tv.tv_nsec = (suseconds_t)arc4random_uniform(
(DHCP_MAX_DELAY - DHCP_MIN_DELAY) * NSEC_PER_SEC);

View File

@ -1,4 +1,4 @@
/* $NetBSD: dhcp.h,v 1.9 2015/05/02 15:18:36 roy Exp $ */
/* $NetBSD: dhcp.h,v 1.10 2015/07/09 10:15:34 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -197,8 +197,7 @@ enum DHS {
DHS_REBOOT,
DHS_INFORM,
DHS_RENEW_REQUESTED,
DHS_IPV4LL_BOUND,
DHS_PROBE
DHS_RELEASE
};
struct dhcp_state {
@ -215,29 +214,16 @@ struct dhcp_state {
int socket;
int raw_fd;
int arp_fd;
size_t buffer_size, buffer_len, buffer_pos;
unsigned char *buffer;
struct in_addr addr;
struct in_addr net;
struct in_addr dst;
uint8_t added;
char leasefile[sizeof(LEASEFILE) + IF_NAMESIZE + (IF_SSIDSIZE * 4)];
time_t start_uptime;
struct timespec started;
unsigned char *clientid;
struct authstate auth;
struct arp_statehead arp_states;
size_t arping_index;
struct arp_state *arp_ipv4ll;
unsigned int conflicts;
time_t defend;
char randomstate[128];
};
#define D_STATE(ifp) \
@ -259,8 +245,7 @@ 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) != NULL && \
get_option_uint8((i)->ctx, NULL, (m), DHO_MESSAGETYPE) == -1)
struct rt_head *get_option_routes(struct interface *,
const struct dhcp_message *);
@ -284,7 +269,7 @@ void dhcp_start(struct interface *);
void dhcp_stop(struct interface *);
void dhcp_discover(void *);
void dhcp_inform(struct interface *);
void dhcp_bind(struct interface *, struct arp_state *);
void dhcp_bind(struct interface *);
void dhcp_reboot_newopts(struct interface *, unsigned long long);
void dhcp_close(struct interface *);
void dhcp_free(struct interface *);

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: dhcp6.c,v 1.13 2015/05/16 23:31:32 roy Exp $");
__RCSID("$NetBSD: dhcp6.c,v 1.14 2015/07/09 10:15:34 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -35,6 +35,7 @@
#include <netinet/in.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@ -301,7 +302,8 @@ dhcp6_updateelapsed(struct interface *ifp, struct dhcp6_message *m, size_t len)
struct dhcp6_state *state;
const struct dhcp6_option *co;
struct dhcp6_option *o;
time_t up;
struct timespec tv;
time_t hsec;
uint16_t u16;
co = dhcp6_getmoption(D6_OPTION_ELAPSED, m, len);
@ -310,10 +312,26 @@ dhcp6_updateelapsed(struct interface *ifp, struct dhcp6_message *m, size_t len)
o = __UNCONST(co);
state = D6_STATE(ifp);
up = uptime() - state->start_uptime;
if (up < 0 || up > (time_t)UINT16_MAX)
up = (time_t)UINT16_MAX;
u16 = htons((uint16_t)up);
clock_gettime(CLOCK_MONOTONIC, &tv);
if (state->RTC == 0) {
/* An RTC of zero means we're the first message
* out of the door, so the elapsed time is zero. */
state->started = tv;
hsec = 0;
} else {
timespecsub(&tv, &state->started, &tv);
/* Elapsed time is measured in centiseconds.
* We need to be sure it will not potentially overflow. */
if (tv.tv_sec >= (UINT16_MAX / CSEC_PER_SEC) + 1)
hsec = UINT16_MAX;
else {
hsec = (tv.tv_sec * CSEC_PER_SEC) +
(tv.tv_nsec / NSEC_PER_CSEC);
if (hsec > UINT16_MAX)
hsec = UINT16_MAX;
}
}
u16 = htons((uint16_t)hsec);
memcpy(D6_OPTION_DATA(o), &u16, sizeof(u16));
return 0;
}
@ -645,31 +663,20 @@ dhcp6_makemessage(struct interface *ifp)
!(ap->flags & IPV6_AF_REQUEST))
continue;
if (ap->ia_type == D6_OPTION_IA_PD) {
if (!(ifo->options & DHCPCD_NOPFXDLG)) {
len += sizeof(*o) + sizeof(u8) +
sizeof(u32) + sizeof(u32) +
sizeof(ap->prefix);
if (ap->prefix_exclude_len)
len += sizeof(*o) + 1 +
(uint8_t)((ap->prefix_exclude_len -
ap->prefix_len - 1) / NBBY)
+ 1;
}
} else if (!(ifo->options & DHCPCD_PFXDLGONLY))
len += sizeof(*o) + sizeof(u8) +
sizeof(u32) + sizeof(u32) +
sizeof(ap->prefix);
if (ap->prefix_exclude_len)
len += sizeof(*o) + 1 +
(uint8_t)((ap->prefix_exclude_len -
ap->prefix_len - 1) / NBBY) + 1;
} else
len += sizeof(*o) + sizeof(ap->addr) +
sizeof(u32) + sizeof(u32);
}
/* FALLTHROUGH */
case DH6S_INIT:
for (l = 0; l < ifo->ia_len; l++) {
if (ifo->ia[l].ia_type == D6_OPTION_IA_PD) {
if (ifo->options & DHCPCD_NOPFXDLG)
continue;
} else if (ifo->options & DHCPCD_PFXDLGONLY)
continue;
len += sizeof(*o) + (sizeof(u32) * 3);
}
len += ifo->ia_len * (sizeof(*o) + (sizeof(u32) * 3));
IA = 1;
break;
default:
@ -781,11 +788,6 @@ dhcp6_makemessage(struct interface *ifp)
}
for (l = 0; IA && l < ifo->ia_len; l++) {
if (ifo->ia[l].ia_type == D6_OPTION_IA_PD) {
if (ifo->options & DHCPCD_NOPFXDLG)
continue;
} else if (ifo->options & DHCPCD_PFXDLGONLY)
continue;
o = D6_NEXT_OPTION(o);
o->code = htons(ifo->ia[l].ia_type);
o->len = htons(sizeof(u32) + sizeof(u32) + sizeof(u32));
@ -1057,6 +1059,9 @@ dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
state->send->xid[1],
state->send->xid[2]);
else {
if (state->IMD &&
!(ifp->options->options & DHCPCD_INITIAL_DELAY))
state->IMD = 0;
if (state->IMD) {
/* Some buggy PPP servers close the link too early
* after sending an invalid status in their reply
@ -1097,7 +1102,7 @@ dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
else
timespecadd(&state->RT, &RTprev, &state->RT);
if (state->RT.tv_sec > state->MRT) {
if (state->MRT != 0 && state->RT.tv_sec > state->MRT) {
RTprev.tv_sec = state->MRT;
RTprev.tv_nsec = 0;
state->RT.tv_sec = state->MRT;
@ -1124,8 +1129,12 @@ logsend:
state->send->xid[2],
timespec_to_double(&state->RT));
/* This sometimes happens when we delegate to this interface
* AND run DHCPv6 on it normally. */
assert(timespec_to_double(&state->RT) != 0);
/* Wait the initial delay */
if (state->IMD) {
if (state->IMD != 0) {
state->IMD = 0;
eloop_timeout_add_tv(ifp->ctx->eloop,
&state->RT, callback, ifp);
@ -1230,14 +1239,12 @@ dhcp6_sendconfirm(void *arg)
dhcp6_sendmessage(arg, dhcp6_sendconfirm);
}
/*
static void
dhcp6_sendrelease(void *arg)
{
dhcp6_sendmessage(arg, dhcp6_sendrelease);
}
*/
static void
dhcp6_startrenew(void *arg)
@ -1248,7 +1255,6 @@ dhcp6_startrenew(void *arg)
ifp = arg;
state = D6_STATE(ifp);
state->state = DH6S_RENEW;
state->start_uptime = uptime();
state->RTC = 0;
state->IRT = REN_TIMEOUT;
state->MRT = REN_MAX_RT;
@ -1388,7 +1394,6 @@ dhcp6_startdiscover(void *arg)
logger(ifp->ctx, LOG_INFO, "%s: soliciting a DHCPv6 lease", ifp->name);
state = D6_STATE(ifp);
state->state = DH6S_DISCOVER;
state->start_uptime = uptime();
state->RTC = 0;
state->IMD = SOL_MAX_DELAY;
state->IRT = SOL_TIMEOUT;
@ -1462,9 +1467,6 @@ dhcp6_hasprefixdelegation(struct interface *ifp)
size_t i;
uint16_t t;
if (ifp->options->options & DHCPCD_NOPFXDLG)
return 0;
t = 0;
for (i = 0; i < ifp->options->ia_len; i++) {
if (t && t != ifp->options->ia[i].ia_type) {
@ -1551,7 +1553,6 @@ dhcp6_startconfirm(struct interface *ifp)
state = D6_STATE(ifp);
state->state = DH6S_CONFIRM;
state->start_uptime = uptime();
state->RTC = 0;
state->IMD = CNF_MAX_DELAY;
state->IRT = CNF_TIMEOUT;
@ -1582,7 +1583,6 @@ dhcp6_startinform(void *arg)
logger(ifp->ctx, LOG_INFO,
"%s: requesting DHCPv6 information", ifp->name);
state->state = DH6S_INFORM;
state->start_uptime = uptime();
state->RTC = 0;
state->IMD = INF_MAX_DELAY;
state->IRT = INF_TIMEOUT;
@ -1615,6 +1615,18 @@ dhcp6_startexpire(void *arg)
"%s: no advertising IPv6 router wants DHCP", ifp->name);
}
static void
dhcp6_finishrelease(void *arg)
{
struct interface *ifp;
struct dhcp6_state *state;
ifp = (struct interface *)arg;
state = D6_STATE(ifp);
state->state = DH6S_RELEASED;
dhcp6_drop(ifp, "RELEASE6");
}
static void
dhcp6_startrelease(struct interface *ifp)
{
@ -1625,22 +1637,25 @@ dhcp6_startrelease(struct interface *ifp)
return;
state->state = DH6S_RELEASE;
state->start_uptime = uptime();
state->RTC = 0;
state->IRT = REL_TIMEOUT;
state->MRT = 0;
/* MRC of REL_MAX_RC is optional in RFC 3315 18.1.6 */
#if 0
state->MRC = REL_MAX_RC;
//state->MRCcallback = dhcp6_failrelease;
state->MRCcallback = dhcp6_finishrelease;
#else
state->MRC = 0;
state->MRCcallback = NULL;
#endif
if (dhcp6_makemessage(ifp) == -1)
logger(ifp->ctx, LOG_ERR,
"%s: dhcp6_makemessage: %m", ifp->name);
else
/* XXX: We should loop a few times
* Luckily RFC3315 section 18.1.6 says this is optional */
//dhcp6_sendrelease(ifp);
dhcp6_sendmessage(ifp, NULL);
else {
dhcp6_sendrelease(ifp);
dhcp6_finishrelease(ifp);
}
}
static int
@ -1696,24 +1711,16 @@ dhcp6_checkstatusok(const struct interface *ifp,
return -1;
}
static struct ipv6_addr *
dhcp6_iffindaddr(struct interface *ifp, const struct in6_addr *addr,
const struct ipv6_addr *
dhcp6_iffindaddr(const struct interface *ifp, const struct in6_addr *addr,
short flags)
{
struct dhcp6_state *state;
struct ipv6_addr *ap;
const struct dhcp6_state *state;
const struct ipv6_addr *ap;
state = D6_STATE(ifp);
if (state) {
if ((state = D6_STATE(ifp)) != NULL) {
TAILQ_FOREACH(ap, &state->addrs, next) {
if (addr == NULL) {
if ((ap->flags &
(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) ==
(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED))
return ap;
} else if (ap->prefix_vltime &&
IN6_ARE_ADDR_EQUAL(&ap->addr, addr) &&
(!flags || ap->flags & flags))
if (ipv6_findaddrmatch(ap, addr, flags))
return ap;
}
}
@ -1726,11 +1733,15 @@ dhcp6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr,
{
struct interface *ifp;
struct ipv6_addr *ap;
struct dhcp6_state *state;
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
ap = dhcp6_iffindaddr(ifp, addr, flags);
if (ap)
return ap;
if ((state = D6_STATE(ifp)) != NULL) {
TAILQ_FOREACH(ap, &state->addrs, next) {
if (ipv6_findaddrmatch(ap, addr, flags))
return ap;
}
}
}
return NULL;
}
@ -1765,7 +1776,10 @@ dhcp6_findna(struct interface *ifp, uint16_t ot, const uint8_t *iaid,
continue;
}
iap = (const struct dhcp6_ia_addr *)D6_COPTION_DATA(o);
a = dhcp6_iffindaddr(ifp, &iap->addr, 0);
TAILQ_FOREACH(a, &state->addrs, next) {
if (ipv6_findaddrmatch(a, &iap->addr, 0))
break;
}
if (a == NULL) {
a = calloc(1, sizeof(*a));
if (a == NULL) {
@ -2043,15 +2057,13 @@ dhcp6_findia(struct interface *ifp, const struct dhcp6_message *m, size_t l,
continue;
}
if (code == D6_OPTION_IA_PD) {
if (!(ifo->options & DHCPCD_NOPFXDLG) &&
dhcp6_findpd(ifp, iaid, p, ol, acquired) == 0)
{
if (dhcp6_findpd(ifp, iaid, p, ol, acquired) == 0) {
logger(ifp->ctx, LOG_WARNING,
"%s: %s: DHCPv6 REPLY missing Prefix",
ifp->name, sfrom);
continue;
}
} else if (!(ifo->options & DHCPCD_PFXDLGONLY)) {
} else {
if (dhcp6_findna(ifp, code, iaid, p, ol, acquired) == 0)
{
logger(ifp->ctx, LOG_WARNING,
@ -2444,8 +2456,6 @@ dhcp6_delegate_prefix(struct interface *ifp)
}
TAILQ_FOREACH(ifd, ifp->ctx->ifaces, next) {
if (ifd->options->options & DHCPCD_NOPFXDLG)
continue;
k = 0;
carrier_warned = abrt = 0;
TAILQ_FOREACH(ap, &state->addrs, next) {
@ -2578,24 +2588,6 @@ dhcp6_find_delegates(struct interface *ifp)
return k;
}
static struct interface *
dhcp6_findpfxdlgif(struct interface *ifp)
{
struct interface *ifn;
if (ifp->options && ifp->options->options & DHCPCD_PFXDLGONLY)
return NULL;
if (ifp->ctx && ifp->ctx->ifaces) {
TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
if (strcmp(ifn->name, ifp->name) == 0 &&
ifn->options->options & DHCPCD_PFXDLGONLY)
return ifn;
}
}
return NULL;
}
/* ARGSUSED */
static void
dhcp6_handledata(void *arg)
@ -2606,7 +2598,7 @@ dhcp6_handledata(void *arg)
ssize_t bytes;
struct cmsghdr *cm;
struct in6_pktinfo pkt;
struct interface *ifp, *ifpx;
struct interface *ifp;
const char *op;
struct dhcp6_message *r;
struct dhcp6_state *state;
@ -2659,9 +2651,7 @@ dhcp6_handledata(void *arg)
}
TAILQ_FOREACH(ifp, dctx->ifaces, next) {
/* Ensure we work on the master interface */
if (ifp->index == (unsigned int)pkt.ipi6_ifindex &&
!(ifp->options->options & DHCPCD_PFXDLGONLY))
if (ifp->index == (unsigned int)pkt.ipi6_ifindex)
break;
}
if (ifp == NULL) {
@ -2671,18 +2661,6 @@ dhcp6_handledata(void *arg)
return;
}
r = (struct dhcp6_message *)ctx->rcvhdr.msg_iov[0].iov_base;
/* Which interface state is the IAID for? */
ifpx = dhcp6_findpfxdlgif(ifp);
if (ifpx && D6_STATE(ifpx)) {
state = D6_STATE(ifpx);
if (r->xid[0] == state->send->xid[0] &&
r->xid[1] == state->send->xid[1] &&
r->xid[2] == state->send->xid[2])
ifp = ifpx;
}
state = D6_STATE(ifp);
if (state == NULL || state->send == NULL) {
logger(ifp->ctx, LOG_DEBUG,
@ -2690,6 +2668,7 @@ dhcp6_handledata(void *arg)
return;
}
r = (struct dhcp6_message *)ctx->rcvhdr.msg_iov[0].iov_base;
/* We're already bound and this message is for another machine */
/* XXX DELEGATED? */
if (r->type != DHCP6_RECONFIGURE &&
@ -3185,43 +3164,6 @@ dhcp6_start1(void *arg)
if (dhcp6_findselfsla(ifp, NULL))
del_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT);
/* Create a 2nd interface to handle the PD state */
if (!(ifo->options & (DHCPCD_PFXDLGONLY | DHCPCD_PFXDLGMIX)) &&
dhcp6_hasprefixdelegation(ifp) > 1)
{
const char * const argv[] = { ifp->name };
struct if_head *ifs;
struct interface *ifn;
ifn = dhcp6_findpfxdlgif(ifp);
if (ifn == NULL) {
ifs = if_discover(ifp->ctx, -1, UNCONST(argv));
if (ifs) {
ifn = TAILQ_FIRST(ifs);
if (ifn) {
logger(ifp->ctx, LOG_INFO,
"%s: creating pseudo interface"
" to handle Prefix Delegation",
ifp->name);
ifp->options->options |=
DHCPCD_NOPFXDLG;
TAILQ_REMOVE(ifs, ifn, next);
TAILQ_INSERT_AFTER(ifp->ctx->ifaces,
ifp, ifn, next);
dhcpcd_initstate(ifn,
DHCPCD_PFXDLGONLY);
eloop_timeout_add_sec(ifp->ctx->eloop,
0, dhcpcd_startinterface, ifn);
}
while ((ifn = TAILQ_FIRST(ifs))) {
TAILQ_REMOVE(ifs, ifn, next);
if_free(ifn);
}
free(ifs);
}
}
}
if (state->state == DH6S_INFORM) {
add_option_mask(ifo->requestmask6, D6_OPTION_INFO_REFRESH_TIME);
dhcp6_startinform(ifp);
@ -3276,8 +3218,7 @@ dhcp6_start(struct interface *ifp, enum DH6S init_state)
gogogo:
state->state = init_state;
dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
AF_INET6, ifp,
ifp->options->options & DHCPCD_PFXDLGONLY ? ".pd" : "");
AF_INET6, ifp);
if (ipv6_linklocal(ifp) == NULL) {
logger(ifp->ctx, LOG_DEBUG,
"%s: delaying DHCPv6 soliciation for LL address",
@ -3314,7 +3255,6 @@ dhcp6_reboot(struct interface *ifp)
static void
dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
{
struct interface *ifpx;
struct dhcp6_state *state;
struct dhcpcd_ctx *ctx;
unsigned long long options;
@ -3341,18 +3281,7 @@ dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
else
options = 0;
dropdele = (options & (DHCPCD_STOPPING | DHCPCD_RELEASE) &&
(options &
(DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
(DHCPCD_EXITING | DHCPCD_PERSISTENT));
ifpx = dhcp6_findpfxdlgif(ifp);
if (ifpx) {
if (options & DHCPCD_EXITING)
ifpx->options->options |= DHCPCD_EXITING;
dhcp6_freedrop(ifpx, dropdele ? 1 : drop, reason);
TAILQ_REMOVE(ifp->ctx->ifaces, ifpx, next);
if_free(ifpx);
}
(options & DHCPCD_NODROP) != DHCPCD_NODROP);
if (ifp->ctx->eloop)
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
@ -3362,10 +3291,20 @@ dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
state = D6_STATE(ifp);
if (state) {
dhcp_auth_reset(&state->auth);
/* Failure to send the release may cause this function to
* re-enter */
if (state->state == DH6S_RELEASE) {
dhcp6_finishrelease(ifp);
return;
}
if (drop && options & DHCPCD_RELEASE) {
if (ifp->carrier == LINK_UP)
if (ifp->carrier == LINK_UP &&
state->state != DH6S_RELEASED)
{
dhcp6_startrelease(ifp);
return;
}
unlink(state->leasefile);
}
dhcp6_freedrop_addrs(ifp, drop, NULL);
@ -3375,9 +3314,7 @@ dhcp6_freedrop(struct interface *ifp, int drop, const char *reason)
state->new = NULL;
state->new_len = 0;
if (drop && state->old &&
(options &
(DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
(DHCPCD_EXITING | DHCPCD_PERSISTENT))
(options & DHCPCD_NODROP) != DHCPCD_NODROP)
{
if (reason == NULL)
reason = "STOP6";
@ -3598,8 +3535,7 @@ dhcp6_dump(struct interface *ifp)
}
TAILQ_INIT(&state->addrs);
dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
AF_INET6, ifp,
ifp->options->options & DHCPCD_PFXDLGONLY ? ".pd" : "");
AF_INET6, ifp);
if (dhcp6_readlease(ifp, 0) == -1) {
logger(ifp->ctx, LOG_ERR, "%s: %s: %m",
*ifp->name ? ifp->name : state->leasefile, __func__);

View File

@ -1,4 +1,4 @@
/* $NetBSD: dhcp6.h,v 1.9 2015/05/02 15:18:36 roy Exp $ */
/* $NetBSD: dhcp6.h,v 1.10 2015/07/09 10:15:34 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -166,12 +166,13 @@ enum DH6S {
DH6S_RENEW_REQUESTED,
DH6S_PROBE,
DH6S_DELEGATED,
DH6S_RELEASE
DH6S_RELEASE,
DH6S_RELEASED
};
struct dhcp6_state {
enum DH6S state;
time_t start_uptime;
struct timespec started;
/* Message retransmission timings */
struct timespec RT;
@ -234,6 +235,8 @@ struct dhcp6_state {
#ifdef INET6
void dhcp6_printoptions(const struct dhcpcd_ctx *,
const struct dhcp_opt *, size_t);
const struct ipv6_addr *dhcp6_iffindaddr(const struct interface *ifp,
const struct in6_addr *addr, short flags);
struct ipv6_addr *dhcp6_findaddr(struct dhcpcd_ctx *, const struct in6_addr *,
short);
size_t dhcp6_find_delegates(struct interface *);
@ -249,7 +252,6 @@ int dhcp6_dadcompleted(const struct interface *);
void dhcp6_drop(struct interface *, const char *);
int dhcp6_dump(struct interface *);
#else
#define dhcp6_findaddr(a, b, c) (0)
#define dhcp6_find_delegates(a) {}
#define dhcp6_start(a, b) (0)
#define dhcp6_reboot(a) {}

View File

@ -1,4 +1,4 @@
# $NetBSD: dhcpcd-definitions.conf,v 1.8 2015/05/16 23:31:32 roy Exp $
# $NetBSD: dhcpcd-definitions.conf,v 1.9 2015/07/09 10:15:34 roy Exp $
# Copyright (c) 2006-2015 Roy Marples
# All rights reserved
@ -77,7 +77,7 @@ define 56 string dhcp_message
define 57 uint16 dhcp_max_message_size
define 58 request uint32 dhcp_renewal_time
define 59 request uint32 dhcp_rebinding_time
define 60 binhex vendor_class_identifier
define 60 string vendor_class_identifier
define 61 binhex dhcp_client_identifier
define 64 string nisplus_domain
define 65 array ipaddress nisplus_servers
@ -112,6 +112,10 @@ define 81 embed fqdn
embed bitflags=0000NEOS flags
embed byte rcode1
embed byte rcode2
# dhcpcd always sets the E bit which means the fqdn itself is always
# RFC1035 encoded.
# The server MUST use the encoding as specified by the client as noted
# in RFC4702 Section 2.1.
embed domain fqdn
# Option 82 is for Relay Agents and DHCP servers
@ -285,7 +289,13 @@ encap 1 binhex vpn_id
encap 255 flag global
# Options 222 and 223 are unused, RFC3942
# Options 224-254 are reserved for Private Use
# However, an expired RFC for Web Proxy Auto Discovery Protocol does define
# Option 252 which is commonly used by major browsers.
# Apparently the code was assigned by agreement of the DHC working group chair.
define 252 string wpad_url
# Option 255 End
##############################################################################

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: dhcpcd-embedded.c,v 1.9 2015/05/16 23:31:32 roy Exp $");
__RCSID("$NetBSD: dhcpcd-embedded.c,v 1.10 2015/07/09 10:15:34 roy Exp $");
/*
* DO NOT EDIT!
@ -98,7 +98,7 @@ const char * const dhcpcd_embedded_conf[] = {
"define 57 uint16 dhcp_max_message_size",
"define 58 request uint32 dhcp_renewal_time",
"define 59 request uint32 dhcp_rebinding_time",
"define 60 binhex vendor_class_identifier",
"define 60 string vendor_class_identifier",
"define 61 binhex dhcp_client_identifier",
"define 64 string nisplus_domain",
"define 65 array ipaddress nisplus_servers",
@ -201,6 +201,7 @@ const char * const dhcpcd_embedded_conf[] = {
"encap 0 string nvt",
"encap 1 binhex vpn_id",
"encap 255 flag global",
"define 252 string wpad_url",
"definend 1 binhex source_address",
"definend 2 binhex target_address",
"definend 3 index embed prefix_information",

View File

@ -1,4 +1,4 @@
/* $NetBSD: dhcpcd-embedded.h,v 1.8 2015/05/16 23:31:32 roy Exp $ */
/* $NetBSD: dhcpcd-embedded.h,v 1.9 2015/07/09 10:15:34 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -27,7 +27,7 @@
* SUCH DAMAGE.
*/
#define INITDEFINES 121
#define INITDEFINES 122
#define INITDEFINENDS 6
#define INITDEFINE6S 68

View File

@ -1,10 +1,10 @@
# $NetBSD: 01-test,v 1.7 2014/11/26 16:05:14 roy Exp $
# $NetBSD: 01-test,v 1.8 2015/07/09 10:15:34 roy Exp $
# Just echo our DHCP options we have
# Echo the interface flags, reason and message options
if [ "$reason" = "TEST" ]; then
set | grep "^\(interface\|pid\|reason\|profile\|skip_hooks\)=" | sort
set | grep "^if\(carrier\|flags\|mtu\|wireless\|ssid\)=" | sort
set | grep "^\(new_\|old_\|ra_count=\|ra[0-9]*_\)" | sort
set | grep "^\(new_\|old_\|nd[0-9]*_\)" | sort
exit 0
fi

View File

@ -1,4 +1,4 @@
.\" $NetBSD: dhcpcd-run-hooks.8.in,v 1.14 2015/05/16 23:31:32 roy Exp $
.\" $NetBSD: dhcpcd-run-hooks.8.in,v 1.15 2015/07/09 10:15:34 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 May 14, 2015
.Dd June 29, 2015
.Dt DHCPCD-RUN-HOOKS 8
.Os
.Sh NAME
@ -93,7 +93,7 @@ dhcpcd successfully requested a lease from a DHCP server.
.It Dv DELEGATED6
dhcpcd assigned a delegated prefix to the interface.
.It Dv IPV4LL
dhcpcd failed to contact any DHCP servers but did obtain an IPV4LL address.
dhcpcd obtaind an IPV4LL address, or one was removed.
.It Dv STATIC
dhcpcd has been configured with a static configuration which has not been
obtained from a DHCP server.
@ -184,9 +184,9 @@ if the
.Ev interface
is down, otherwise
.Dv false .
.It Ev $if_oneup
.Dv true
if any interface is up, otherwise false.
.It Ev $af_waiting
Address family waiting for, as defined in
.Xr dhcpcd.conf 5 .
.It Ev $profile
the name of the profile selected from
.Xr dhcpcd.conf 5 .

View File

@ -1,5 +1,5 @@
#!/bin/sh
# $NetBSD: dhcpcd-run-hooks.in,v 1.9 2015/03/26 10:26:37 roy Exp $
# $NetBSD: dhcpcd-run-hooks.in,v 1.10 2015/07/09 10:15:34 roy Exp $
# dhcpcd client configuration script
@ -9,10 +9,12 @@ case "$reason" in
ifsuffix=".ra";;
INFORM6|BOUND6|RENEW6|REBIND6|REBOOT6|EXPIRE6|RELEASE6|STOP6)
ifsuffix=".dhcp6";;
IPV4LL)
ifsuffix=".ipv4ll";;
*)
ifsuffix=".dhcp";;
esac
ifname="$interface$ifsuffix${ifclass+.}$ifclass"
ifname="$interface$ifsuffix"
from=from
signature_base="# Generated by dhcpcd"

View File

@ -1,4 +1,4 @@
.\" $NetBSD: dhcpcd.8.in,v 1.42 2015/05/16 23:31:32 roy Exp $
.\" $NetBSD: dhcpcd.8.in,v 1.43 2015/07/09 10:15:34 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 May 9, 2015
.Dd July 3, 2015
.Dt DHCPCD 8
.Os
.Sh NAME
@ -338,7 +338,10 @@ This causes an existing
process running on the
.Ar interface
to release its lease and de-configure the
.Ar interface .
.Ar interface
regardless of the
.Fl p , Fl Fl persistent
option.
If no
.Ar interface
is specified then this applies to all interfaces.
@ -499,10 +502,13 @@ This will signal an existing
.Nm
process running on the
.Ar interface
to de-configure the
.Ar interface
and exit.
to exit.
If no interface is specified, then the above is applied to all interfaces.
See the
.Fl p , Fl Fl persistent
option to control configuration persistence on exit,
which is enabled by default in
.Xr dhcpcd.conf 5 .
.Nm
then waits until this process has exited.
.It Fl y , Fl Fl reboot Ar seconds
@ -609,9 +615,6 @@ Use the
or
.Fl 6
flags to specify an address family.
Pass a 2nd
.Fl U, Fl Fl dumplease option to dump a secondary lease, such as
DHCPv6 Prefix Delegation when not being mixed with another IA type.
.It Fl V, Fl Fl variables
Display a list of option codes, the associated variable and encoding for use in
.Xr dhcpcd-run-hooks 8 .
@ -718,7 +721,6 @@ running on the
Control socket to the master daemon.
.It Pa @RUNDIR@/dhcpcd.unpriv.sock
Unpriviledged socket to the master daemon, only allows state retrieval.
Control socket to the master daemon.
.It Pa @RUNDIR@/dhcpcd\- Ns Ar interface Ns .sock
Control socket to per interface daemon.
.El
@ -735,7 +737,7 @@ RFC\ 3004, RFC\ 3118, RFC\ 3203, RFC\ 3315, RFC\ 3361, RFC\ 3633, RFC\ 3396,
RFC\ 3397, RFC\ 3442, RFC\ 3495, RFC\ 3925, RFC\ 3927, RFC\ 4039, RFC\ 4075,
RFC\ 4242, RFC\ 4361, RFC\ 4390, RFC\ 4702, RFC\ 4074, RFC\ 4861, RFC\ 4833,
RFC\ 4941, RFC\ 5227, RFC\ 5942, RFC\ 5969, RFC\ 6106, RFC\ 6334, RFC\ 6603,
RFC\ 6704, RFC\ 7217.
RFC\ 6704, RFC\ 7217, RFC\ 7550.
.Sh AUTHORS
.An Roy Marples Aq Mt roy@marples.name
.Sh BUGS

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: dhcpcd.c,v 1.25 2015/05/16 23:31:32 roy Exp $");
__RCSID("$NetBSD: dhcpcd.c,v 1.26 2015/07/09 10:15:34 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -64,6 +64,7 @@ const char dhcpcd_copyright[] = "Copyright (c) 2006-2015 Roy Marples";
#include "if.h"
#include "if-options.h"
#include "ipv4.h"
#include "ipv4ll.h"
#include "ipv6.h"
#include "ipv6nd.h"
#include "script.h"
@ -209,62 +210,94 @@ handle_exit_timeout(void *arg)
dhcpcd_daemonise(ctx);
}
int
dhcpcd_oneup(struct dhcpcd_ctx *ctx)
static const char *
dhcpcd_af(int af)
{
const struct interface *ifp;
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
if (D_STATE_RUNNING(ifp) ||
RS_STATE_RUNNING(ifp) ||
D6_STATE_RUNNING(ifp))
return 1;
switch (af) {
case AF_UNSPEC:
return "IP";
case AF_INET:
return "IPv4";
case AF_INET6:
return "IPv6";
default:
return NULL;
}
return 0;
}
static int
dhcpcd_ifipwaited(struct interface *ifp, unsigned long long opts)
int
dhcpcd_ifafwaiting(const struct interface *ifp)
{
unsigned long long opts;
if (opts & DHCPCD_WAITIP4 && !ipv4_ifaddrexists(ifp))
return 0;
if (opts & DHCPCD_WAITIP6 && !ipv6_iffindaddr(ifp, NULL))
return 0;
opts = ifp->options->options;
if (opts & DHCPCD_WAITIP4 && !ipv4_hasaddr(ifp))
return AF_INET;
if (opts & DHCPCD_WAITIP6 && !ipv6_hasaddr(ifp))
return AF_INET6;
if (opts & DHCPCD_WAITIP &&
!(opts & (DHCPCD_WAITIP4 | DHCPCD_WAITIP6)) &&
!ipv4_ifaddrexists(ifp) &&
!ipv6_iffindaddr(ifp, NULL))
return 0;
return 1;
!ipv4_hasaddr(ifp) && !ipv6_hasaddr(ifp))
return AF_UNSPEC;
return AF_MAX;
}
int
dhcpcd_afwaiting(const struct dhcpcd_ctx *ctx)
{
unsigned long long opts;
const struct interface *ifp;
int af;
if (!(ctx->options & DHCPCD_WAITOPTS))
return AF_MAX;
opts = ctx->options;
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
if (opts & (DHCPCD_WAITIP | DHCPCD_WAITIP4) &&
ipv4_hasaddr(ifp))
opts &= ~(DHCPCD_WAITIP | DHCPCD_WAITIP4);
if (opts & (DHCPCD_WAITIP | DHCPCD_WAITIP6) &&
ipv6_hasaddr(ifp))
opts &= ~(DHCPCD_WAITIP | DHCPCD_WAITIP6);
if (!(opts & DHCPCD_WAITOPTS))
break;
}
if (opts & DHCPCD_WAITIP)
af = AF_UNSPEC;
else if (opts & DHCPCD_WAITIP4)
af = AF_INET;
else if (opts & DHCPCD_WAITIP6)
af = AF_INET6;
else
return AF_MAX;
return af;
}
static int
dhcpcd_ipwaited(struct dhcpcd_ctx *ctx)
{
struct interface *ifp;
int af;
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
if (ifp->options->options & DHCPCD_WAITOPTS) {
if (!dhcpcd_ifipwaited(ifp, ifp->options->options)) {
logger(ctx, LOG_DEBUG,
"%s: waiting for an ip address",
ifp->name);
return 0;
}
if ((af = dhcpcd_ifafwaiting(ifp)) != AF_MAX) {
logger(ctx, LOG_DEBUG,
"%s: waiting for an %s address",
ifp->name, dhcpcd_af(af));
return 0;
}
}
if (!(ctx->options & DHCPCD_WAITOPTS))
return 1;
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
if (dhcpcd_ifipwaited(ifp, ctx->options))
return 1;
if ((af = dhcpcd_afwaiting(ctx)) != AF_MAX) {
logger(ctx, LOG_DEBUG,
"waiting for an %s address",
dhcpcd_af(af));
return 0;
}
logger(ctx, LOG_DEBUG, "waiting for an ip address");
return 0;
return 1;
}
/* Returns the pid of the child, otherwise 0. */
@ -351,6 +384,7 @@ dhcpcd_drop(struct interface *ifp, int stop)
dhcp6_drop(ifp, stop ? NULL : "EXPIRE6");
ipv6nd_drop(ifp);
ipv6_drop(ifp);
ipv4ll_drop(ifp);
dhcp_drop(ifp, stop ? "STOP" : "EXPIRE");
arp_close(ifp);
}
@ -411,19 +445,16 @@ configure_interface1(struct interface *ifp)
ifp->metric = (unsigned int)ifo->metric;
if (!(ifo->options & DHCPCD_IPV4))
ifo->options &= ~(DHCPCD_DHCP | DHCPCD_IPV4LL);
ifo->options &= ~(DHCPCD_DHCP | DHCPCD_IPV4LL | DHCPCD_WAITIP4);
if (!(ifo->options & DHCPCD_IPV6))
ifo->options &= ~(DHCPCD_IPV6RS | DHCPCD_DHCP6);
ifo->options &=
~(DHCPCD_IPV6RS | DHCPCD_DHCP6 | DHCPCD_WAITIP6);
if (ifo->options & DHCPCD_SLAACPRIVATE &&
!(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 */
if (ifp->options->options & DHCPCD_PFXDLGONLY)
ifp->options->options &= ~(DHCPCD_IPV4 | DHCPCD_IPV6RS);
/* We want to disable kernel interface RA as early as possible. */
if (ifo->options & DHCPCD_IPV6RS &&
!(ifp->ctx->options & DHCPCD_DUMPLEASE))
@ -731,8 +762,6 @@ warn_iaid_conflict(struct interface *ifp, uint8_t *iaid)
TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
if (ifn == ifp)
continue;
if (ifn->options->options & DHCPCD_PFXDLGONLY)
continue;
if (memcmp(ifn->options->iaid, iaid,
sizeof(ifn->options->iaid)) == 0)
break;
@ -744,7 +773,7 @@ warn_iaid_conflict(struct interface *ifp, uint8_t *iaid)
}
/* This is only a problem if the interfaces are on the same network. */
if (ifn && strcmp(ifp->name, ifn->name))
if (ifn)
logger(ifp->ctx, LOG_ERR,
"%s: IAID conflicts with one assigned to %s",
ifp->name, ifn->name);
@ -802,17 +831,14 @@ dhcpcd_startinterface(void *arg)
if (ifp->ctx->duid == NULL) {
if (duid_init(ifp) == 0)
return;
if (!(ifo->options & DHCPCD_PFXDLGONLY))
logger(ifp->ctx, LOG_INFO, "DUID %s",
hwaddr_ntoa(ifp->ctx->duid,
ifp->ctx->duid_len,
buf, sizeof(buf)));
logger(ifp->ctx, LOG_INFO, "DUID %s",
hwaddr_ntoa(ifp->ctx->duid,
ifp->ctx->duid_len,
buf, sizeof(buf)));
}
}
if (ifo->options & (DHCPCD_DUID | DHCPCD_IPV6) &&
!(ifo->options & DHCPCD_PFXDLGONLY))
{
if (ifo->options & (DHCPCD_DUID | DHCPCD_IPV6)) {
/* Report IAIDs */
logger(ifp->ctx, LOG_INFO, "%s: IAID %s", ifp->name,
hwaddr_ntoa(ifo->iaid, sizeof(ifo->iaid),
@ -868,8 +894,11 @@ dhcpcd_startinterface(void *arg)
}
}
if (ifo->options & DHCPCD_IPV4)
dhcp_start(ifp);
if (ifo->options & DHCPCD_IPV4) {
/* Ensure we have an IPv4 state before starting DHCP */
if (ipv4_getstate(ifp) != NULL)
dhcp_start(ifp);
}
}
static void
@ -1129,16 +1158,8 @@ stop_all_interfaces(struct dhcpcd_ctx *ctx, int do_release)
{
struct interface *ifp;
/* drop_dhcp could change the order, so we do it like this. */
for (;;) {
/* Be sane and drop the last config first,
* skipping any pseudo interfaces */
TAILQ_FOREACH_REVERSE(ifp, ctx->ifaces, if_head, next) {
if (!(ifp->options->options & DHCPCD_PFXDLGONLY))
break;
}
if (ifp == NULL)
break;
/* Drop the last interface first */
while ((ifp = TAILQ_LAST(ctx->ifaces, if_head)) != NULL) {
if (do_release) {
ifp->options->options |= DHCPCD_RELEASE;
ifp->options->options &= ~DHCPCD_PERSISTENT;
@ -1220,6 +1241,8 @@ dhcpcd_getinterfaces(void *arg)
len++;
if (D_STATE_RUNNING(ifp))
len++;
if (IPV4LL_STATE_RUNNING(ifp))
len++;
if (RS_STATE_RUNNING(ifp))
len++;
if (D6_STATE_RUNNING(ifp))
@ -1419,10 +1442,7 @@ main(int argc, char **argv)
i = 1;
break;
case 'U':
if (i == 3)
i = 4;
else if (i != 4)
i = 3;
i = 3;
break;
case 'V':
i = 2;
@ -1482,8 +1502,6 @@ main(int argc, char **argv)
ctx.options |= DHCPCD_TEST;
else
ctx.options |= DHCPCD_DUMPLEASE;
if (i == 4)
ctx.options |= DHCPCD_PFXDLGONLY;
ctx.options |= DHCPCD_PERSISTENT;
ctx.options &= ~DHCPCD_DAEMONISE;
}
@ -1578,8 +1596,6 @@ main(int argc, char **argv)
}
}
configure_interface(ifp, ctx.argc, ctx.argv, 0);
if (ctx.options & DHCPCD_PFXDLGONLY)
ifp->options->options |= DHCPCD_PFXDLGONLY;
if (family == 0 || family == AF_INET) {
if (dhcp_dump(ifp) == -1)
i = 1;
@ -1625,10 +1641,6 @@ main(int argc, char **argv)
}
#endif
if (geteuid())
logger(&ctx, LOG_WARNING,
PACKAGE " will not work correctly unless run as root");
#ifdef USE_SIGNALS
if (sig != 0) {
pid = read_pid(ctx.pidfile);

View File

@ -1,4 +1,4 @@
.\" $NetBSD: dhcpcd.conf.5.in,v 1.21 2015/05/16 23:31:32 roy Exp $
.\" $NetBSD: dhcpcd.conf.5.in,v 1.22 2015/07/09 10:15:34 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 May 15, 2015
.Dd July 9, 2015
.Dt DHCPCD.CONF 5
.Os
.Sh NAME
@ -263,6 +263,8 @@ Unless a
.Ar sla_id
of 0 is assigned, a reject route is installed for the Delegated Prefix to
stop unallocated addresses being resolved upstream.
This reject route is in essence SLA 0, thus you need space within the prefix
to assign a SLA per interface.
If no
.Ar interface
is given then we will assign a prefix to every other interface with a
@ -309,30 +311,23 @@ The DHCPv6 server is going to provide us with an IPv6 address, a default
route and a /64 subnet to be delegated to the internal interface.
The eth1 interface will be automatically configured
for IPv6 using the first address (::1) from the delegated prefix.
A second prefix is requested and assigned to two other interfaces.
.Xr rtadvd 8
can be used with an empty configuration file on eth1 to provide automatic
can be used with an empty configuration file on eth1, eth2 and eth3,
to provide automatic
IPv6 address configuration for the internal network.
.Bd -literal -indent
noipv6rs # disable routing solicitation
denyinterfaces eth2 # Don't touch eth2 at all
noipv6rs # disable routing solicitation
denyinterfaces eth2 # Don't touch eth2 at all
interface eth0
ipv6rs # enable routing solicitation get the
# default IPv6 route
ia_na 1 # request an IPv6 address
ia_pd 2 eth1/0 # get a /64 and assign it to eth1
ipv6rs # enable routing solicitation get the
# default IPv6 route
ia_na 1 # request an IPv6 address
ia_pd 2 eth1/0 # request a PD and assign it to eth1
ia_pd 3 eth2/1 eth3/2 # req a PD and assign it to eth2 and eth3
# we cannot use SLA 0 above because we are
# assinging the PD to more than one interface
.Ed
.It Ic ia_pd_mix
To be RFC compliant,
.Nm dhcpcd
cannot mix Prefix Delegation with other DHCPv6 address types in the same
session.
This has a number of issues: additional DHCP traffic and potential collisions
between options.
.Ic ia_pd_mix
enables
.Li draft-ietf-dhc-dhcpv6-stateful-issues-06
support so that Prefix Delegation can be mixed with other address types in
the same session.
.It Ic ipv4only
Only configure IPv4.
.It Ic ipv6only
@ -413,6 +408,8 @@ Don't send any ARP requests.
This also disables IPv4LL.
.It Ic noauthrequired
Don't require authentication even though we requested it.
.It Ic nodelay
Don't delay for an initial randomised time when starting protocols.
.It Ic nodev
Don't load
.Pa /dev

View File

@ -1,4 +1,4 @@
/* $NetBSD: dhcpcd.h,v 1.11 2015/05/16 23:31:32 roy Exp $ */
/* $NetBSD: dhcpcd.h,v 1.12 2015/07/09 10:15:34 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -52,11 +52,13 @@
#define LINK_DOWN -1
#define IF_DATA_IPV4 0
#define IF_DATA_DHCP 1
#define IF_DATA_IPV6 2
#define IF_DATA_IPV6ND 3
#define IF_DATA_DHCP6 4
#define IF_DATA_MAX 5
#define IF_DATA_ARP 1
#define IF_DATA_IPV4LL 2
#define IF_DATA_DHCP 3
#define IF_DATA_IPV6 4
#define IF_DATA_IPV6ND 5
#define IF_DATA_DHCP6 6
#define IF_DATA_MAX 7
/* If the interface does not support carrier status (ie PPP),
* dhcpcd can poll it for the relevant flags periodically */
@ -164,7 +166,8 @@ extern const int dhcpcd_signals[];
extern const size_t dhcpcd_signals_len;
#endif
int dhcpcd_oneup(struct dhcpcd_ctx *);
int dhcpcd_ifafwaiting(const struct interface *);
int dhcpcd_afwaiting(const struct dhcpcd_ctx *);
pid_t dhcpcd_daemonise(struct dhcpcd_ctx *);
int dhcpcd_handleargs(struct dhcpcd_ctx *, struct fd_list *, int, char **);

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: duid.c,v 1.8 2015/03/26 10:26:37 roy Exp $");
__RCSID("$NetBSD: duid.c,v 1.9 2015/07/09 10:15:34 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -143,7 +143,8 @@ duid_get(unsigned char *d, const struct interface *ifp)
}
len = duid_make(d, ifp, DUID_LLT);
x = fprintf(fp, "%s\n", hwaddr_ntoa(d, len, line, sizeof(line)));
fclose(fp);
if (fclose(fp) == EOF)
x = -1;
/* Failed to write the duid? scrub it, we cannot use it */
if (x < 1) {
logger(ifp->ctx, LOG_ERR, "error writing DUID: %s: %m", DUID);

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: if-bsd.c,v 1.21 2015/05/16 23:31:32 roy Exp $");
__RCSID("$NetBSD: if-bsd.c,v 1.22 2015/07/09 10:15:34 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -296,7 +296,7 @@ const char *if_pfname = "Berkley Packet Filter";
int
if_openrawsocket(struct interface *ifp, uint16_t protocol)
{
struct dhcp_state *state;
struct ipv4_state *state;
int fd = -1;
struct ifreq ifr;
int ibuf_len = 0;
@ -321,8 +321,7 @@ if_openrawsocket(struct interface *ifp, uint16_t protocol)
if (fd == -1)
return -1;
state = D_STATE(ifp);
state = IPV4_STATE(ifp);
memset(&pv, 0, sizeof(pv));
if (ioctl(fd, BIOCVERSION, &pv) == -1)
goto eexit;
@ -384,7 +383,6 @@ if_sendrawpacket(const struct interface *ifp, uint16_t protocol,
struct iovec iov[2];
struct ether_header hw;
int fd;
const struct dhcp_state *state;
memset(&hw, 0, ETHER_HDR_LEN);
memset(&hw.ether_dhost, 0xff, ETHER_ADDR_LEN);
@ -393,11 +391,7 @@ if_sendrawpacket(const struct interface *ifp, uint16_t protocol,
iov[0].iov_len = ETHER_HDR_LEN;
iov[1].iov_base = UNCONST(data);
iov[1].iov_len = len;
state = D_CSTATE(ifp);
if (protocol == ETHERTYPE_ARP)
fd = state->arp_fd;
else
fd = state->raw_fd;
fd = ipv4_protocol_fd(ifp, protocol);
return writev(fd, iov, 2);
}
@ -411,13 +405,10 @@ if_readrawpacket(struct interface *ifp, uint16_t protocol,
struct bpf_hdr packet;
ssize_t bytes;
const unsigned char *payload;
struct dhcp_state *state;
struct ipv4_state *state;
state = D_STATE(ifp);
if (protocol == ETHERTYPE_ARP)
fd = state->arp_fd;
else
fd = state->raw_fd;
state = IPV4_STATE(ifp);
fd = ipv4_protocol_fd(ifp, protocol);
*flags = 0;
for (;;) {
@ -518,6 +509,7 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct rt_msghdr *rtm)
else
rt->net.s_addr = INADDR_BROADCAST;
COPYOUT(rt->gate, rti_info[RTAX_GATEWAY]);
COPYOUT(rt->src, rti_info[RTAX_IFA]);
if (rtm->rtm_index)
rt->iface = if_findindex(ctx->ifaces, rtm->rtm_index);

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: if-options.c,v 1.24 2015/05/16 23:31:32 roy Exp $");
__RCSID("$NetBSD: if-options.c,v 1.25 2015/07/09 10:15:34 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -97,13 +97,14 @@
#define O_CONTROLGRP O_BASE + 34
#define O_SLAAC O_BASE + 35
#define O_GATEWAY O_BASE + 36
#define O_PFXDLGMIX O_BASE + 37
// unassigned O_BASE + 37
#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
#define O_DEFINEND O_BASE + 43
#define O_NODELAY O_BASE + 44
const struct option cf_options[] = {
{"background", no_argument, NULL, 'b'},
@ -195,9 +196,9 @@ const struct option cf_options[] = {
{"controlgroup", required_argument, NULL, O_CONTROLGRP},
{"slaac", required_argument, NULL, O_SLAAC},
{"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},
{"nodelay", no_argument, NULL, O_NODELAY},
{NULL, 0, NULL, '\0'}
};
@ -472,7 +473,6 @@ parse_addr(struct dhcpcd_ctx *ctx,
struct in_addr *addr, struct in_addr *net, const char *arg)
{
char *p;
int i;
if (arg == NULL || *arg == '\0') {
if (addr != NULL)
@ -482,10 +482,13 @@ parse_addr(struct dhcpcd_ctx *ctx,
return 0;
}
if ((p = strchr(arg, '/')) != NULL) {
int e;
intmax_t i;
*p++ = '\0';
if (net != NULL &&
(sscanf(p, "%d", &i) != 1 ||
inet_cidrtoaddr(i, net) != 0))
i = strtoi(p, NULL, 10, 0, 32, &e);
if (e != 0 ||
(net != NULL && inet_cidrtoaddr((int)i, net) != 0))
{
logger(ctx, LOG_ERR, "`%s' is not a valid CIDR", p);
return -1;
@ -1634,7 +1637,7 @@ err_sla:
else if (strcasecmp(arg, "ascii") == 0)
t |= STRING | ASCII;
else if (strcasecmp(arg, "domain") == 0)
t |= STRING | DOMAIN | RFC3397;
t |= STRING | DOMAIN | RFC1035;
else if (strcasecmp(arg, "dname") == 0)
t |= STRING | DOMAIN;
else if (strcasecmp(arg, "binhex") == 0)
@ -1661,7 +1664,7 @@ err_sla:
l = 0;
}
if (t & ARRAY && t & (STRING | BINHEX) &&
!(t & (RFC3397 | DOMAIN)))
!(t & (RFC1035 | DOMAIN)))
{
logger(ctx, LOG_WARNING, "ignoring array for strings");
t &= ~ARRAY;
@ -2011,12 +2014,12 @@ err_sla:
else
ifo->options &= ~DHCPCD_SLAACPRIVATE;
break;
case O_PFXDLGMIX:
ifo->options |= DHCPCD_PFXDLGMIX;
break;
case O_BOOTP:
ifo->options |= DHCPCD_BOOTP;
break;
case O_NODELAY:
ifo->options &= ~DHCPCD_INITIAL_DELAY;
break;
default:
return 0;
}
@ -2099,7 +2102,7 @@ read_config(struct dhcpcd_ctx *ctx,
char *line, *buf, *option, *p;
size_t buflen;
ssize_t vlen;
int skip = 0, have_profile = 0;
int skip, have_profile, new_block, had_block;
#ifndef EMBEDDED_CONFIG
const char * const *e;
size_t ol;
@ -2116,7 +2119,7 @@ read_config(struct dhcpcd_ctx *ctx,
logger(ctx, LOG_ERR, "%s: %m", __func__);
return NULL;
}
ifo->options |= DHCPCD_DAEMONISE | DHCPCD_LINK;
ifo->options |= DHCPCD_DAEMONISE | DHCPCD_LINK | DHCPCD_INITIAL_DELAY;
#ifdef PLUGIN_DEV
ifo->options |= DHCPCD_DEV;
#endif
@ -2273,6 +2276,8 @@ read_config(struct dhcpcd_ctx *ctx,
ifo->mtime = sb.st_mtime;
ldop = edop = NULL;
skip = have_profile = new_block = 0;
had_block = ifname == NULL ? 1 : 0;
while ((line = get_line(&buf, &buflen, fp))) {
option = strsep(&line, " \t");
if (line)
@ -2285,10 +2290,16 @@ read_config(struct dhcpcd_ctx *ctx,
*(p - 1) != '\\')
*p-- = '\0';
}
if (skip == 0 && new_block) {
had_block = 1;
new_block = 0;
ifo->options &= ~DHCPCD_WAITOPTS;
}
/* Start of an interface block, skip if not ours */
if (strcmp(option, "interface") == 0) {
char **n;
new_block = 1;
if (ifname && line && strcmp(line, ifname) == 0)
skip = 0;
else
@ -2315,6 +2326,7 @@ read_config(struct dhcpcd_ctx *ctx,
}
/* Start of an ssid block, skip if not ours */
if (strcmp(option, "ssid") == 0) {
new_block = 1;
if (ssid && line && strcmp(line, ssid) == 0)
skip = 0;
else
@ -2323,6 +2335,7 @@ read_config(struct dhcpcd_ctx *ctx,
}
/* Start of a profile block, skip if not ours */
if (strcmp(option, "profile") == 0) {
new_block = 1;
if (profile && line && strcmp(line, profile) == 0) {
skip = 0;
have_profile = 1;
@ -2347,6 +2360,8 @@ read_config(struct dhcpcd_ctx *ctx,
return NULL;
}
if (!had_block)
ifo->options &= ~DHCPCD_WAITOPTS;
finish_config(ifo);
return ifo;
}
@ -2356,18 +2371,27 @@ add_options(struct dhcpcd_ctx *ctx, const char *ifname,
struct if_options *ifo, int argc, char **argv)
{
int oi, opt, r;
unsigned long long wait_opts;
if (argc == 0)
return 1;
optind = 0;
r = 1;
/* Don't apply the command line wait options to each interface,
* only use the dhcpcd.conf entry for that. */
if (ifname != NULL)
wait_opts = ifo->options & DHCPCD_WAITOPTS;
while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
{
r = parse_option(ctx, ifname, ifo, opt, optarg, NULL, NULL);
if (r != 1)
break;
}
if (ifname != NULL) {
ifo->options &= ~DHCPCD_WAITOPTS;
ifo->options |= wait_opts;
}
finish_config(ifo);
return r;

View File

@ -1,4 +1,4 @@
/* $NetBSD: if-options.h,v 1.11 2015/05/16 23:31:32 roy Exp $ */
/* $NetBSD: if-options.h,v 1.12 2015/07/09 10:15:34 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -106,19 +106,21 @@
#define DHCPCD_IAID (1ULL << 48)
#define DHCPCD_DHCP (1ULL << 49)
#define DHCPCD_DHCP6 (1ULL << 50)
#define DHCPCD_NOPFXDLG (1ULL << 51)
#define DHCPCD_PFXDLGONLY (1ULL << 52)
#define DHCPCD_PFXDLGMIX (1ULL << 53)
// unassigned (1ULL << 51)
// unassigned (1ULL << 52)
// unassinged (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_INITIAL_DELAY (1ULL << 58)
#define DHCPCD_WAITOPTS (DHCPCD_WAITIP | DHCPCD_WAITIP4 | DHCPCD_WAITIP6)
#define DHCPCD_NODROP (DHCPCD_EXITING | DHCPCD_PERSISTENT)
#define DHCPCD_WARNINGS (DHCPCD_CSR_WARNED | \
#define DHCPCD_WAITOPTS (DHCPCD_WAITIP | DHCPCD_WAITIP4 | DHCPCD_WAITIP6)
#define DHCPCD_WARNINGS (DHCPCD_CSR_WARNED | \
DHCPCD_ROUTER_HOST_ROUTE_WARNED)
#define DHCPCD_CONF (DHCPCD_NOPFXDLG | DHCPCD_PFXDLGONLY)
extern const struct option cf_options[];

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: if.c,v 1.13 2015/05/02 15:18:37 roy Exp $");
__RCSID("$NetBSD: if.c,v 1.14 2015/07/09 10:15:34 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -70,6 +70,7 @@
#include "if.h"
#include "if-options.h"
#include "ipv4.h"
#include "ipv4ll.h"
#include "ipv6nd.h"
#ifdef __QNX__
@ -83,8 +84,9 @@ if_free(struct interface *ifp)
if (ifp == NULL)
return;
ipv4_free(ifp);
ipv4ll_free(ifp);
dhcp_free(ifp);
ipv4_free(ifp);
dhcp6_free(ifp);
ipv6nd_free(ifp);
ipv6_free(ifp);
@ -551,13 +553,11 @@ if_findindexname(struct if_head *ifaces, unsigned int idx, const char *name)
struct interface *ifp;
TAILQ_FOREACH(ifp, ifaces, next) {
if ((ifp->options == NULL ||
!(ifp->options->options & DHCPCD_PFXDLGONLY)) &&
((name && strcmp(ifp->name, name) == 0) ||
if ((name && strcmp(ifp->name, name) == 0) ||
#ifdef __linux__
(name && strcmp(ifp->alias, name) == 0) ||
#endif
(!name && ifp->index == idx)))
(!name && ifp->index == idx))
return ifp;
}
}
@ -606,14 +606,6 @@ if_cmp(const struct interface *si, const struct interface *ti)
int r;
#endif
/* Always prefer master interfaces */
if (!(si->options->options & DHCPCD_PFXDLGONLY) &&
ti->options->options & DHCPCD_PFXDLGONLY)
return -1;
if (si->options->options & DHCPCD_PFXDLGONLY &&
!(ti->options->options & DHCPCD_PFXDLGONLY))
return 1;
/* Check carrier status first */
if (si->carrier > ti->carrier)
return -1;

View File

@ -1,4 +1,4 @@
/* $NetBSD: if.h,v 1.10 2015/05/02 15:18:37 roy Exp $ */
/* $NetBSD: if.h,v 1.11 2015/07/09 10:15:34 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -85,14 +85,6 @@
((addr & IN_CLASSB_NET) == 0xc0a80000))
#endif
#define LINKLOCAL_ADDR 0xa9fe0000
#define LINKLOCAL_MASK IN_CLASSB_NET
#define LINKLOCAL_BRDC (LINKLOCAL_ADDR | ~LINKLOCAL_MASK)
#ifndef IN_LINKLOCAL
# define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == LINKLOCAL_ADDR)
#endif
#define RAW_EOF 1 << 0
#define RAW_PARTIALCSUM 2 << 0

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: ipv4.c,v 1.15 2015/05/16 23:31:32 roy Exp $");
__RCSID("$NetBSD: ipv4.c,v 1.16 2015/07/09 10:15:34 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -31,9 +31,11 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
#include <assert.h>
#include <ctype.h>
@ -50,6 +52,7 @@
#include "if.h"
#include "if-options.h"
#include "ipv4.h"
#include "ipv4ll.h"
#include "script.h"
#define IPV4_LOOPBACK_ROUTE
@ -160,33 +163,17 @@ ipv4_findaddr(struct dhcpcd_ctx *ctx, const struct in_addr *addr)
}
int
ipv4_ifaddrexists(const struct interface *ifp)
ipv4_hasaddr(const struct interface *ifp)
{
const struct dhcp_state *state;
const struct dhcp_state *dstate;
const struct ipv4ll_state *istate;
state = D_CSTATE(ifp);
return (state && state->addr.s_addr != INADDR_ANY);
}
int
ipv4_addrexists(struct dhcpcd_ctx *ctx, const struct in_addr *addr)
{
struct interface *ifp;
struct dhcp_state *state;
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
state = D_STATE(ifp);
if (state) {
if (addr == NULL) {
if (state->addr.s_addr != INADDR_ANY)
return 1;
} else if (addr->s_addr == state->addr.s_addr)
return 1;
}
if (addr != NULL && ipv4_iffindaddr(ifp, addr, NULL))
return 1;
}
return 0;
dstate = D_CSTATE(ifp);
istate = IPV4LL_CSTATE(ifp);
return ((dstate &&
dstate->added == STATE_ADDED &&
dstate->addr.s_addr != INADDR_ANY) ||
(istate && istate->addr.s_addr != INADDR_ANY));
}
void
@ -218,6 +205,25 @@ ipv4_init(struct dhcpcd_ctx *ctx)
return 0;
}
int
ipv4_protocol_fd(const struct interface *ifp, uint16_t protocol)
{
if (protocol == ETHERTYPE_ARP) {
const struct iarp_state *istate;
istate = ARP_CSTATE(ifp);
assert(istate != NULL);
return istate->fd;
} else {
const struct dhcp_state *dstate;
dstate = D_CSTATE(ifp);
assert(dstate != NULL);
return dstate->raw_fd;
}
}
/* Interface comparer for working out ordering. */
int
ipv4_ifcmp(const struct interface *si, const struct interface *ti)
@ -474,6 +480,7 @@ add_subnet_route(struct rt_head *rt, const struct interface *ifp)
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;
r->src = s->addr;
TAILQ_INSERT_HEAD(rt, r, next);
return rt;
@ -499,9 +506,10 @@ add_loopback_route(struct rt_head *rt, const struct interface *ifp)
ipv4_freeroutes(rt);
return NULL;
}
r->dest.s_addr = s->addr.s_addr;
r->dest = s->addr;
r->net.s_addr = INADDR_BROADCAST;
r->gate.s_addr = htonl(INADDR_LOOPBACK);
r->src = s->addr;
TAILQ_INSERT_HEAD(rt, r, next);
return rt;
}
@ -512,9 +520,11 @@ get_routes(struct interface *ifp)
{
struct rt_head *nrt;
struct rt *rt, *r = NULL;
const struct dhcp_state *state;
if (ifp->options->routes && TAILQ_FIRST(ifp->options->routes)) {
nrt = malloc(sizeof(*nrt));
if ((nrt = malloc(sizeof(*nrt))) == NULL)
return NULL;
TAILQ_INIT(nrt);
TAILQ_FOREACH(rt, ifp->options->routes, next) {
if (rt->gate.s_addr == 0)
@ -528,42 +538,30 @@ get_routes(struct interface *ifp)
memcpy(r, rt, sizeof(*r));
TAILQ_INSERT_TAIL(nrt, r, next);
}
return nrt;
}
} else
nrt = get_option_routes(ifp, D_STATE(ifp)->new);
return get_option_routes(ifp, D_STATE(ifp)->new);
}
/* Some DHCP servers add set host routes by setting the gateway
* 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)
{
struct rt *r;
if (rt) {
TAILQ_FOREACH(r, rt, next) {
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);
}
/* Copy our address as the source address */
if (nrt) {
state = D_CSTATE(ifp);
TAILQ_FOREACH(rt, nrt, next) {
rt->src = state->addr;
}
}
return rt;
}
return nrt;
}
static struct rt_head *
add_destination_route(struct rt_head *rt, const struct interface *ifp)
{
struct rt *r;
const struct dhcp_state *state;
if (rt == NULL || /* failed a malloc earlier probably */
!(ifp->flags & IFF_POINTOPOINT) ||
!has_option_mask(ifp->options->dstmask, DHO_ROUTER))
!has_option_mask(ifp->options->dstmask, DHO_ROUTER) ||
(state = D_CSTATE(ifp)) == NULL)
return rt;
r = malloc(sizeof(*r));
@ -574,7 +572,7 @@ add_destination_route(struct rt_head *rt, const struct interface *ifp)
}
r->dest.s_addr = INADDR_ANY;
r->net.s_addr = INADDR_ANY;
r->gate.s_addr = D_CSTATE(ifp)->dst.s_addr;
r->gate.s_addr = state->dst.s_addr;
TAILQ_INSERT_HEAD(rt, r, next);
return rt;
}
@ -616,7 +614,8 @@ add_router_host_route(struct rt_head *rt, const struct interface *ifp)
}
if (rtn != rtp)
continue;
state = D_CSTATE(ifp);
if ((state = D_CSTATE(ifp)) == NULL)
continue;
ifo = ifp->options;
if (ifp->flags & IFF_NOARP) {
if (!(ifo->options & DHCPCD_ROUTER_HOST_ROUTE_WARNED) &&
@ -664,8 +663,7 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx)
* our routes are managed correctly. */
if_sortinterfaces(ctx);
nrs = malloc(sizeof(*nrs));
if (nrs == NULL) {
if ((nrs = malloc(sizeof(*nrs))) == NULL) {
logger(ctx, LOG_ERR, "%s: %m", __func__);
return;
}
@ -673,11 +671,24 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx)
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
state = D_CSTATE(ifp);
if (state == NULL || state->new == NULL || !state->added)
if (state != NULL && state->new != NULL && state->added) {
dnr = get_routes(ifp);
dnr = add_subnet_route(dnr, ifp);
} else
dnr = NULL;
if ((rt = ipv4ll_subnet_route(ifp)) != NULL) {
if (dnr == NULL) {
if ((dnr = malloc(sizeof(*dnr))) == NULL) {
logger(ifp->ctx, LOG_ERR,
"%s: malloc %m", __func__);
continue;
}
TAILQ_INIT(dnr);
}
TAILQ_INSERT_HEAD(dnr, rt, next);
}
if (dnr == NULL)
continue;
dnr = get_routes(ifp);
dnr = massage_host_routes(dnr, ifp);
dnr = add_subnet_route(dnr, ifp);
#ifdef IPV4_LOOPBACK_ROUTE
dnr = add_loopback_route(dnr, ifp);
#endif
@ -685,7 +696,7 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx)
dnr = add_router_host_route(dnr, ifp);
dnr = add_destination_route(dnr, ifp);
}
if (dnr == NULL) /* failed to malloc all new routes */
if (dnr == NULL)
continue;
TAILQ_FOREACH_SAFE(rt, dnr, next, rtn) {
rt->iface = ifp;
@ -696,7 +707,6 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx)
/* Is this route already in our table? */
if ((find_route(nrs, rt, NULL)) != NULL)
continue;
rt->src.s_addr = state->addr.s_addr;
/* Do we already manage it? */
if ((or = find_route(ctx->ipv4_routes, rt, NULL))) {
if (state->added & STATE_FAKE)
@ -706,7 +716,7 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx)
#ifdef HAVE_ROUTE_METRIC
rt->metric != or->metric ||
#endif
or->src.s_addr != state->addr.s_addr ||
rt->src.s_addr != or->src.s_addr ||
rt->gate.s_addr != or->gate.s_addr)
{
if (c_route(or, rt) != 0)
@ -719,7 +729,7 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx)
or = ipv4_findrt(ctx, rt, 1);
if (or == NULL ||
or->gate.s_addr != rt->gate.s_addr)
continue;
continue;
} else {
if (n_route(rt) != 0)
continue;
@ -748,7 +758,7 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx)
int
ipv4_deladdr(struct interface *ifp,
const struct in_addr *addr, const struct in_addr *net)
const struct in_addr *addr, const struct in_addr *net, int keeparp)
{
struct dhcp_state *dstate;
int r;
@ -764,7 +774,7 @@ ipv4_deladdr(struct interface *ifp,
errno != ENODEV)
logger(ifp->ctx, LOG_ERR, "%s: %s: %m", ifp->name, __func__);
if ((astate = arp_find(ifp, addr)) != NULL)
if (!keeparp && (astate = arp_find(ifp, addr)) != NULL)
arp_free(astate);
state = IPV4_STATE(ifp);
@ -804,11 +814,11 @@ delete_address(struct interface *ifp)
if (ifo->options & DHCPCD_INFORM ||
(ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
return 0;
r = ipv4_deladdr(ifp, &state->addr, &state->net);
r = ipv4_deladdr(ifp, &state->addr, &state->net, 0);
return r;
}
static struct ipv4_state *
struct ipv4_state *
ipv4_getstate(struct interface *ifp)
{
struct ipv4_state *state;
@ -823,102 +833,76 @@ ipv4_getstate(struct interface *ifp)
}
TAILQ_INIT(&state->addrs);
TAILQ_INIT(&state->routes);
#ifdef BSD
state->buffer_size = state->buffer_len = state->buffer_pos = 0;
state->buffer = NULL;
#endif
}
return state;
}
static int
ipv4_addaddr(struct interface *ifp, const struct dhcp_lease *lease)
struct ipv4_addr *
ipv4_addaddr(struct interface *ifp, const struct in_addr *addr,
const struct in_addr *mask, const struct in_addr *bcast)
{
struct ipv4_state *state;
struct ipv4_addr *ia;
struct dhcp_state *dstate;
if ((state = ipv4_getstate(ifp)) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: ipv4_getstate: %m", __func__);
return -1;
return NULL;
}
if (ifp->options->options & DHCPCD_NOALIAS) {
struct ipv4_addr *ian;
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->addr.s_addr != addr->s_addr)
ipv4_deladdr(ifp, &ia->addr, &ia->net, 0);
}
}
if ((ia = malloc(sizeof(*ia))) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
return -1;
return NULL;
}
logger(ifp->ctx, LOG_DEBUG, "%s: adding IP address %s/%d",
ifp->name, inet_ntoa(lease->addr),
inet_ntocidr(lease->net));
if (if_addaddress(ifp, &lease->addr, &lease->net, &lease->brd) == -1) {
ifp->name, inet_ntoa(*addr), inet_ntocidr(*mask));
if (if_addaddress(ifp, addr, mask, bcast) == -1) {
if (errno != EEXIST)
logger(ifp->ctx, LOG_ERR, "%s: if_addaddress: %m",
__func__);
free(ia);
return -1;
return NULL;
}
ia->iface = ifp;
ia->addr = lease->addr;
ia->net = lease->net;
ia->addr = *addr;
ia->net = *mask;
#ifdef IN_IFF_TENTATIVE
ia->addr_flags = IN_IFF_TENTATIVE;
#endif
TAILQ_INSERT_TAIL(&state->addrs, ia, next);
return ia;
}
dstate = D_STATE(ifp);
#ifdef IN_IFF_TENTATIVE
dstate->added |= STATE_ADDED;
#else
dstate->added = STATE_ADDED;
#endif
dstate->defend = 0;
dstate->addr.s_addr = lease->addr.s_addr;
dstate->net.s_addr = lease->net.s_addr;
static int
ipv4_daddaddr(struct interface *ifp, const struct dhcp_lease *lease)
{
struct dhcp_state *state;
if (ipv4_addaddr(ifp, &lease->addr, &lease->net, &lease->brd) == NULL)
return -1;
state = D_STATE(ifp);
state->added = STATE_ADDED;
state->addr.s_addr = lease->addr.s_addr;
state->net.s_addr = lease->net.s_addr;
return 0;
}
static void
ipv4_finalisert(struct interface *ifp)
{
const struct dhcp_state *state = D_CSTATE(ifp);
assert(state != NULL);
/* 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 &= (uint8_t)~(STATE_FAKE | STATE_TENTATIVE);
ipv4_finalisert(ifp);
}
int
ipv4_preferanother(struct interface *ifp)
{
@ -934,7 +918,7 @@ ipv4_preferanother(struct interface *ifp)
goto out;
TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
if (ifn == ifp || strcmp(ifn->name, ifp->name) == 0)
if (ifn == ifp)
break; /* We are already the most preferred */
nstate = D_STATE(ifn);
if (nstate && !nstate->added &&
@ -943,9 +927,9 @@ ipv4_preferanother(struct interface *ifp)
preferred = 1;
delete_address(ifp);
if (ifn->options->options & DHCPCD_ARP)
dhcp_bind(ifn, NULL);
dhcp_bind(ifn);
else {
ipv4_addaddr(ifn, &nstate->lease);
ipv4_daddaddr(ifn, &nstate->lease);
nstate->added = STATE_ADDED;
}
break;
@ -991,7 +975,7 @@ ipv4_applyaddr(void *arg)
/* Ensure only one interface has the address */
r = 0;
TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
if (ifn == ifp || strcmp(ifn->name, ifp->name) == 0) {
if (ifn == ifp) {
r = 1; /* past ourselves */
continue;
}
@ -1005,14 +989,13 @@ ipv4_applyaddr(void *arg)
ifp->name,
inet_ntoa(lease->addr),
ifn->name);
state->added &= (uint8_t)~STATE_TENTATIVE;
return;
}
logger(ifp->ctx, LOG_INFO, "%s: preferring %s on %s",
ifn->name,
inet_ntoa(lease->addr),
ifp->name);
ipv4_deladdr(ifn, &nstate->addr, &nstate->net);
ipv4_deladdr(ifn, &nstate->addr, &nstate->net, 0);
break;
}
}
@ -1020,18 +1003,18 @@ ipv4_applyaddr(void *arg)
/* Does another interface already have the address from a prior boot? */
if (ifn == NULL) {
TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
if (ifn == ifp || strcmp(ifn->name, ifp->name) == 0)
if (ifn == ifp)
continue;
ap = ipv4_iffindaddr(ifn, &lease->addr, NULL);
if (ap)
ipv4_deladdr(ifn, &ap->addr, &ap->net);
ipv4_deladdr(ifn, &ap->addr, &ap->net, 0);
}
}
/* 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)
ipv4_deladdr(ifp, &ap->addr, &ap->net);
ipv4_deladdr(ifp, &ap->addr, &ap->net, 0);
if (ipv4_iffindaddr(ifp, &lease->addr, &lease->net))
logger(ifp->ctx, LOG_DEBUG,
@ -1039,7 +1022,7 @@ ipv4_applyaddr(void *arg)
ifp->name, inet_ntoa(lease->addr),
inet_ntocidr(lease->net));
else {
r = ipv4_addaddr(ifp, lease);
r = ipv4_daddaddr(ifp, lease);
if (r == -1 && errno != EEXIST)
return;
}
@ -1054,7 +1037,24 @@ ipv4_applyaddr(void *arg)
return;
#endif
ipv4_finaliseaddr(ifp);
/* 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->addr.s_addr = lease->addr.s_addr;
state->net.s_addr = lease->net.s_addr;
/* 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
@ -1126,6 +1126,9 @@ ipv4_free(struct interface *ifp)
free(addr);
}
ipv4_freerts(&state->routes);
#ifdef BSD
free(state->buffer);
#endif
free(state);
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ipv4.h,v 1.11 2015/05/16 23:31:32 roy Exp $ */
/* $NetBSD: ipv4.h,v 1.12 2015/07/09 10:15:34 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -37,6 +37,23 @@
(IN_IFF_TENTATIVE | IN_IFF_DUPLICATED | IN_IFF_DETACHED)
#endif
/* Prefer our macro */
#ifdef HTONL
#undef HTONL
#endif
#if BYTE_ORDER == BIG_ENDIAN
#define HTONL(A) (A)
#elif BYTE_ORDER == LITTLE_ENDIAN
#define HTONL(A) \
((((uint32_t)(A) & 0xff000000) >> 24) | \
(((uint32_t)(A) & 0x00ff0000) >> 8) | \
(((uint32_t)(A) & 0x0000ff00) << 8) | \
(((uint32_t)(A) & 0x000000ff) << 24))
#else
#error Endian unknown
#endif /* BYTE_ORDER */
struct rt {
TAILQ_ENTRY(rt) next;
struct in_addr dest;
@ -64,6 +81,12 @@ TAILQ_HEAD(ipv4_addrhead, ipv4_addr);
struct ipv4_state {
struct ipv4_addrhead addrs;
struct rt_head routes;
#ifdef BSD
/* Buffer for BPF */
size_t buffer_size, buffer_len, buffer_pos;
unsigned char *buffer;
#endif
};
#define IPV4_STATE(ifp) \
@ -72,23 +95,24 @@ struct ipv4_state {
((const struct ipv4_state *)(ifp)->if_data[IF_DATA_IPV4])
#ifdef INET
struct ipv4_state *ipv4_getstate(struct interface *);
int ipv4_init(struct dhcpcd_ctx *);
int ipv4_protocol_fd(const struct interface *, uint16_t);
int ipv4_ifcmp(const struct interface *, const struct interface *);
uint8_t inet_ntocidr(struct in_addr);
int inet_cidrtoaddr(int, struct in_addr *);
uint32_t ipv4_getnetmask(uint32_t);
int ipv4_ifaddrexists(const struct interface *);
int ipv4_addrexists(struct dhcpcd_ctx *, const struct in_addr *);
int ipv4_hasaddr(const struct interface *);
#define STATE_ADDED 0x01
#define STATE_FAKE 0x02
#define STATE_TENTATIVE 0x04
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 *);
int ipv4_preferanother(struct interface *ifp);
int ipv4_deladdr(struct interface *, const struct in_addr *,
const struct in_addr *, int);
int ipv4_preferanother(struct interface *);
struct ipv4_addr *ipv4_addaddr(struct interface *,
const struct in_addr *, 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 *);
@ -112,7 +136,8 @@ void ipv4_ctxfree(struct dhcpcd_ctx *);
#define ipv4_freeroutes(a) {}
#define ipv4_free(a) {}
#define ipv4_ctxfree(a) {}
#define ipv4_ifaddrexists(a) (0)
#define ipv4_hasaddr(a) (0)
#define ipv4_preferanother(a) (0)
#endif
#endif

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: ipv4ll.c,v 1.10 2015/05/02 15:18:37 roy Exp $");
__RCSID("$NetBSD: ipv4ll.c,v 1.11 2015/07/09 10:15:34 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -28,6 +28,9 @@
* SUCH DAMAGE.
*/
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
@ -38,101 +41,137 @@
#include "config.h"
#include "arp.h"
#include "common.h"
#include "dhcp.h"
#include "eloop.h"
#include "if.h"
#include "if-options.h"
#include "ipv4.h"
#include "ipv4ll.h"
#include "script.h"
static struct dhcp_message *
ipv4ll_make_lease(uint32_t addr)
{
uint32_t u32;
struct dhcp_message *dhcp;
uint8_t *p;
dhcp = calloc(1, sizeof(*dhcp));
if (dhcp == NULL)
return NULL;
/* Put some LL options in */
dhcp->yiaddr = addr;
p = dhcp->options;
*p++ = DHO_SUBNETMASK;
*p++ = sizeof(u32);
u32 = htonl(LINKLOCAL_MASK);
memcpy(p, &u32, sizeof(u32));
p += sizeof(u32);
*p++ = DHO_BROADCAST;
*p++ = sizeof(u32);
u32 = htonl(LINKLOCAL_BRDC);
memcpy(p, &u32, sizeof(u32));
p += sizeof(u32);
*p++ = DHO_END;
return dhcp;
}
static const struct in_addr inaddr_llmask = { HTONL(LINKLOCAL_MASK) };
static const struct in_addr inaddr_llbcast = { HTONL(LINKLOCAL_BRDC) };
static in_addr_t
ipv4ll_pick_addr(const struct arp_state *astate)
{
in_addr_t addr;
struct interface *ifp;
const struct dhcp_state *state;
struct in_addr addr;
for (;;) {
do {
/* RFC 3927 Section 2.1 states that the first 256 and
* last 256 addresses are reserved for future use.
* See ipv4ll_start for why we don't use arc4_random. */
addr = ntohl(LINKLOCAL_ADDR |
addr.s_addr = ntohl(LINKLOCAL_ADDR |
((uint32_t)(random() % 0xFD00) + 0x0100));
/* No point using a failed address */
if (addr == astate->failed.s_addr)
if (addr.s_addr == astate->failed.s_addr)
continue;
/* Ensure we don't have the address on another interface */
TAILQ_FOREACH(ifp, astate->iface->ctx->ifaces, next) {
state = D_CSTATE(ifp);
if (state && state->addr.s_addr == addr)
break;
}
} while (ipv4_findaddr(astate->iface->ctx, &addr) != NULL);
/* Yay, this should be a unique and workable IPv4LL address */
if (ifp == NULL)
break;
return addr.s_addr;
}
struct rt *
ipv4ll_subnet_route(const struct interface *ifp)
{
const struct ipv4ll_state *state;
struct rt *rt;
assert(ifp != NULL);
if ((state = IPV4LL_CSTATE(ifp)) == NULL ||
state->addr.s_addr == INADDR_ANY)
return NULL;
if ((rt = malloc(sizeof(*rt))) == NULL) {
logger(ifp->ctx, LOG_ERR, "%s: malloc: %m", __func__);
return NULL;
}
return addr;
rt->iface = ifp;
rt->dest.s_addr = state->addr.s_addr & inaddr_llmask.s_addr;
rt->net = inaddr_llmask;
rt->gate.s_addr = INADDR_ANY;
rt->src = state->addr;
return rt;
}
ssize_t
ipv4ll_env(char **env, const char *prefix, const struct interface *ifp)
{
const struct ipv4ll_state *state;
const char *pf = prefix == NULL ? "" : "_";
struct in_addr netnum;
assert(ifp != NULL);
if ((state = IPV4LL_CSTATE(ifp)) == NULL)
return 0;
if (env == NULL)
return 5;
/* Emulate a DHCP environment */
if (asprintf(&env[0], "%s%sip_address=%s",
prefix, pf, inet_ntoa(state->addr)) == -1)
return -1;
if (asprintf(&env[1], "%s%ssubnet_mask=%s",
prefix, pf, inet_ntoa(inaddr_llmask)) == -1)
return -1;
if (asprintf(&env[2], "%s%ssubnet_cidr=%d",
prefix, pf, inet_ntocidr(inaddr_llmask)) == -1)
return -1;
if (asprintf(&env[3], "%s%sbroadcast_address=%s",
prefix, pf, inet_ntoa(inaddr_llbcast)) == -1)
return -1;
netnum.s_addr = state->addr.s_addr & inaddr_llmask.s_addr;
if (asprintf(&env[4], "%s%snetwork_number=%s",
prefix, pf, inet_ntoa(netnum)) == -1)
return -1;
return 5;
}
static void
ipv4ll_probed(struct arp_state *astate)
{
struct dhcp_state *state = D_STATE(astate->iface);
struct interface *ifp;
struct ipv4ll_state *state;
struct ipv4_addr *ia;
if (state->state == DHS_IPV4LL_BOUND) {
ipv4_finaliseaddr(astate->iface);
assert(astate != NULL);
assert(astate->iface != NULL);
ifp = astate->iface;
state = IPV4LL_STATE(ifp);
assert(state != NULL);
ia = ipv4_iffindaddr(ifp, &astate->addr, &inaddr_llmask);
#ifdef IN_IFF_NOTREADY
if (ia == NULL || ia->addr_flags & IN_IFF_NOTREADY)
#endif
logger(ifp->ctx, LOG_INFO, "%s: using IPv4LL address %s",
ifp->name, inet_ntoa(astate->addr));
if (ia == NULL)
ia = ipv4_addaddr(ifp, &astate->addr,
&inaddr_llmask, &inaddr_llbcast);
if (ia == NULL)
return;
}
if (state->state != DHS_BOUND) {
struct dhcp_message *offer;
/* A DHCP lease could have already been offered.
* 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)
logger(astate->iface->ctx, LOG_ERR, "%s: %m", __func__);
else
dhcp_bind(astate->iface, astate);
state->offer = offer;
}
#ifdef IN_IFF_NOTREADY
if (ia->addr_flags & IN_IFF_NOTREADY)
return;
logger(ifp->ctx, LOG_DEBUG, "%s: DAD completed for %s",
ifp->name, inet_ntoa(astate->addr));
#endif
state->addr = astate->addr;
timespecclear(&state->defend);
ipv4_buildroutes(ifp->ctx);
arp_announce(astate);
script_runreason(ifp, "IPV4LL");
dhcpcd_daemonise(ifp->ctx);
}
static void
ipv4ll_announced(struct arp_state *astate)
{
struct dhcp_state *state = D_STATE(astate->iface);
struct ipv4ll_state *state = IPV4LL_STATE(astate->iface);
state->conflicts = 0;
/* Need to keep the arp state so we can defend our IP. */
@ -152,9 +191,16 @@ ipv4ll_probe(void *arg)
static void
ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
{
struct dhcp_state *state = D_STATE(astate->iface);
struct interface *ifp;
struct ipv4ll_state *state;
in_addr_t fail;
assert(astate != NULL);
assert(astate->iface != NULL);
ifp = astate->iface;
state = IPV4LL_STATE(ifp);
assert(state != NULL);
fail = 0;
/* RFC 3927 2.2.1, Probe Conflict Detection */
if (amsg == NULL ||
@ -163,7 +209,7 @@ ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
fail = astate->addr.s_addr;
/* RFC 3927 2.5, Conflict Defense */
if (IN_LINKLOCAL(htonl(state->addr.s_addr)) &&
if (IN_LINKLOCAL(ntohl(state->addr.s_addr)) &&
amsg && amsg->sip.s_addr == state->addr.s_addr)
fail = state->addr.s_addr;
@ -174,46 +220,73 @@ ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
arp_report_conflicted(astate, amsg);
if (astate->failed.s_addr == state->addr.s_addr) {
time_t up;
struct timespec now, defend;
/* RFC 3927 Section 2.5 */
up = uptime();
if (state->defend + DEFEND_INTERVAL > up) {
logger(astate->iface->ctx, LOG_WARNING,
defend.tv_sec = state->defend.tv_sec + DEFEND_INTERVAL;
defend.tv_nsec = state->defend.tv_nsec;
clock_gettime(CLOCK_MONOTONIC, &now);
if (timespeccmp(&defend, &now, >)) {
logger(ifp->ctx, LOG_WARNING,
"%s: IPv4LL %d second defence failed for %s",
astate->iface->name, DEFEND_INTERVAL,
ifp->name, DEFEND_INTERVAL,
inet_ntoa(state->addr));
dhcp_drop(astate->iface, "EXPIRE");
ipv4_deladdr(ifp, &state->addr, &inaddr_llmask, 1);
state->down = 1;
script_runreason(ifp, "IPV4LL");
state->addr.s_addr = INADDR_ANY;
} else {
logger(astate->iface->ctx, LOG_DEBUG,
logger(ifp->ctx, LOG_DEBUG,
"%s: defended IPv4LL address %s",
astate->iface->name, inet_ntoa(state->addr));
state->defend = up;
ifp->name, inet_ntoa(state->addr));
state->defend = now;
return;
}
}
arp_cancel(astate);
if (++state->conflicts == MAX_CONFLICTS)
logger(astate->iface->ctx, LOG_ERR,
logger(ifp->ctx, LOG_ERR,
"%s: failed to acquire an IPv4LL address",
astate->iface->name);
ifp->name);
astate->addr.s_addr = ipv4ll_pick_addr(astate);
eloop_timeout_add_sec(astate->iface->ctx->eloop,
eloop_timeout_add_sec(ifp->ctx->eloop,
state->conflicts >= MAX_CONFLICTS ?
RATE_LIMIT_INTERVAL : PROBE_WAIT,
ipv4ll_probe, astate);
}
static void
ipv4ll_arpfree(struct arp_state *astate)
{
struct ipv4ll_state *state;
state = IPV4LL_STATE(astate->iface);
if (state->arp == astate)
state->arp = NULL;
}
void
ipv4ll_start(void *arg)
{
struct interface *ifp = arg;
struct dhcp_state *state = D_STATE(ifp);
struct interface *ifp;
struct ipv4ll_state *state;
struct arp_state *astate;
struct ipv4_addr *ap;
struct ipv4_addr *ia;
if (state->arp_ipv4ll)
assert(arg != NULL);
ifp = arg;
if ((state = IPV4LL_STATE(ifp)) == NULL) {
ifp->if_data[IF_DATA_IPV4LL] = calloc(1, sizeof(*state));
if ((state = IPV4LL_STATE(ifp)) == NULL) {
syslog(LOG_ERR, "%s: calloc %m", __func__);
return;
}
state->addr.s_addr = INADDR_ANY;
}
if (state->arp != NULL)
return;
/* RFC 3927 Section 2.1 states that the random number generator
@ -235,39 +308,40 @@ ipv4ll_start(void *arg)
if ((astate = arp_new(ifp, NULL)) == NULL)
return;
state->arp_ipv4ll = astate;
state->arp = astate;
astate->probed_cb = ipv4ll_probed;
astate->announced_cb = ipv4ll_announced;
astate->conflicted_cb = ipv4ll_conflicted;
astate->free_cb = ipv4ll_arpfree;
if (IN_LINKLOCAL(htonl(state->addr.s_addr))) {
astate->addr = state->addr;
arp_announce(astate);
return;
/* Find an existing IPv4LL address and ensure we can work with it. */
ia = ipv4_iffindlladdr(ifp);
#ifdef IN_IFF_TENTATIVE
if (ia != NULL && ia->addr_flags & IN_IFF_DUPLICATED) {
ipv4_deladdr(ifp, &ia->addr, &ia->net, 0);
ia = NULL;
}
if (state->offer && IN_LINKLOCAL(ntohl(state->offer->yiaddr))) {
astate->addr.s_addr = state->offer->yiaddr;
free(state->offer);
state->offer = NULL;
ap = ipv4_iffindaddr(ifp, &astate->addr, NULL);
} else
ap = ipv4_iffindlladdr(ifp);
if (ap) {
astate->addr = ap->addr;
#endif
if (ia != NULL) {
astate->addr = ia->addr;
#ifdef IN_IFF_TENTATIVE
if (ia->addr_flags & (IN_IFF_TENTATIVE | IN_IFF_DETACHED)) {
logger(ifp->ctx, LOG_INFO,
"%s: waiting for DAD to complete on %s",
ifp->name, inet_ntoa(ia->addr));
return;
}
logger(ifp->ctx, LOG_INFO, "%s: using IPv4LL address %s",
ifp->name, inet_ntoa(astate->addr));
#endif
ipv4ll_probed(astate);
return;
}
setstate(state->randomstate);
/* We maybe rebooting an IPv4LL address. */
if (!IN_LINKLOCAL(htonl(astate->addr.s_addr))) {
logger(ifp->ctx, LOG_INFO, "%s: probing for an IPv4LL address",
ifp->name);
astate->addr.s_addr = INADDR_ANY;
}
if (astate->addr.s_addr == INADDR_ANY)
astate->addr.s_addr = ipv4ll_pick_addr(astate);
logger(ifp->ctx, LOG_INFO, "%s: probing for an IPv4LL address",
ifp->name);
astate->addr.s_addr = ipv4ll_pick_addr(astate);
#ifdef IN_IFF_TENTATIVE
ipv4ll_probed(astate);
#else
@ -276,9 +350,45 @@ ipv4ll_start(void *arg)
}
void
ipv4ll_stop(struct interface *ifp)
ipv4ll_freedrop(struct interface *ifp, int drop)
{
struct dhcp_state *state = D_STATE(ifp);
struct ipv4ll_state *state;
eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp_ipv4ll);
assert(ifp != NULL);
state = IPV4LL_STATE(ifp);
/* Free ARP state first because ipv4_deladdr might also ... */
if (state && state->arp) {
eloop_timeout_delete(ifp->ctx->eloop, NULL, state->arp);
arp_free(state->arp);
state->arp = NULL;
}
if (drop && (ifp->options->options & DHCPCD_NODROP) != DHCPCD_NODROP) {
struct ipv4_state *istate;
if (state && state->addr.s_addr != INADDR_ANY) {
ipv4_deladdr(ifp, &state->addr, &inaddr_llmask, 1);
state->addr.s_addr = INADDR_ANY;
}
/* Free any other link local addresses that might exist. */
if ((istate = IPV4_STATE(ifp)) != NULL) {
struct ipv4_addr *ia, *ian;
TAILQ_FOREACH_SAFE(ia, &istate->addrs, next, ian) {
if (IN_LINKLOCAL(ntohl(ia->addr.s_addr)))
ipv4_deladdr(ifp, &ia->addr,
&ia->net, 0);
}
}
script_runreason(ifp, "IPV4LL");
}
if (state) {
free(state);
ifp->if_data[IF_DATA_IPV4LL] = NULL;
ipv4_buildroutes(ifp->ctx);
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ipv4ll.h,v 1.8 2015/03/26 10:26:37 roy Exp $ */
/* $NetBSD: ipv4ll.h,v 1.9 2015/07/09 10:15:34 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -30,9 +30,41 @@
#ifndef IPV4LL_H
#define IPV4LL_H
#include "arp.h"
#define LINKLOCAL_ADDR 0xa9fe0000
#define LINKLOCAL_MASK IN_CLASSB_NET
#define LINKLOCAL_BRDC (LINKLOCAL_ADDR | ~LINKLOCAL_MASK)
#ifndef IN_LINKLOCAL
# define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == LINKLOCAL_ADDR)
#endif
struct ipv4ll_state {
struct in_addr addr;
struct arp_state *arp;
unsigned int conflicts;
struct timespec defend;
char randomstate[128];
uint8_t down;
};
#define IPV4LL_STATE(ifp) \
((struct ipv4ll_state *)(ifp)->if_data[IF_DATA_IPV4LL])
#define IPV4LL_CSTATE(ifp) \
((const struct ipv4ll_state *)(ifp)->if_data[IF_DATA_IPV4LL])
#define IPV4LL_STATE_RUNNING(ifp) \
(IPV4LL_CSTATE((ifp)) && !IPV4LL_CSTATE((ifp))->down && \
IN_LINKLOCAL(ntohl(IPV4LL_CSTATE((ifp))->addr.s_addr)))
struct rt* ipv4ll_subnet_route(const struct interface *);
ssize_t ipv4ll_env(char **, const char *, const struct interface *);
void ipv4ll_start(void *);
void ipv4ll_claimed(void *);
void ipv4ll_handle_failure(void *);
void ipv4ll_stop(struct interface *);
#define ipv4ll_free(ifp) ipv4ll_freedrop((ifp), 0);
#define ipv4ll_drop(ifp) ipv4ll_freedrop((ifp), 1);
void ipv4ll_freedrop(struct interface *, int);
#endif

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: ipv6.c,v 1.12 2015/05/16 23:31:32 roy Exp $");
__RCSID("$NetBSD: ipv6.c,v 1.13 2015/07/09 10:15:34 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -254,7 +254,8 @@ ipv6_readsecret(struct dhcpcd_ctx *ctx)
goto eexit;
x = fprintf(fp, "%s\n",
hwaddr_ntoa(ctx->secret, ctx->secret_len, line, sizeof(line)));
fclose(fp);
if (fclose(fp) == EOF)
x = -1;
if (x > 0)
return (ssize_t)ctx->secret_len;
@ -628,7 +629,7 @@ ipv6_addaddr(struct ipv6_addr *ap, const struct timespec *now)
/* Ensure no other interface has this address */
TAILQ_FOREACH(ifp, ap->iface->ctx->ifaces, next) {
if (ifp == ap->iface || strcmp(ifp->name, ap->iface->name) == 0)
if (ifp == ap->iface)
continue;
state = IPV6_STATE(ifp);
if (state == NULL)
@ -751,10 +752,28 @@ int
ipv6_publicaddr(const struct ipv6_addr *ia)
{
return (ia->prefix_pltime &&
(ia->addr.s6_addr[0] & 0xfe) != 0xc &&
(ia->addr.s6_addr[0] & 0xfe) != 0xfc &&
!(ia->addr_flags & IN6_IFF_NOTUSEABLE));
}
int
ipv6_findaddrmatch(const struct ipv6_addr *addr, const struct in6_addr *match,
short flags)
{
if (match == NULL) {
if ((addr->flags &
(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) ==
(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED))
return 1;
} else if (addr->prefix_vltime &&
IN6_ARE_ADDR_EQUAL(&addr->addr, match) &&
(!flags || addr->flags & flags))
return 1;
return 0;
}
struct ipv6_addr *
ipv6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr, short flags)
{
@ -801,9 +820,7 @@ ipv6_addaddrs(struct ipv6_addrhead *addrs)
{
apf = ipv6_findaddr(ap->iface->ctx,
&ap->addr, IPV6_AF_ADDED);
if (apf && apf->iface != ap->iface &&
strcmp(apf->iface->name, ap->iface->name))
{
if (apf && apf->iface != ap->iface) {
if (apf->iface->metric <= ap->iface->metric) {
logger(apf->iface->ctx, LOG_INFO,
"%s: preferring %s on %s",
@ -867,8 +884,7 @@ ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop,
/* Find the same address somewhere else */
apf = ipv6_findaddr(ap->iface->ctx, &ap->addr, 0);
if (apf == NULL ||
(apf->iface != ap->iface &&
strcmp(apf->iface->name, ap->iface->name)))
(apf->iface != ap->iface))
ipv6_deleteaddr(ap);
if (!(ap->iface->options->options &
DHCPCD_EXITING) && apf)
@ -934,109 +950,116 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
errno = ESRCH;
return;
}
TAILQ_FOREACH(ifp, ifs, next) {
/* Each psuedo interface also stores addresses */
if (strcmp(ifp->name, ifname))
continue;
state = ipv6_getstate(ifp);
if (state == NULL)
continue;
if ((ifp = if_find(ifs, ifname)) == NULL)
return;
if ((state = ipv6_getstate(ifp)) == NULL)
return;
if (!IN6_IS_ADDR_LINKLOCAL(addr)) {
ipv6nd_handleifa(ctx, cmd, ifname, addr, flags);
dhcp6_handleifa(ctx, cmd, ifname, addr, flags);
}
TAILQ_FOREACH(ap, &state->addrs, next) {
if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr))
break;
}
switch (cmd) {
case RTM_DELADDR:
if (ap) {
TAILQ_REMOVE(&state->addrs, ap, next);
ipv6_freeaddr(ap);
}
break;
case RTM_NEWADDR:
if (ap == NULL) {
char buf[INET6_ADDRSTRLEN];
const char *cbp;
ap = calloc(1, sizeof(*ap));
ap->iface = ifp;
ap->addr = *addr;
ap->prefix_len = prefix_len;
ipv6_makeprefix(&ap->prefix, &ap->addr,
ap->prefix_len);
cbp = inet_ntop(AF_INET6, &addr->s6_addr,
buf, sizeof(buf));
if (cbp)
snprintf(ap->saddr, sizeof(ap->saddr),
"%s/%d", cbp, prefix_len);
if (if_getlifetime6(ap) == -1) {
/* No support or address vanished.
* Either way, just set a deprecated
* infinite time lifetime and continue.
* This is fine because we only want
* to know this when trying to extend
* temporary addresses.
* As we can't extend infinite, we'll
* create a new temporary address. */
ap->prefix_pltime = 0;
ap->prefix_vltime =
ND6_INFINITE_LIFETIME;
}
/* This is a minor regression against RFC 4941
* because the kernel only knows when the
* lifetimes were last updated, not when the
* address was initially created.
* Provided dhcpcd is not restarted, this
* won't be a problem.
* If we don't like it, we can always
* pretend lifetimes are infinite and always
* generate a new temporary address on
* restart. */
ap->acquired = ap->created;
TAILQ_INSERT_TAIL(&state->addrs,
ap, next);
}
ap->addr_flags = flags;
#ifdef IPV6_MANAGETEMPADDR
if (ap->addr_flags & IN6_IFF_TEMPORARY)
ap->flags |= IPV6_AF_TEMPORARY;
#endif
if (IN6_IS_ADDR_LINKLOCAL(&ap->addr)) {
#ifdef IPV6_POLLADDRFLAG
if (ap->addr_flags & IN6_IFF_TENTATIVE) {
struct timespec tv;
ms_to_ts(&tv, RETRANS_TIMER / 2);
eloop_timeout_add_tv(
ap->iface->ctx->eloop,
&tv, ipv6_checkaddrflags, ap);
break;
}
#endif
if (!(ap->addr_flags & IN6_IFF_NOTUSEABLE)) {
/* Now run any callbacks.
* Typically IPv6RS or DHCPv6 */
while ((cb =
TAILQ_FIRST(&state->ll_callbacks)))
{
TAILQ_REMOVE(
&state->ll_callbacks,
cb, next);
cb->callback(cb->arg);
free(cb);
}
}
}
break;
}
if (!IN6_IS_ADDR_LINKLOCAL(addr)) {
ipv6nd_handleifa(ctx, cmd, ifname, addr, flags);
dhcp6_handleifa(ctx, cmd, ifname, addr, flags);
}
TAILQ_FOREACH(ap, &state->addrs, next) {
if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr))
break;
}
switch (cmd) {
case RTM_DELADDR:
if (ap) {
TAILQ_REMOVE(&state->addrs, ap, next);
ipv6_freeaddr(ap);
}
break;
case RTM_NEWADDR:
if (ap == NULL) {
char buf[INET6_ADDRSTRLEN];
const char *cbp;
ap = calloc(1, sizeof(*ap));
ap->iface = ifp;
ap->addr = *addr;
ap->prefix_len = prefix_len;
ipv6_makeprefix(&ap->prefix, &ap->addr,
ap->prefix_len);
cbp = inet_ntop(AF_INET6, &addr->s6_addr,
buf, sizeof(buf));
if (cbp)
snprintf(ap->saddr, sizeof(ap->saddr),
"%s/%d", cbp, prefix_len);
if (if_getlifetime6(ap) == -1) {
/* No support or address vanished.
* Either way, just set a deprecated
* infinite time lifetime and continue.
* This is fine because we only want
* to know this when trying to extend
* temporary addresses.
* As we can't extend infinite, we'll
* create a new temporary address. */
ap->prefix_pltime = 0;
ap->prefix_vltime =
ND6_INFINITE_LIFETIME;
}
/* This is a minor regression against RFC 4941
* because the kernel only knows when the
* lifetimes were last updated, not when the
* address was initially created.
* Provided dhcpcd is not restarted, this
* won't be a problem.
* If we don't like it, we can always
* pretend lifetimes are infinite and always
* generate a new temporary address on
* restart. */
ap->acquired = ap->created;
TAILQ_INSERT_TAIL(&state->addrs,
ap, next);
}
ap->addr_flags = flags;
#ifdef IPV6_MANAGETEMPADDR
if (ap->addr_flags & IN6_IFF_TEMPORARY)
ap->flags |= IPV6_AF_TEMPORARY;
#endif
if (IN6_IS_ADDR_LINKLOCAL(&ap->addr)) {
#ifdef IPV6_POLLADDRFLAG
if (ap->addr_flags & IN6_IFF_TENTATIVE) {
struct timespec tv;
ms_to_ts(&tv, RETRANS_TIMER / 2);
eloop_timeout_add_tv(
ap->iface->ctx->eloop,
&tv, ipv6_checkaddrflags, ap);
break;
}
#endif
if (!(ap->addr_flags & IN6_IFF_NOTUSEABLE)) {
/* Now run any callbacks.
* Typically IPv6RS or DHCPv6 */
while ((cb =
TAILQ_FIRST(&state->ll_callbacks)))
{
TAILQ_REMOVE(
&state->ll_callbacks,
cb, next);
cb->callback(cb->arg);
free(cb);
}
}
}
break;
}
}
int
ipv6_hasaddr(const struct interface *ifp)
{
if (ipv6nd_iffindaddr(ifp, NULL, 0) != NULL)
return 1;
if (dhcp6_iffindaddr(ifp, NULL, 0) != NULL)
return 1;
return 0;
}
const struct ipv6_addr *

View File

@ -1,4 +1,4 @@
/* $NetBSD: ipv6.h,v 1.13 2015/05/16 23:31:32 roy Exp $ */
/* $NetBSD: ipv6.h,v 1.14 2015/07/09 10:15:34 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -251,6 +251,9 @@ int ipv6_handleifa_addrs(int, struct ipv6_addrhead *,
int ipv6_publicaddr(const struct ipv6_addr *);
const struct ipv6_addr *ipv6_iffindaddr(const struct interface *,
const struct in6_addr *);
int ipv6_hasaddr(const struct interface *);
int ipv6_findaddrmatch(const struct ipv6_addr *, const struct in6_addr *,
short);
struct ipv6_addr *ipv6_findaddr(struct dhcpcd_ctx *,
const struct in6_addr *, short);
#define ipv6_linklocal(ifp) ipv6_iffindaddr((ifp), NULL)
@ -281,7 +284,7 @@ void ipv6_buildroutes(struct dhcpcd_ctx *);
#else
#define ipv6_init(a) (NULL)
#define ipv6_start(a) (-1)
#define ipv6_iffindaddr(a, b) (NULL)
#define ipv6_hasaddr(a) (0)
#define ipv6_free_ll_callbacks(a) {}
#define ipv6_free(a) {}
#define ipv6_drop(a) {}

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: ipv6nd.c,v 1.24 2015/05/16 23:31:32 roy Exp $");
__RCSID("$NetBSD: ipv6nd.c,v 1.25 2015/07/09 10:15:34 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -421,6 +421,27 @@ ipv6nd_neighbour(struct dhcpcd_ctx *ctx, struct in6_addr *addr, int flags)
}
}
const struct ipv6_addr *
ipv6nd_iffindaddr(const struct interface *ifp, const struct in6_addr *addr,
short flags)
{
struct ra *rap;
struct ipv6_addr *ap;
if (ifp->ctx->ipv6 == NULL)
return NULL;
TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
if (rap->iface != ifp)
continue;
TAILQ_FOREACH(ap, &rap->addrs, next) {
if (ipv6_findaddrmatch(ap, addr, flags))
return ap;
}
}
return NULL;
}
struct ipv6_addr *
ipv6nd_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr,
short flags)
@ -433,14 +454,7 @@ ipv6nd_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr,
TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) {
TAILQ_FOREACH(ap, &rap->addrs, next) {
if (addr == NULL) {
if ((ap->flags &
(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) ==
(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED))
return ap;
} else if (ap->prefix_vltime &&
IN6_ARE_ADDR_EQUAL(&ap->addr, addr) &&
(!flags || ap->flags & flags))
if (ipv6_findaddrmatch(ap, addr, flags))
return ap;
}
}
@ -735,7 +749,7 @@ ipv6nd_ra_has_public_addr(const struct ra *rap)
static void
ipv6nd_handlera(struct dhcpcd_ctx *dctx, struct interface *ifp,
struct icmp6_hdr *icp, size_t len)
struct icmp6_hdr *icp, size_t len, int hoplimit)
{
struct ipv6_ctx *ctx = dctx->ipv6;
size_t i, olen;
@ -756,25 +770,33 @@ ipv6nd_handlera(struct dhcpcd_ctx *dctx, struct interface *ifp,
uint8_t new_ap;
#endif
if (ifp == NULL) {
#ifdef DEBUG_RS
logger(dctx, LOG_DEBUG,
"RA for unexpected interface from %s", ctx->sfrom);
#endif
return;
}
if (len < sizeof(struct nd_router_advert)) {
logger(dctx, LOG_ERR,
"IPv6 RA packet too short from %s", ctx->sfrom);
return;
}
/* RFC 4861 7.1.2 */
if (hoplimit != 255) {
logger(dctx, LOG_ERR,
"invalid hoplimit(%d) in RA from %s", hoplimit, ctx->sfrom);
return;
}
if (!IN6_IS_ADDR_LINKLOCAL(&ctx->from.sin6_addr)) {
logger(dctx, LOG_ERR,
"RA from non local address %s", ctx->sfrom);
return;
}
if (ifp == NULL) {
#ifdef DEBUG_RS
logger(dctx, LOG_DEBUG,
"RA for unexpected interface from %s", ctx->sfrom);
#endif
return;
}
if (!(ifp->options->options & DHCPCD_IPV6RS)) {
#ifdef DEBUG_RS
logger(ifp->ctx, LOG_DEBUG, "%s: unexpected RA from %s",
@ -851,9 +873,6 @@ ipv6nd_handlera(struct dhcpcd_ctx *dctx, struct interface *ifp,
clock_gettime(CLOCK_MONOTONIC, &rap->acquired);
rap->flags = nd_ra->nd_ra_flags_reserved;
if (new_rap == 0 && rap->lifetime == 0)
logger(ifp->ctx, LOG_WARNING, "%s: %s router available",
ifp->name, rap->sfrom);
rap->lifetime = ntohs(nd_ra->nd_ra_router_lifetime);
if (nd_ra->nd_ra_reachable) {
rap->reachable = ntohl(nd_ra->nd_ra_reachable);
@ -902,7 +921,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *dctx, struct interface *ifp,
if (dho->option == ndo->nd_opt_type)
break;
}
if (dho != NULL)
if (dho != NULL)
logger(ifp->ctx, LOG_WARNING,
"%s: reject RA (option %s) from %s",
ifp->name, dho->var, ctx->sfrom);
@ -1101,7 +1120,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *dctx, struct interface *ifp,
" (no public prefix, no managed address)",
rap->iface->name, rap->sfrom);
rap->no_public_warned = 1;
return;
goto handle_flag;
}
if (ifp->ctx->options & DHCPCD_TEST) {
script_runreason(ifp, "TEST");
@ -1464,16 +1483,14 @@ ipv6nd_drop(struct interface *ifp)
ipv6nd_drop_ra(rap);
}
ipv6_buildroutes(ifp->ctx);
if ((ifp->options->options &
(DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
(DHCPCD_EXITING | DHCPCD_PERSISTENT))
if ((ifp->options->options & DHCPCD_NODROP) != DHCPCD_NODROP)
script_runreason(ifp, "ROUTERADVERT");
}
}
static void
ipv6nd_handlena(struct dhcpcd_ctx *dctx, struct interface *ifp,
struct icmp6_hdr *icp, size_t len)
struct icmp6_hdr *icp, size_t len, int hoplimit)
{
struct ipv6_ctx *ctx = dctx->ipv6;
struct nd_neighbor_advert *nd_na;
@ -1496,6 +1513,13 @@ ipv6nd_handlena(struct dhcpcd_ctx *dctx, struct interface *ifp,
return;
}
/* RFC 4861 7.1.2 */
if (hoplimit != 255) {
logger(dctx, LOG_ERR,
"invalid hoplimit(%d) in NA from %s", hoplimit, ctx->sfrom);
return;
}
nd_na = (struct nd_neighbor_advert *)icp;
is_router = nd_na->nd_na_flags_reserved & ND_NA_FLAG_ROUTER;
is_solicited = nd_na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED;
@ -1599,17 +1623,15 @@ ipv6nd_handledata(void *arg)
}
}
if (pkt.ipi6_ifindex == 0 || hoplimit == 0) {
if (pkt.ipi6_ifindex == 0) {
logger(dctx, LOG_ERR,
"IPv6 RA/NA did not contain index or hop limit from %s",
"IPv6 RA/NA did not contain index from %s",
ctx->sfrom);
return;
}
TAILQ_FOREACH(ifp, dctx->ifaces, next) {
if (ifp->index == (unsigned int)pkt.ipi6_ifindex &&
!(ifp->options->options & DHCPCD_PFXDLGONLY))
{
if (ifp->index == (unsigned int)pkt.ipi6_ifindex) {
if (!(ifp->options->options & DHCPCD_IPV6))
return;
break;
@ -1620,10 +1642,12 @@ ipv6nd_handledata(void *arg)
if (icp->icmp6_code == 0) {
switch(icp->icmp6_type) {
case ND_NEIGHBOR_ADVERT:
ipv6nd_handlena(dctx, ifp, icp, (size_t)len);
ipv6nd_handlena(dctx, ifp, icp, (size_t)len,
hoplimit);
return;
case ND_ROUTER_ADVERT:
ipv6nd_handlera(dctx, ifp, icp, (size_t)len);
ipv6nd_handlera(dctx, ifp, icp, (size_t)len,
hoplimit);
return;
}
}
@ -1673,6 +1697,11 @@ ipv6nd_startrs(struct interface *ifp)
struct timespec tv;
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
if (!(ifp->options->options & DHCPCD_INITIAL_DELAY)) {
ipv6nd_startrs1(ifp);
return;
}
tv.tv_sec = 0;
tv.tv_nsec = (suseconds_t)arc4random_uniform(
MAX_RTR_SOLICITATION_DELAY * NSEC_PER_SEC);

View File

@ -1,4 +1,4 @@
/* $NetBSD: ipv6nd.h,v 1.12 2015/05/16 23:31:32 roy Exp $ */
/* $NetBSD: ipv6nd.h,v 1.13 2015/07/09 10:15:34 roy Exp $ */
/*
* dhcpcd - DHCP client daemon
@ -101,6 +101,8 @@ void ipv6nd_printoptions(const struct dhcpcd_ctx *,
const struct dhcp_opt *, size_t);
void ipv6nd_startrs(struct interface *);
ssize_t ipv6nd_env(char **, const char *, const struct interface *);
const struct ipv6_addr *ipv6nd_iffindaddr(const struct interface *ifp,
const struct in6_addr *addr, short flags);
struct ipv6_addr *ipv6nd_findaddr(struct dhcpcd_ctx *,
const struct in6_addr *, short);
void ipv6nd_freedrop_ra(struct ra *, int);
@ -123,6 +125,7 @@ void ipv6nd_neighbour(struct dhcpcd_ctx *, struct in6_addr *, int);
#define ipv6nd_hasra(a) (0)
#define ipv6nd_dadcompleted(a) (0)
#define ipv6nd_drop(a) {}
#define ipv6nd_expire(a, b) {}
#endif
#endif

View File

@ -1,5 +1,5 @@
#include <sys/cdefs.h>
__RCSID("$NetBSD: script.c,v 1.20 2015/05/16 23:31:32 roy Exp $");
__RCSID("$NetBSD: script.c,v 1.21 2015/07/09 10:15:34 roy Exp $");
/*
* dhcpcd - DHCP client daemon
@ -50,6 +50,7 @@
#include "dhcp6.h"
#include "if.h"
#include "if-options.h"
#include "ipv4ll.h"
#include "ipv6nd.h"
#include "script.h"
@ -233,9 +234,11 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
#endif
const struct if_options *ifo = ifp->options;
const struct interface *ifp2;
int af;
#ifdef INET
int dhcp;
int dhcp, ipv4ll;
const struct dhcp_state *state;
const struct ipv4ll_state *istate;
#endif
#ifdef INET6
const struct dhcp6_state *d6_state;
@ -243,8 +246,9 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
#endif
#ifdef INET
dhcp = 0;
dhcp = ipv4ll = 0;
state = D_STATE(ifp);
istate = IPV4LL_CSTATE(ifp);
#endif
#ifdef INET6
dhcp6 = ra = 0;
@ -259,8 +263,10 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
ra = 1;
#endif
#ifdef INET
else
else if (state->added)
dhcp = 1;
else
ipv4ll = 1;
#endif
}
#ifdef INET6
@ -279,6 +285,8 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
/* This space left intentionally blank */
}
#ifdef INET
else if (strcmp(reason, "IPV4LL") == 0)
ipv4ll = 1;
else
dhcp = 1;
#endif
@ -288,11 +296,11 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
if (ifp->ctx->options & DHCPCD_DUMPLEASE)
elen = 2;
else
elen = 12;
elen = 11;
#define EMALLOC(i, l) if ((env[(i)] = malloc((l))) == NULL) goto eexit;
/* Make our env + space for profile, wireless and debug */
env = calloc(1, sizeof(char *) * (elen + 3 + 1));
env = calloc(1, sizeof(char *) * (elen + 4 + 1));
if (env == NULL)
goto eexit;
e = strlen("interface") + strlen(ifp->name) + 2;
@ -320,8 +328,7 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
snprintf(env[7], e, "ifmtu=%d", if_getmtu(ifp->name));
l = e = strlen("interface_order=");
TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
if (!(ifp2->options->options & DHCPCD_PFXDLGONLY))
e += strlen(ifp2->name) + 1;
e += strlen(ifp2->name) + 1;
}
EMALLOC(8, e);
p = env[8];
@ -329,13 +336,11 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
e -= l;
p += l;
TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
if (!(ifp2->options->options & DHCPCD_PFXDLGONLY)) {
l = strlcpy(p, ifp2->name, e);
p += l;
e -= l;
*p++ = ' ';
e--;
}
l = strlcpy(p, ifp2->name, e);
p += l;
e -= l;
*p++ = ' ';
e--;
}
*--p = '\0';
if (strcmp(reason, "STOPPED") == 0) {
@ -354,6 +359,7 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
} else if (1 == 2 /* appease ifdefs */
#ifdef INET
|| (dhcp && state && state->new)
|| (ipv4ll && IPV4LL_STATE_RUNNING(ifp))
#endif
#ifdef INET6
|| (dhcp6 && d6_state && d6_state->new)
@ -369,12 +375,22 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
}
if (env[9] == NULL || env[10] == NULL)
goto eexit;
if (dhcpcd_oneup(ifp->ctx))
env[11] = strdup("if_oneup=true");
else
env[11] = strdup("if_oneup=false");
if (env[11] == NULL)
goto eexit;
if ((af = dhcpcd_ifafwaiting(ifp)) != AF_MAX) {
e = 20;
EMALLOC(elen, e);
snprintf(env[elen++], e, "if_afwaiting=%d", af);
}
if ((af = dhcpcd_afwaiting(ifp->ctx)) != AF_MAX) {
TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) {
if ((af = dhcpcd_ifafwaiting(ifp2)) != AF_MAX)
break;
}
}
if (af != AF_MAX) {
e = 20;
EMALLOC(elen, e);
snprintf(env[elen++], e, "af_waiting=%d", af);
}
if (ifo->options & DHCPCD_DEBUG) {
e = strlen("syslog_debug=true") + 1;
EMALLOC(elen, e);
@ -424,16 +440,6 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
}
#endif
#ifdef INET6
if (dhcp6 && d6_state && ifo->options & DHCPCD_PFXDLGONLY) {
nenv = realloc(env, sizeof(char *) * (elen + 2));
if (nenv == NULL)
goto eexit;
env = nenv;
env[elen] = strdup("ifclass=pd");
if (env[elen] == NULL)
goto eexit;
elen++;
}
if (dhcp6 && d6_state && d6_state->old) {
n = dhcp6_env(NULL, NULL, ifp,
d6_state->old, d6_state->old_len);
@ -454,6 +460,20 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
dumplease:
#ifdef INET
if (ipv4ll) {
n = ipv4ll_env(NULL, NULL, ifp);
if (n > 0) {
nenv = realloc(env, sizeof(char *) *
(elen + (size_t)n + 1));
if (nenv == NULL)
goto eexit;
env = nenv;
if ((n = ipv4ll_env(env + elen,
istate->down ? "old" : "new", ifp)) == -1)
goto eexit;
elen += (size_t)n;
}
}
if (dhcp && state && state->new) {
n = dhcp_env(NULL, NULL, state->new, ifp);
if (n > 0) {
@ -595,6 +615,10 @@ send_interface(struct fd_list *fd, const struct interface *ifp)
if (send_interface1(fd, ifp, d->reason) == -1)
retval = -1;
}
if (IPV4LL_STATE_RUNNING(ifp)) {
if (send_interface1(fd, ifp, "IPV4LL") == -1)
retval = -1;
}
#endif
#ifdef INET6
@ -625,20 +649,27 @@ script_runreason(const struct interface *ifp, const char *reason)
if (ifp->options->script &&
(ifp->options->script[0] == '\0' ||
strcmp(ifp->options->script, "/dev/null") == 0))
strcmp(ifp->options->script, "/dev/null") == 0) &&
TAILQ_FIRST(&ifp->ctx->control_fds) == NULL)
return 0;
argv[0] = ifp->options->script ? ifp->options->script : UNCONST(SCRIPT);
argv[1] = NULL;
logger(ifp->ctx, LOG_DEBUG, "%s: executing `%s' %s",
ifp->name, argv[0], reason);
/* Make our env */
elen = (size_t)make_env(ifp, reason, &env);
if (elen == (size_t)-1) {
logger(ifp->ctx, LOG_ERR, "%s: make_env: %m", ifp->name);
return -1;
}
if (ifp->options->script &&
(ifp->options->script[0] == '\0' ||
strcmp(ifp->options->script, "/dev/null") == 0))
goto send_listeners;
argv[0] = ifp->options->script ? ifp->options->script : UNCONST(SCRIPT);
argv[1] = NULL;
logger(ifp->ctx, LOG_DEBUG, "%s: executing `%s' %s",
ifp->name, argv[0], reason);
/* Resize for PATH and RC_SVCNAME */
svcname = getenv(RC_SVCNAME);
ep = realloc(env, sizeof(char *) * (elen + 2 + (svcname ? 1 : 0)));
@ -697,6 +728,7 @@ script_runreason(const struct interface *ifp, const char *reason)
__func__, argv[0], strsignal(WTERMSIG(status)));
}
send_listeners:
/* Send to our listeners */
bigenv = NULL;
status = 0;