Sync
This commit is contained in:
parent
c4c68644a2
commit
76ccb05303
|
@ -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) {
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 *,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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__);
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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
|
||||
|
||||
##############################################################################
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 .
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 **);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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[];
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue