Import dhcpcd-7.0.0-rc2 with the following changes:

*  dhcp: fixed classless static routes
  *  prefix delegation: build routes after assigning addresses
  *  dhcp: on lease expiration, discover only when carrier
  *  ip6: fix potential segfault when lifetime overflows
  *  dhcp: fix reporting of DNS encoded SIP servers
  *  dhcp6: fix unicast in non master mode
This commit is contained in:
roy 2017-09-19 19:16:48 +00:00
parent 9745661280
commit 2e864d58b0
29 changed files with 1165 additions and 880 deletions

View File

@ -9,6 +9,7 @@ CONFMODE?= 0644
CC?= cc
INSTALL?= install
LINT?= lint
SED?= sed
HOST_SH?= /bin/sh

View File

@ -52,10 +52,18 @@ hostname
# In this case, comment out duid and enable clientid above.
duid
# Persist interface configuration when dhcpcd exits.
persistent
# Rapid commit support.
# Safe to enable by default because it requires the equivalent option set
# on the server to actually work.
option rapid_commit
# A list of options to request from the DHCP server.
option domain_name_servers, domain_name, domain_search, host_name
option classless_static_routes
# Respect the network MTU.
# Respect the network MTU. This is applied to DHCP routes.
option interface_mtu
# Most distributions have NTP support.
@ -88,4 +96,4 @@ install similar logic into their dhcpcd package.
We no longer supply a ChangeLog.
However, you're more than welcome to read the
[commit log](http://roy.marples.name/git/dhcpcd.git/log/) and
[archived release annoucements](http://roy.marples.name/archives/dhcpcd-discuss/).
[archived release announcements](http://roy.marples.name/archives/dhcpcd-discuss/).

View File

@ -3,14 +3,18 @@
# Handy variables and functions for our hooks to use
case "$reason" in
PREINIT|CARRIER|NOCARRIER|DEPARTED|STOPPED|DUMP|TEST)
ifsuffix=;; #unset
ROUTERADVERT)
ifsuffix=".ra";;
INFORM6|BOUND6|RENEW6|REBIND6|REBOOT6|EXPIRE6|RELEASE6|STOP6)
ifsuffix=".dhcp6";;
IPV4LL)
ifsuffix=".ipv4ll";;
*)
INFORM|BOUND|RENEW|REBIND|REBOOT|EXPIRE|RELEASE|STOP)
ifsuffix=".dhcp";;
*)
ifsuffix=;; #unset
esac
ifname="$interface$ifsuffix"
@ -33,10 +37,10 @@ uniqify()
for i do
case " $result " in
*" $i "*);;
*) result="$result $i";;
*) result="$result${result:+ }$i";;
esac
done
echo "${result# *}"
echo "$result"
}
# List interface config files in a directory.
@ -198,8 +202,7 @@ syslog()
fi
}
# Check for a valid domain name as per RFC1123 with the exception of
# allowing - and _ as they seem to be widely used.
# Check for a valid name as per RFC952 and RFC1123 section 2.1
valid_domainname()
{
local name="$1" label
@ -211,14 +214,12 @@ valid_domainname()
[ -z "$label" -o ${#label} -gt 63 ] && return 1
case "$label" in
-*|_*|*-|*_) return 1;;
# some sh require - as the first or last character in the class
# when matching it
*[![:alnum:]_-]*) return 1;;
"$name") return 0;;
esac
[ "$name" = "${name#*.}" ] && break
name="${name#*.}"
done
return 0
return 0
}
valid_domainname_list()
@ -231,16 +232,6 @@ valid_domainname_list()
return 0
}
# Check for a valid path
valid_path()
{
case "$@" in
*[![:alnum:]#%+-_:\.,@~\\/\[\]=\ ]*) return 1;;
esac
return 0
}
# With the advent of alternative init systems, it's possible to have
# more than one installed. So we need to try and guess what one we're
# using unless overriden by configure.

View File

@ -71,6 +71,9 @@ depend: .depend
${PROG}: ${DEPEND} ${OBJS}
${CC} ${LDFLAGS} -o $@ ${OBJS} ${LDADD}
lint:
${LINT} -Suz ${CPPFLAGS} ${SRCS} ${PCRYPT_SRCS} ${PCOMPAT_SRCS}
_embeddedinstall: ${DHCPCD_DEFS}
${INSTALL} -d ${DESTDIR}${LIBEXECDIR}
${INSTALL} -m ${CONFMODE} ${DHCPCD_DEFS} ${DESTDIR}${LIBEXECDIR}

View File

@ -35,7 +35,6 @@
#include <netinet/if_ether.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@ -53,7 +52,7 @@
#include "ipv4ll.h"
#include "logerr.h"
#if defined(ARP) && (!defined(KERNEL_RFC5227) || defined(ARPING))
#if defined(ARP)
#define ARP_LEN \
(sizeof(struct arphdr) + (2 * sizeof(uint32_t)) + (2 * HWADDR_LEN))
@ -282,8 +281,6 @@ arp_probe(struct arp_state *astate)
astate->iface->name, inet_ntoa(astate->addr));
arp_probe1(astate);
}
#else /* !ARP */
#define arp_close(ifp) {}
#endif /* ARP */
static void
@ -305,11 +302,6 @@ arp_announce1(void *arg)
struct arp_state *astate = arg;
struct interface *ifp = astate->iface;
#ifdef KERNEL_RFC5227
/* We rely on the kernel announcing correctly.
* As the timings are not random we can callback safely. */
astate->claims++;
#else
if (++astate->claims < ANNOUNCE_NUM)
logdebugx("%s: ARP announcing %s (%d of %d), "
"next in %d.0 seconds",
@ -321,27 +313,80 @@ arp_announce1(void *arg)
astate->claims, ANNOUNCE_NUM);
if (arp_request(ifp, astate->addr.s_addr, astate->addr.s_addr) == -1)
logerr(__func__);
#endif
eloop_timeout_add_sec(ifp->ctx->eloop, ANNOUNCE_WAIT,
astate->claims < ANNOUNCE_NUM ? arp_announce1 : arp_announced,
astate);
}
/*
* XXX FIXME
* Kernels supporting RFC5227 will announce the address when it's
* added.
* dhcpcd should not announce when this happens, nor need to open
* a BPF socket for it.
* Also, an address might be added to a non preferred inteface when
* the same address exists on a preferred one so we need to instruct
* the kernel not to announce the address somehow.
*/
void
arp_announce(struct arp_state *astate)
{
struct iarp_state *state;
struct interface *ifp;
struct arp_state *a2;
int r;
#ifndef KERNEL_RFC5227
if (arp_open(astate->iface) == -1) {
logerr(__func__);
return;
}
#endif
/* Cancel any other ARP announcements for this address. */
TAILQ_FOREACH(ifp, astate->iface->ctx->ifaces, next) {
state = ARP_STATE(ifp);
if (state == NULL)
continue;
TAILQ_FOREACH(a2, &state->arp_states, next) {
if (astate == a2 ||
a2->addr.s_addr != astate->addr.s_addr)
continue;
r = eloop_timeout_delete(a2->iface->ctx->eloop,
a2->claims < ANNOUNCE_NUM
? arp_announce1 : arp_announced,
a2);
if (r == -1)
logerr(__func__);
else if (r != 0)
logdebugx("%s: ARP announcement "
"of %s cancelled",
a2->iface->name,
inet_ntoa(a2->addr));
}
}
astate->claims = 0;
arp_announce1(astate);
}
void
arp_announceaddr(struct dhcpcd_ctx *ctx, struct in_addr *ia)
{
struct interface *ifp;
struct arp_state *astate;
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
if (ipv4_iffindaddr(ifp, ia, NULL))
break;
}
if (ifp == NULL)
return;
astate = arp_find(ifp, ia);
if (astate != NULL)
arp_announce(astate);
}
void
arp_report_conflicted(const struct arp_state *astate,
const struct arp_msg *amsg)

View File

@ -85,25 +85,21 @@ struct iarp_state {
#define ARP_CSTATE(ifp) \
((const struct iarp_state *)(ifp)->if_data[IF_DATA_ARP])
#if defined(ARP) && (!defined(KERNEL_RFC5227) || defined(ARPING))
#ifdef ARP
int arp_open(struct interface *);
ssize_t arp_request(const struct interface *, in_addr_t, in_addr_t);
void arp_probe(struct arp_state *);
void arp_close(struct interface *);
#endif
#ifdef ARP
void arp_report_conflicted(const struct arp_state *, const struct arp_msg *);
struct arp_state *arp_new(struct interface *, const struct in_addr *);
struct arp_state *arp_find(struct interface *, const struct in_addr *);
void arp_announce(struct arp_state *);
void arp_announceaddr(struct dhcpcd_ctx *, struct in_addr *);
void arp_cancel(struct arp_state *);
void arp_free(struct arp_state *);
void arp_free_but(struct arp_state *);
void arp_drop(struct interface *);
void arp_handleifa(int, struct ipv4_addr *);
#else
#define arp_drop(a) {}
#endif
#endif
#endif /* ARP */
#endif /* ARP_H */

View File

@ -50,7 +50,7 @@
#ifndef htonll
#if (BYTE_ORDER == LITTLE_ENDIAN)
#define htonll(x) ((uint64_t)htonl((uint32_t)((x) >> 32)) | \
(uint64_t)htonl((uint32_t)((x) & 0xffffffff)) << 32)
(uint64_t)htonl((uint32_t)((x) & 0x00000000ffffffffULL)) << 32)
#else /* (BYTE_ORDER == LITTLE_ENDIAN) */
#define htonll(x) (x)
#endif
@ -59,7 +59,7 @@
#ifndef ntohll
#if (BYTE_ORDER == LITTLE_ENDIAN)
#define ntohll(x) ((uint64_t)ntohl((uint32_t)((x) >> 32)) | \
(uint64_t)ntohl((uint32_t)((x) & 0xffffffff)) << 32)
(uint64_t)ntohl((uint32_t)((x) & 0x00000000ffffffffULL)) << 32)
#else /* (BYTE_ORDER == LITTLE_ENDIAN) */
#define ntohll(x) (x)
#endif

View File

@ -179,7 +179,6 @@ read_hwaddr_aton(uint8_t **data, const char *path)
FILE *fp;
char *buf;
size_t buf_len, len;
ssize_t llen;
if ((fp = fopen(path, "r")) == NULL)
return 0;
@ -187,7 +186,7 @@ read_hwaddr_aton(uint8_t **data, const char *path)
buf = NULL;
buf_len = len = 0;
*data = NULL;
while ((llen = getline(&buf, &buf_len, fp)) != -1) {
while (getline(&buf, &buf_len, fp) != -1) {
if ((len = hwaddr_aton(NULL, buf)) != 0) {
if (buf_len >= len)
*data = (uint8_t *)buf;

View File

@ -28,7 +28,7 @@
#define CONFIG_H
#define PACKAGE "dhcpcd"
#define VERSION "7.0.0-rc1"
#define VERSION "7.0.0-rc2"
#ifndef CONFIG
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"

View File

@ -315,23 +315,19 @@ ssize_t
decode_rfc1035(char *out, size_t len, const uint8_t *p, size_t pl)
{
const char *start;
size_t start_len, l, count;
size_t start_len, l, d_len, o_len;
const uint8_t *r, *q = p, *e;
int hops;
uint8_t ltype;
if (pl > NS_MAXCDNAME) {
errno = E2BIG;
return -1;
}
count = 0;
o_len = 0;
start = out;
start_len = len;
q = p;
e = p + pl;
while (q < e) {
r = NULL;
d_len = 0;
hops = 0;
/* Check we are inside our length again in-case
* the name isn't fully qualified (ie, not terminated) */
@ -370,16 +366,16 @@ decode_rfc1035(char *out, size_t len, const uint8_t *p, size_t pl)
errno = ERANGE;
return -1;
}
count += l + 1;
if (l > NS_MAXLABEL) {
errno = EINVAL;
return -1;
}
d_len += l + 1;
if (out) {
if (l + 1 > len) {
errno = ENOBUFS;
return -1;
}
if (l + 1 > NS_MAXLABEL) {
errno = EINVAL;
return -1;
}
memcpy(out, q, l);
out += l;
*out++ = '.';
@ -389,6 +385,14 @@ decode_rfc1035(char *out, size_t len, const uint8_t *p, size_t pl)
q += l;
}
}
/* Don't count the trailing NUL */
if (d_len > NS_MAXDNAME + 1) {
errno = E2BIG;
return -1;
}
o_len += d_len;
/* change last dot to space */
if (out && out != start)
*(out - 1) = ' ';
@ -404,18 +408,14 @@ decode_rfc1035(char *out, size_t len, const uint8_t *p, size_t pl)
*out = '\0';
}
if (count)
/* Don't count the trailing NUL */
count--;
if (count > NS_MAXDNAME) {
errno = E2BIG;
return -1;
}
return (ssize_t)count;
/* Remove the trailing NUL */
if (o_len != 0)
o_len--;
return (ssize_t)o_len;
}
/* Check for a valid domain name as per RFC1123 with the exception of
* allowing - and _ (but not at start or end) as they seem to be widely used. */
/* Check for a valid name as per RFC952 and RFC1123 section 2.1 */
static int
valid_domainname(char *lbl, int type)
{
@ -504,7 +504,7 @@ print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl)
if (type & OT_BINHEX) {
if (dst) {
if (len == 0 || len == 1) {
errno = ENOSPC;
errno = ENOBUFS;
return -1;
}
*dst++ = hexchrs[(c & 0xF0) >> 4];
@ -532,7 +532,7 @@ print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl)
if (c == '\\') {
if (dst) {
if (len == 0 || len == 1) {
errno = ENOSPC;
errno = ENOBUFS;
return -1;
}
*dst++ = '\\'; *dst++ = '\\';
@ -543,7 +543,7 @@ print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl)
}
if (dst) {
if (len < 5) {
errno = ENOSPC;
errno = ENOBUFS;
return -1;
}
*dst++ = '\\';
@ -556,7 +556,7 @@ print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl)
} else {
if (dst) {
if (len == 0) {
errno = ENOSPC;
errno = ENOBUFS;
return -1;
}
*dst++ = (char)c;
@ -569,7 +569,7 @@ print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl)
/* NULL */
if (dst) {
if (len == 0) {
errno = ENOSPC;
errno = ENOBUFS;
return -1;
}
*dst = '\0';
@ -669,19 +669,18 @@ print_option(char *s, size_t len, const struct dhcp_opt *opt,
struct in_addr addr;
ssize_t bytes = 0, sl;
size_t l;
#ifdef INET
char *tmp;
#endif
if (opt->type & OT_RFC1035) {
sl = decode_rfc1035(NULL, 0, data, dl);
sl = decode_rfc1035(s, len, data, dl);
if (sl == 0 || sl == -1)
return sl;
l = (size_t)sl + 1;
tmp = malloc(l);
if (tmp == NULL)
return -1;
decode_rfc1035(tmp, l, data, dl);
sl = print_string(s, len, opt->type, (uint8_t *)tmp, l - 1);
free(tmp);
if (s != NULL) {
if (valid_domainname(s, opt->type) == -1)
return -1;
}
return sl;
}
@ -868,6 +867,7 @@ dhcp_envoption1(char **env, const char *prefix,
ssize_t len;
size_t e;
char *v, *val;
int r;
/* Ensure a valid length */
ol = (size_t)dhcp_optlen(opt, ol);
@ -890,11 +890,18 @@ dhcp_envoption1(char **env, const char *prefix,
if (v == NULL)
return 0;
if (vname)
v += snprintf(val, e, "%s_%s=", prefix, opt->var);
r = snprintf(val, e, "%s_%s=", prefix, opt->var);
else
v += snprintf(val, e, "%s=", prefix);
if (len != 0)
print_option(v, (size_t)len + 1, opt, od, ol, ifname);
r = snprintf(val, e, "%s=", prefix);
if (r != -1 && len != 0) {
v += r;
if (print_option(v, (size_t)len + 1, opt, od, ol, ifname) == -1)
r = -1;
}
if (r == -1) {
free(val);
return 0;
}
return e;
}

View File

@ -183,6 +183,7 @@ struct dhcp_lease {
};
enum DHS {
DHS_NONE,
DHS_INIT,
DHS_DISCOVER,
DHS_REQUEST,

File diff suppressed because it is too large Load Diff

View File

@ -108,30 +108,40 @@
#define D6_STATUS_NOTONLINK 4
#define D6_STATUS_USEMULTICAST 5
#define SOL_MAX_DELAY 1
#define SOL_TIMEOUT 1
#define SOL_MAX_RT 3600 /* RFC7083 */
#define REQ_TIMEOUT 1
#define REQ_MAX_RT 30
#define REQ_MAX_RC 10
#define CNF_MAX_DELAY 1
#define CNF_TIMEOUT 1
#define CNF_MAX_RT 4
#define CNF_MAX_RD 10
#define REN_TIMEOUT 10
#define REN_MAX_RT 600
#define REB_TIMEOUT 10
#define REB_MAX_RT 600
#define INF_MAX_DELAY 1
#define INF_TIMEOUT 1
#define INF_MAX_RT 3600 /* RFC7083 */
#define REL_TIMEOUT 1
#define REL_MAX_RC 5
#define DEC_TIMEOUT 1
#define DEC_MAX_RC 5
#define REC_TIMEOUT 2
#define REC_MAX_RC 8
#define HOP_COUNT_LIMIT 32
#define SOL_MAX_DELAY 1
#define SOL_TIMEOUT 1
#define SOL_MAX_RT 3600 /* RFC7083 */
#define SOL_MAX_RC 0
#define REQ_MAX_DELAY 0
#define REQ_TIMEOUT 1
#define REQ_MAX_RT 30
#define REQ_MAX_RC 10
#define CNF_MAX_DELAY 1
#define CNF_TIMEOUT 1
#define CNF_MAX_RT 4
#define CNF_MAX_RC 0
#define CNF_MAX_RD 10
#define REN_MAX_DELAY 0
#define REN_TIMEOUT 10
#define REN_MAX_RT 600
#define REB_MAX_DELAY 0
#define REB_TIMEOUT 10
#define REB_MAX_RT 600
#define INF_MAX_DELAY 1
#define INF_TIMEOUT 1
#define INF_MAX_RD CNF_MAX_RD /* NOT RFC defined */
#define INF_MAX_RT 3600 /* RFC7083 */
#define REL_MAX_DELAY 0
#define REL_TIMEOUT 1
#define REL_MAX_RT 0
#define REL_MAX_RC 5
#define DEC_MAX_DELAY 0
#define DEC_TIMEOUT 1
#define DEC_MAX_RC 5
#define REC_MAX_DELAY 0
#define REC_TIMEOUT 2
#define REC_MAX_RC 8
#define HOP_COUNT_LIMIT 32
/* RFC4242 3.1 */
#define IRT_DEFAULT 86400
@ -153,6 +163,8 @@ enum DH6S {
DH6S_RENEW_REQUESTED,
DH6S_PROBE,
DH6S_DELEGATED,
DH6S_TIMEDOUT,
DH6S_ITIMEDOUT,
DH6S_RELEASE,
DH6S_RELEASED
};
@ -181,6 +193,7 @@ struct dhcp6_state {
struct dhcp6_message *old;
size_t old_len;
struct timespec acquired;
uint32_t renew;
uint32_t rebind;
uint32_t expire;
@ -206,9 +219,9 @@ struct dhcp6_state {
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);
const struct in6_addr *addr, unsigned int flags);
struct ipv6_addr *dhcp6_findaddr(struct dhcpcd_ctx *, const struct in6_addr *,
short);
unsigned int);
size_t dhcp6_find_delegates(struct interface *);
int dhcp6_start(struct interface *, enum DH6S);
void dhcp6_reboot(struct interface *);

View File

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd May 9, 2017
.Dd August 29, 2017
.Dt DHCPCD 8
.Os
.Sh NAME
@ -584,6 +584,15 @@ will try to do as much as it can by default.
However, there are sometimes situations where you don't want the things to be
configured exactly how the the DHCP server wants.
Here are some options that deal with turning these bits off.
.Pp
Note that when
.Nm
is restricted to a single interface then the interface also needs to be
specified when asking
.Nm
to exit using the commandline.
If the protocol is restricted as well then the protocol needs to be included
with the exit instruction.
.Bl -tag -width indent
.It Fl 1 , Fl Fl oneshot
Exit after configuring an interface.

View File

@ -436,7 +436,7 @@ eloop_event_add_w(struct eloop *eloop, int fd,
return eloop_event_add_rw(eloop, fd, NULL,NULL, write_cb, write_cb_arg);
}
void
int
eloop_event_delete_write(struct eloop *eloop, int fd, int write_only)
{
struct eloop_event *e;
@ -450,11 +450,14 @@ eloop_event_delete_write(struct eloop *eloop, int fd, int write_only)
if (fd > eloop->events_maxfd ||
(e = eloop->event_fds[fd]) == NULL)
return;
{
errno = ENOENT;
return -1;
}
if (write_only) {
if (e->write_cb == NULL)
return;
return 0;
if (e->read_cb == NULL)
goto remove;
e->write_cb = NULL;
@ -471,7 +474,7 @@ eloop_event_delete_write(struct eloop *eloop, int fd, int write_only)
epoll_ctl(eloop->poll_fd, EPOLL_CTL_MOD, fd, &epe);
#endif
eloop_event_setup_fds(eloop);
return;
return 1;
}
remove:
@ -495,6 +498,7 @@ remove:
#endif
eloop_event_setup_fds(eloop);
return 1;
}
int
@ -586,14 +590,16 @@ eloop_timeout_add_now(struct eloop *eloop,
}
#endif
void
int
eloop_q_timeout_delete(struct eloop *eloop, int queue,
void (*callback)(void *), void *arg)
{
struct eloop_timeout *t, *tt;
int n;
assert(eloop != NULL);
n = 0;
TAILQ_FOREACH_SAFE(t, &eloop->timeouts, next, tt) {
if ((queue == 0 || t->queue == queue) &&
t->arg == arg &&
@ -601,8 +607,10 @@ eloop_q_timeout_delete(struct eloop *eloop, int queue,
{
TAILQ_REMOVE(&eloop->timeouts, t, next);
TAILQ_INSERT_TAIL(&eloop->free_timeouts, t, next);
n++;
}
}
return n;
}
void

View File

@ -80,7 +80,7 @@ int eloop_event_add_w(struct eloop *, int,
eloop_event_delete_write((eloop), (fd), 0)
#define eloop_event_remove_writecb(eloop, fd) \
eloop_event_delete_write((eloop), (fd), 1)
void eloop_event_delete_write(struct eloop *, int, int);
int eloop_event_delete_write(struct eloop *, int, int);
#define eloop_timeout_add_tv(eloop, tv, cb, ctx) \
eloop_q_timeout_add_tv((eloop), ELOOP_QUEUE, (tv), (cb), (ctx))
@ -96,7 +96,7 @@ int eloop_q_timeout_add_sec(struct eloop *, int,
time_t, void (*)(void *), void *);
int eloop_q_timeout_add_msec(struct eloop *, int,
long, void (*)(void *), void *);
void eloop_q_timeout_delete(struct eloop *, int, void (*)(void *), void *);
int eloop_q_timeout_delete(struct eloop *, int, void (*)(void *), void *);
int eloop_signal_set_cb(struct eloop *, const int *, size_t,
void (*)(int, void *), void *);

View File

@ -437,7 +437,7 @@ if_copysa(struct sockaddr *dst, const struct sockaddr *src)
assert(src != NULL);
memcpy(dst, src, src->sa_len);
#ifdef __KAME__
#if defined(INET6) && defined(__KAME__)
if (dst->sa_family == AF_INET6) {
struct in6_addr *in6;
@ -505,8 +505,7 @@ if_route(unsigned char cmd, const struct rt *rt)
if (!(rtm->rtm_flags & RTF_REJECT) &&
!sa_is_loopback(&rt->rt_gateway))
{
if (!gateway_unspec)
rtm->rtm_addrs |= RTA_IFP;
rtm->rtm_addrs |= RTA_IFP;
if (!sa_is_unspecified(&rt->rt_ifa))
rtm->rtm_addrs |= RTA_IFA;
}
@ -770,7 +769,7 @@ ifa_scope(struct sockaddr_in6 *sin, unsigned int ifindex)
#ifdef __KAME__
/* KAME based systems want to store the scope inside the sin6_addr
* for link local addreses */
* for link local addresses */
if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
uint16_t scope = htons((uint16_t)ifindex);
memcpy(&sin->sin6_addr.s6_addr[2], &scope,
@ -1398,6 +1397,16 @@ set_ifxflags(int s, const struct interface *ifp)
}
#endif
/* OpenBSD removed ND6 flags entirely, so we need to check for their
* existnance. */
#if defined(ND6_IFF_AUTO_LINKLOCAL) || \
defined(ND6_IFF_PERFORMNUD) || \
defined(ND6_IFF_ACCEPT_RTADV) || \
defined(ND6_IFF_OVERRIDE_RTADV) || \
defined(ND6_IFF_IFDISABLED)
#define ND6_NDI_FLAGS
#endif
int
if_checkipv6(struct dhcpcd_ctx *ctx, const struct interface *ifp)
{
@ -1408,6 +1417,7 @@ if_checkipv6(struct dhcpcd_ctx *ctx, const struct interface *ifp)
s = priv->pf_inet6_fd;
if (ifp) {
#ifdef ND6_NDI_FLAGS
struct in6_ndireq nd;
int flags;
@ -1416,6 +1426,7 @@ if_checkipv6(struct dhcpcd_ctx *ctx, const struct interface *ifp)
if (ioctl(s, SIOCGIFINFO_IN6, &nd) == -1)
return -1;
flags = (int)nd.ndi.flags;
#endif
#ifdef ND6_IFF_AUTO_LINKLOCAL
if (!(ctx->options & DHCPCD_TEST) &&
@ -1454,6 +1465,7 @@ if_checkipv6(struct dhcpcd_ctx *ctx, const struct interface *ifp)
flags &= ~ND6_IFF_IFDISABLED;
#endif
#ifdef ND6_NDI_FLAGS
if (nd.ndi.flags != (uint32_t)flags) {
if (ctx->options & DHCPCD_TEST) {
logwarnx("%s: interface not IPv6 enabled",
@ -1466,6 +1478,7 @@ if_checkipv6(struct dhcpcd_ctx *ctx, const struct interface *ifp)
return -1;
}
}
#endif
/* Enabling IPv6 by whatever means must be the
* last action undertaken to ensure kernel RS and

View File

@ -1310,7 +1310,7 @@ const char *bpf_name = "Packet Socket";
int
bpf_open(struct interface *ifp, int (*filter)(struct interface *, int))
{
struct ipv4_state *state = IPV4_STATE(ifp);
struct ipv4_state *state;
/* Linux is a special snowflake for opening BPF. */
int s;
union sockunion {
@ -1328,6 +1328,9 @@ bpf_open(struct interface *ifp, int (*filter)(struct interface *, int))
#undef SF
/* Allocate a suitably large buffer for a single packet. */
state = ipv4_getstate(ifp);
if (state == NULL)
goto eexit;
if (state->buffer_size < ETH_DATA_LEN) {
void *nb;

View File

@ -143,10 +143,12 @@ struct if_ia {
uint8_t iaid_set;
struct in6_addr addr;
uint8_t prefix_len;
#ifndef SMALL
uint32_t sla_max;
size_t sla_len;
struct if_sla *sla;
#endif
#endif
};
struct vivco {

View File

@ -264,6 +264,24 @@ static void if_learnaddrs(struct dhcpcd_ctx *ctx, struct if_head *ifs,
}
}
bool
if_valid_hwaddr(const uint8_t *hwaddr, size_t hwlen)
{
size_t i;
bool all_zeros, all_ones;
all_zeros = all_ones = true;
for (i = 0; i < hwlen; i++) {
if (hwaddr[i] != 0x00)
all_zeros = false;
if (hwaddr[i] != 0xff)
all_ones = false;
if (!all_zeros && !all_ones)
return true;
}
return false;
}
struct if_head *
if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
{
@ -469,6 +487,10 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
ifp->index = if_nametoindex(ifp->name);
#endif
/* Ensure hardware address is valid. */
if (!if_valid_hwaddr(ifp->hwaddr, ifp->hwlen))
ifp->hwlen = 0;
/* We only work on ethernet by default */
if (ifp->family != ARPHRD_ETHER) {
if ((argc == 0 || argc == -1) &&

View File

@ -111,6 +111,7 @@ int if_getifaddrs(struct ifaddrs **);
int if_setflag(struct interface *ifp, short flag);
#define if_up(ifp) if_setflag((ifp), (IFF_UP | IFF_RUNNING))
bool if_valid_hwaddr(const uint8_t *, size_t);
struct if_head *if_discover(struct dhcpcd_ctx *, int, char * const *);
struct interface *if_find(struct if_head *, const char *);
struct interface *if_findindex(struct if_head *, unsigned int);

View File

@ -255,9 +255,12 @@ inet_dhcproutes(struct rt_head *routes, struct interface *ifp)
int n;
state = D_CSTATE(ifp);
if (state == NULL || state->state != DHS_BOUND)
if (state == NULL || state->state != DHS_BOUND || !state->added)
return 0;
/* An address does have to exist. */
assert(state->addr);
TAILQ_INIT(&nroutes);
/* First, add a subnet route. */
@ -667,50 +670,11 @@ ipv4_daddaddr(struct interface *ifp, const struct dhcp_lease *lease)
return 0;
}
int
ipv4_preferanother(struct interface *ifp)
{
struct dhcp_state *state = D_STATE(ifp), *nstate;
struct interface *ifn;
int preferred;
if (state == NULL)
return 0;
preferred = 0;
if (!state->added)
goto out;
TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
if (ifn == ifp)
break; /* We are already the most preferred */
nstate = D_STATE(ifn);
if (nstate && !nstate->added &&
state->addr != NULL &&
nstate->lease.addr.s_addr == state->addr->addr.s_addr)
{
preferred = 1;
delete_address(ifp);
if (ifn->options->options & DHCPCD_ARP)
dhcp_bind(ifn);
else {
ipv4_daddaddr(ifn, &nstate->lease);
nstate->added = STATE_ADDED;
}
break;
}
}
out:
rt_build(ifp->ctx, AF_INET);
return preferred;
}
void
ipv4_applyaddr(void *arg)
{
struct interface *ifp = arg, *ifn;
struct dhcp_state *state = D_STATE(ifp), *nstate;
struct interface *ifp = arg;
struct dhcp_state *state = D_STATE(ifp);
struct dhcp_lease *lease;
struct if_options *ifo = ifp->options;
struct ipv4_addr *ia;
@ -720,15 +684,21 @@ ipv4_applyaddr(void *arg)
return;
lease = &state->lease;
if_sortinterfaces(ifp->ctx);
if (state->new == NULL) {
if ((ifo->options & (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
(DHCPCD_EXITING | DHCPCD_PERSISTENT))
{
if (state->added && !ipv4_preferanother(ifp)) {
if (state->added) {
struct in_addr addr;
addr = lease->addr;
delete_address(ifp);
rt_build(ifp->ctx, AF_INET);
#ifdef ARP
/* Announce the preferred address to
* kick ARP caches. */
arp_announceaddr(ifp->ctx, &addr);
#endif
}
script_runreason(ifp, state->reason);
} else
@ -736,45 +706,6 @@ ipv4_applyaddr(void *arg)
return;
}
/* Ensure only one interface has the address */
r = 0;
TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
if (ifn == ifp) {
r = 1; /* past ourselves */
continue;
}
nstate = D_STATE(ifn);
if (nstate && nstate->added &&
nstate->addr &&
nstate->addr->addr.s_addr == lease->addr.s_addr)
{
if (r == 0) {
loginfox("%s: preferring %s on %s",
ifp->name,
inet_ntoa(lease->addr),
ifn->name);
return;
}
loginfox("%s: preferring %s on %s",
ifn->name,
inet_ntoa(lease->addr),
ifp->name);
ipv4_deladdr(nstate->addr, 0);
break;
}
}
/* Does another interface already have the address from a prior boot? */
if (ifn == NULL) {
TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
if (ifn == ifp)
continue;
ia = ipv4_iffindaddr(ifn, &lease->addr, NULL);
if (ia != NULL)
ipv4_deladdr(ia, 0);
}
}
/* If the netmask or broadcast is different, re-add the addresss */
ia = ipv4_iffindaddr(ifp, &lease->addr, NULL);
if (ia &&
@ -821,13 +752,7 @@ ipv4_applyaddr(void *arg)
rt_build(ifp->ctx, AF_INET);
#ifdef ARP
/* Announce the address */
if (ifo->options & DHCPCD_ARP) {
struct arp_state *astate;
if ((astate = arp_find(ifp, &state->addr->addr)) != NULL)
arp_announce(astate);
}
arp_announceaddr(ifp->ctx, &state->addr->addr);
#endif
if (state->state == DHS_BOUND) {

View File

@ -119,7 +119,6 @@ bool inet_getroutes(struct dhcpcd_ctx *, struct rt_head *);
#define STATE_FAKE 0x02
int ipv4_deladdr(struct ipv4_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 *);
@ -140,7 +139,6 @@ void ipv4_free(struct interface *);
#define ipv4_applyaddr(a) {}
#define ipv4_free(a) {}
#define ipv4_hasaddr(a) (0)
#define ipv4_preferanother(a) {}
#endif
#endif

View File

@ -29,7 +29,6 @@
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

View File

@ -379,7 +379,7 @@ ipv6_makeaddr(struct in6_addr *addr, struct interface *ifp,
return 0;
}
int
static int
ipv6_makeprefix(struct in6_addr *prefix, const struct in6_addr *addr, int len)
{
int bytes, bits;
@ -594,7 +594,7 @@ ipv6_deletedaddr(struct ipv6_addr *ia)
#endif
}
static void
void
ipv6_deleteaddr(struct ipv6_addr *ia)
{
struct ipv6_state *state;
@ -619,39 +619,42 @@ ipv6_deleteaddr(struct ipv6_addr *ia)
}
static int
ipv6_addaddr1(struct ipv6_addr *ap, const struct timespec *now)
ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
{
struct interface *ifp;
struct ipv6_state *state;
struct ipv6_addr *nap;
struct ipv6_addr *ia2;
uint32_t pltime, vltime;
__printflike(1, 2) void (*logfunc)(const char *, ...);
/* Ensure no other interface has this address */
TAILQ_FOREACH(ifp, ap->iface->ctx->ifaces, next) {
if (ifp == ap->iface)
TAILQ_FOREACH(ifp, ia->iface->ctx->ifaces, next) {
if (ifp == ia->iface)
continue;
state = IPV6_STATE(ifp);
if (state == NULL)
continue;
TAILQ_FOREACH(nap, &state->addrs, next) {
if (IN6_ARE_ADDR_EQUAL(&nap->addr, &ap->addr)) {
ipv6_deleteaddr(nap);
TAILQ_FOREACH(ia2, &state->addrs, next) {
if (IN6_ARE_ADDR_EQUAL(&ia2->addr, &ia->addr)) {
ipv6_deleteaddr(ia2);
break;
}
}
}
if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
ipv6_iffindaddr(ap->iface, &ap->addr, IN6_IFF_NOTUSEABLE))
ap->flags |= IPV6_AF_DADCOMPLETED;
/* Remember the interface of the address. */
ifp = ia->iface;
if (!(ia->flags & IPV6_AF_DADCOMPLETED) &&
ipv6_iffindaddr(ifp, &ia->addr, IN6_IFF_NOTUSEABLE))
ia->flags |= IPV6_AF_DADCOMPLETED;
/* Adjust plftime and vltime based on acquired time */
pltime = ap->prefix_pltime;
vltime = ap->prefix_vltime;
if (timespecisset(&ap->acquired) &&
(ap->prefix_pltime != ND6_INFINITE_LIFETIME ||
ap->prefix_vltime != ND6_INFINITE_LIFETIME))
pltime = ia->prefix_pltime;
vltime = ia->prefix_vltime;
if (timespecisset(&ia->acquired) &&
(ia->prefix_pltime != ND6_INFINITE_LIFETIME ||
ia->prefix_vltime != ND6_INFINITE_LIFETIME))
{
struct timespec n;
@ -659,88 +662,88 @@ ipv6_addaddr1(struct ipv6_addr *ap, const struct timespec *now)
clock_gettime(CLOCK_MONOTONIC, &n);
now = &n;
}
timespecsub(now, &ap->acquired, &n);
if (ap->prefix_pltime != ND6_INFINITE_LIFETIME) {
ap->prefix_pltime -= (uint32_t)n.tv_sec;
timespecsub(now, &ia->acquired, &n);
if (ia->prefix_pltime != ND6_INFINITE_LIFETIME) {
ia->prefix_pltime -= (uint32_t)n.tv_sec;
/* This can happen when confirming a
* deprecated but still valid lease. */
if (ap->prefix_pltime > pltime)
ap->prefix_pltime = 0;
if (ia->prefix_pltime > pltime)
ia->prefix_pltime = 0;
}
if (ap->prefix_vltime != ND6_INFINITE_LIFETIME) {
ap->prefix_vltime -= (uint32_t)n.tv_sec;
if (ia->prefix_vltime != ND6_INFINITE_LIFETIME) {
ia->prefix_vltime -= (uint32_t)n.tv_sec;
/* This should never happen. */
if (ap->prefix_vltime > vltime) {
if (ia->prefix_vltime > vltime) {
logerrx("%s: %s: lifetime overflow",
ifp->name, ap->saddr);
ap->prefix_vltime = ap->prefix_pltime = 0;
ifp->name, ia->saddr);
ia->prefix_vltime = ia->prefix_pltime = 0;
}
}
}
logfunc = ap->flags & IPV6_AF_NEW ? loginfox : logdebugx;
logfunc("%s: adding %saddress %s", ap->iface->name,
logfunc = ia->flags & IPV6_AF_NEW ? loginfox : logdebugx;
logfunc("%s: adding %saddress %s", ifp->name,
#ifdef IPV6_AF_TEMPORARY
ap->flags & IPV6_AF_TEMPORARY ? "temporary " : "",
ia->flags & IPV6_AF_TEMPORARY ? "temporary " : "",
#else
"",
#endif
ap->saddr);
if (ap->prefix_pltime == ND6_INFINITE_LIFETIME &&
ap->prefix_vltime == ND6_INFINITE_LIFETIME)
ia->saddr);
if (ia->prefix_pltime == ND6_INFINITE_LIFETIME &&
ia->prefix_vltime == ND6_INFINITE_LIFETIME)
logdebugx("%s: pltime infinity, vltime infinity",
ap->iface->name);
else if (ap->prefix_pltime == ND6_INFINITE_LIFETIME)
ifp->name);
else if (ia->prefix_pltime == ND6_INFINITE_LIFETIME)
logdebugx("%s: pltime infinity, vltime %"PRIu32" seconds",
ap->iface->name, ap->prefix_vltime);
else if (ap->prefix_vltime == ND6_INFINITE_LIFETIME)
ifp->name, ia->prefix_vltime);
else if (ia->prefix_vltime == ND6_INFINITE_LIFETIME)
logdebugx("%s: pltime %"PRIu32"seconds, vltime infinity",
ap->iface->name, ap->prefix_pltime);
ifp->name, ia->prefix_pltime);
else
logdebugx("%s: pltime %"PRIu32" seconds, vltime %"PRIu32
" seconds",
ap->iface->name, ap->prefix_pltime, ap->prefix_vltime);
ifp->name, ia->prefix_pltime, ia->prefix_vltime);
if (if_address6(RTM_NEWADDR, ap) == -1) {
if (if_address6(RTM_NEWADDR, ia) == -1) {
logerr(__func__);
/* Restore real pltime and vltime */
ap->prefix_pltime = pltime;
ap->prefix_vltime = vltime;
ia->prefix_pltime = pltime;
ia->prefix_vltime = vltime;
return -1;
}
#ifdef IPV6_MANAGETEMPADDR
/* RFC4941 Section 3.4 */
if (ap->flags & IPV6_AF_TEMPORARY &&
ap->prefix_pltime &&
ap->prefix_vltime &&
ip6_use_tempaddr(ap->iface->name))
eloop_timeout_add_sec(ap->iface->ctx->eloop,
(time_t)ap->prefix_pltime - REGEN_ADVANCE,
ipv6_regentempaddr, ap);
if (ia->flags & IPV6_AF_TEMPORARY &&
ia->prefix_pltime &&
ia->prefix_vltime &&
ip6_use_tempaddr(ifp->name))
eloop_timeout_add_sec(ifp->ctx->eloop,
(time_t)ia->prefix_pltime - REGEN_ADVANCE,
ipv6_regentempaddr, ia);
#endif
/* Restore real pltime and vltime */
ap->prefix_pltime = pltime;
ap->prefix_vltime = vltime;
ia->prefix_pltime = pltime;
ia->prefix_vltime = vltime;
ap->flags &= ~IPV6_AF_NEW;
ap->flags |= IPV6_AF_ADDED;
ia->flags &= ~IPV6_AF_NEW;
ia->flags |= IPV6_AF_ADDED;
#ifndef SMALL
if (ap->delegating_prefix != NULL)
ap->flags |= IPV6_AF_DELEGATED;
if (ia->delegating_prefix != NULL)
ia->flags |= IPV6_AF_DELEGATED;
#endif
#ifdef IPV6_POLLADDRFLAG
eloop_timeout_delete(ap->iface->ctx->eloop,
ipv6_checkaddrflags, ap);
if (!(ap->flags & IPV6_AF_DADCOMPLETED)) {
eloop_timeout_delete(ifp->ctx->eloop,
ipv6_checkaddrflags, ia);
if (!(ia->flags & IPV6_AF_DADCOMPLETED)) {
struct timespec tv;
ms_to_ts(&tv, RETRANS_TIMER / 2);
eloop_timeout_add_tv(ap->iface->ctx->eloop,
&tv, ipv6_checkaddrflags, ap);
eloop_timeout_add_tv(ifp->ctx->eloop,
&tv, ipv6_checkaddrflags, ia);
}
#endif
@ -750,18 +753,18 @@ ipv6_addaddr1(struct ipv6_addr *ap, const struct timespec *now)
* Otherwise aliasing gets confused if we add another
* address during DaD. */
state = IPV6_STATE(ap->iface);
TAILQ_FOREACH(nap, &state->addrs, next) {
if (IN6_ARE_ADDR_EQUAL(&nap->addr, &ap->addr))
state = IPV6_STATE(ifp);
TAILQ_FOREACH(ia2, &state->addrs, next) {
if (IN6_ARE_ADDR_EQUAL(&ia2->addr, &ia->addr))
break;
}
if (nap == NULL) {
if ((nap = malloc(sizeof(*nap))) == NULL) {
if (ia2 == NULL) {
if ((ia2 = malloc(sizeof(*ia2))) == NULL) {
logerr(__func__);
return 0; /* Well, we did add the address */
}
memcpy(nap, ap, sizeof(*nap));
TAILQ_INSERT_TAIL(&state->addrs, nap, next);
memcpy(ia2, ia, sizeof(*ia2));
TAILQ_INSERT_TAIL(&state->addrs, ia2, next);
}
#endif
@ -859,7 +862,7 @@ ipv6_addaddr(struct ipv6_addr *ia, const struct timespec *now)
int
ipv6_findaddrmatch(const struct ipv6_addr *addr, const struct in6_addr *match,
short flags)
unsigned int flags)
{
if (match == NULL) {
@ -876,7 +879,7 @@ ipv6_findaddrmatch(const struct ipv6_addr *addr, const struct in6_addr *match,
}
struct ipv6_addr *
ipv6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr, short flags)
ipv6_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr, unsigned int flags)
{
struct ipv6_addr *dap, *nap;
@ -903,6 +906,9 @@ ipv6_addaddrs(struct ipv6_addrhead *addrs)
i = 0;
timespecclear(&now);
TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
/* A delegated prefix is not an address. */
if (ap->flags & IPV6_AF_DELEGATEDPFX)
continue;
if (ap->prefix_vltime == 0) {
if (ap->flags & IPV6_AF_ADDED) {
ipv6_deleteaddr(ap);
@ -952,23 +958,28 @@ ipv6_addaddrs(struct ipv6_addrhead *addrs)
}
void
ipv6_freeaddr(struct ipv6_addr *ap)
ipv6_freeaddr(struct ipv6_addr *ia)
{
#ifndef SMALL
struct ipv6_addr *ia;
struct ipv6_addr *iad;
/* Forget the reference */
if (ap->flags & IPV6_AF_DELEGATEDPFX) {
TAILQ_FOREACH(ia, &ap->pd_pfxs, pd_next) {
ia->delegating_prefix = NULL;
if (ia->flags & IPV6_AF_DELEGATEDPFX) {
TAILQ_FOREACH(iad, &ia->pd_pfxs, pd_next) {
iad->delegating_prefix = NULL;
}
} else if (ap->delegating_prefix != NULL) {
TAILQ_REMOVE(&ap->delegating_prefix->pd_pfxs, ap, pd_next);
} else if (ia->delegating_prefix != NULL) {
TAILQ_REMOVE(&ia->delegating_prefix->pd_pfxs, ia, pd_next);
}
#endif
eloop_q_timeout_delete(ap->iface->ctx->eloop, 0, NULL, ap);
free(ap);
if (ia->dhcp6_fd != -1) {
close(ia->dhcp6_fd);
eloop_event_delete(ia->iface->ctx->eloop, ia->dhcp6_fd);
}
eloop_q_timeout_delete(ia->iface->ctx->eloop, 0, NULL, ia);
free(ia);
}
void
@ -1286,21 +1297,17 @@ ipv6_addlinklocalcallback(struct interface *ifp,
static struct ipv6_addr *
ipv6_newlinklocal(struct interface *ifp)
{
struct ipv6_addr *ap;
struct ipv6_addr *ia;
struct in6_addr in6;
ap = calloc(1, sizeof(*ap));
if (ap != NULL) {
ap->iface = ifp;
ap->prefix.s6_addr32[0] = htonl(0xfe800000);
ap->prefix.s6_addr32[1] = 0;
ap->prefix_len = 64;
ap->dadcounter = 0;
ap->prefix_pltime = ND6_INFINITE_LIFETIME;
ap->prefix_vltime = ND6_INFINITE_LIFETIME;
ap->flags = IPV6_AF_NEW;
ap->addr_flags = IN6_IFF_TENTATIVE;
memset(&in6, 0, sizeof(in6));
in6.s6_addr32[0] = htonl(0xfe800000);
ia = ipv6_newaddr(ifp, &in6, 64, 0);
if (ia != NULL) {
ia->prefix_pltime = ND6_INFINITE_LIFETIME;
ia->prefix_vltime = ND6_INFINITE_LIFETIME;
}
return ap;
return ia;
}
static const uint8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
@ -1445,31 +1452,75 @@ ipv6_tryaddlinklocal(struct interface *ifp)
return ipv6_addlinklocal(ifp);
}
static struct ipv6_addr *
ipv6_newaddr(struct interface *ifp, struct in6_addr *addr, uint8_t prefix_len)
struct ipv6_addr *
ipv6_newaddr(struct interface *ifp, struct in6_addr *addr, uint8_t prefix_len,
unsigned int flags)
{
struct ipv6_addr *ia;
char buf[INET6_ADDRSTRLEN];
const char *cbp;
bool tempaddr;
int addr_flags;
if ((ia = calloc(1, sizeof(*ia))) == NULL)
return NULL;
ia->iface = ifp;
ia->flags = IPV6_AF_NEW;
ia->addr_flags = IN6_IFF_TENTATIVE;
ia->addr = *addr;
ia->prefix_len = prefix_len;
if (ipv6_makeprefix(&ia->prefix, &ia->addr, ia->prefix_len) == -1) {
free(ia);
return NULL;
}
cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf));
if (cbp)
snprintf(ia->saddr, sizeof(ia->saddr), "%s/%d",
cbp, ia->prefix_len);
/* If adding a new DHCP / RA derived address, check current flags
* from an existing address. */
ia = ipv6_iffindaddr(ifp, addr, 0);
if (ia != NULL)
addr_flags = ia->addr_flags;
else
ia->saddr[0] = '\0';
addr_flags = IN6_IFF_TENTATIVE;
ia = calloc(1, sizeof(*ia));
if (ia == NULL)
goto err;
ia->iface = ifp;
ia->flags = IPV6_AF_NEW | flags;
ia->addr_flags = addr_flags;
ia->prefix_len = prefix_len;
ia->dhcp6_fd = -1;
#ifdef IPV6_AF_TEMPORARY
tempaddr = ia->flags & IPV6_AF_TEMPORARY;
#else
tempaddr = false;
#endif
if (ia->flags & IPV6_AF_AUTOCONF && !tempaddr) {
ia->prefix = *addr;
ia->dadcounter = ipv6_makeaddr(&ia->addr, ifp,
&ia->prefix,
ia->prefix_len);
if (ia->dadcounter == -1)
goto err;
} else if (ia->flags & IPV6_AF_RAPFX) {
ia->prefix = *addr;
return ia;
} else if (ia->flags & (IPV6_AF_REQUEST | IPV6_AF_DELEGATEDPFX) &&
prefix_len != 128)
{
ia->prefix = *addr;
cbp = inet_ntop(AF_INET6, &ia->prefix, buf, sizeof(buf));
goto paddr;
} else {
ia->addr = *addr;
if (ipv6_makeprefix(&ia->prefix,
&ia->addr, ia->prefix_len) == -1)
goto err;
}
cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf));
paddr:
if (cbp == NULL)
goto err;
snprintf(ia->saddr, sizeof(ia->saddr), "%s/%d", cbp, ia->prefix_len);
return ia;
err:
logerr(__func__);
free(ia);
return NULL;
}
static void
@ -1569,7 +1620,7 @@ ipv6_startstatic(struct interface *ifp)
struct ipv6_state *state;
ia = ipv6_newaddr(ifp, &ifp->options->req_addr6,
ifp->options->req_prefix_len);
ifp->options->req_prefix_len, 0);
if (ia == NULL)
return -1;
state = IPV6_STATE(ifp);
@ -1865,8 +1916,6 @@ ipv6_createtempaddr(struct ipv6_addr *ia0, const struct timespec *now)
const struct ipv6_addr *ap;
struct ipv6_addr *ia;
uint32_t i, trylimit;
char buf[INET6_ADDRSTRLEN];
const char *cbp;
trylimit = TEMP_IDGEN_RETRIES;
state = IPV6_STATE(ia0->iface);
@ -1913,17 +1962,11 @@ again:
}
}
if ((ia = calloc(1, sizeof(*ia))) == NULL)
return NULL;
ia->iface = ia0->iface;
ia->addr = addr;
ia = ipv6_newaddr(ia0->iface, &addr, ia0->prefix_len,
IPV6_AF_AUTOCONF | IPV6_AF_TEMPORARY);
/* Must be made tentative, for our DaD to work */
ia->addr_flags = IN6_IFF_TENTATIVE;
ia->dadcallback = ipv6_tempdadcallback;
ia->flags = IPV6_AF_NEW | IPV6_AF_AUTOCONF | IPV6_AF_TEMPORARY;
ia->prefix = ia0->prefix;
ia->prefix_len = ia0->prefix_len;
ia->created = ia->acquired = now ? *now : ia0->acquired;
/* Ensure desync is still valid */
@ -1943,11 +1986,6 @@ again:
return NULL;
}
cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf));
if (cbp)
snprintf(ia->saddr, sizeof(ia->saddr), "%s/%d",
cbp, ia->prefix_len); else ia->saddr[0] = '\0';
TAILQ_INSERT_TAIL(&state->addrs, ia, next);
return ia;
}

View File

@ -94,48 +94,6 @@
# undef IPV6_POLLADDRFLAG
#endif
/*
* If dhcpcd handles RA processing instead of the kernel, the kernel needs
* to either allow userland to set temporary addresses or mark an address
* for the kernel to manage temporary addresses from.
* If the kernel allows the former, a global #define is needed, otherwise
* the address marking will be handled in the platform specific address handler.
*
* Some BSDs do not allow userland to set temporary addresses.
* Linux-3.18 allows the marking of addresses from which to manage temp addrs.
*/
#if defined(BSD) && defined(IN6_IFF_TEMPORARY)
#define IPV6_MANAGETEMPADDR
#endif
/*
* You could enable IPV6_MANAGETEMPADDR anyway and disable the platform
* specific address marking to test dhcpcd's temporary address handling as well,
* but this will not affect source address selection so is of very limited use.
*/
#if 0
/* Pretend we have an old Linux kernel. */
#undef IFA_F_MANAGETEMPADDR
/* Enable dhcpcd handling temporary addresses. */
#define IPV6_MANAGETEMPADDR
#endif
#ifdef __linux__
/* Match Linux defines to BSD */
# define IN6_IFF_TEMPORARY IFA_F_TEMPORARY
# ifdef IFA_F_OPTIMISTIC
# define IN6_IFF_TENTATIVE (IFA_F_TENTATIVE | IFA_F_OPTIMISTIC)
# else
# define IN6_IFF_TENTATIVE (IFA_F_TENTATIVE | 0x04)
# endif
# ifdef IF_F_DADFAILED
# define IN6_IFF_DUPLICATED IFA_F_DADFAILED
# else
# define IN6_IFF_DUPLICATED 0x08
# endif
# define IN6_IFF_DETACHED 0
#endif
#ifdef __sun
/* Solaris lacks these defines.
* While it supports DaD, to seems to only expose IFF_DUPLICATE
@ -149,6 +107,38 @@
#define IN6_IFF_NOTUSEABLE \
(IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED | IN6_IFF_DETACHED)
/*
* If dhcpcd handles RA processing instead of the kernel, the kernel needs
* to either allow userland to set temporary addresses or mark an address
* for the kernel to manage temporary addresses from.
* If the kernel allows the former, a global #define is needed, otherwise
* the address marking will be handled in the platform specific address handler.
*
* Some BSDs do not allow userland to set temporary addresses.
* Linux-3.18 allows the marking of addresses from which to manage temp addrs.
*/
#if defined(IN6_IFF_TEMPORARY) && !defined(__linux__)
#define IPV6_MANAGETEMPADDR
#endif
#ifdef __linux__
/* Match Linux defines to BSD */
# ifdef IFA_F_TEMPORARY
# define IN6_IFF_TEMPORARY IFA_F_TEMPORARY
# endif
# ifdef IFA_F_OPTIMISTIC
# define IN6_IFF_TENTATIVE (IFA_F_TENTATIVE | IFA_F_OPTIMISTIC)
# else
# define IN6_IFF_TENTATIVE (IFA_F_TENTATIVE | 0x04)
# endif
# ifdef IF_F_DADFAILED
# define IN6_IFF_DUPLICATED IFA_F_DADFAILED
# else
# define IN6_IFF_DUPLICATED 0x08
# endif
# define IN6_IFF_DETACHED 0
#endif
TAILQ_HEAD(ipv6_addrhead, ipv6_addr);
struct ipv6_addr {
TAILQ_ENTRY(ipv6_addr) next;
@ -161,10 +151,11 @@ struct ipv6_addr {
struct timespec acquired;
struct in6_addr addr;
int addr_flags;
short flags;
unsigned int flags;
char saddr[INET6_ADDRSTRLEN];
uint8_t iaid[4];
uint16_t ia_type;
int dhcp6_fd;
#ifndef SMALL
struct ipv6_addr *delegating_prefix;
@ -177,30 +168,29 @@ struct ipv6_addr {
void (*dadcallback)(void *);
int dadcounter;
uint8_t *ns;
size_t nslen;
int nsprobes;
#ifdef ALIAS_ADDR
char alias[IF_NAMESIZE];
#endif
};
#define IPV6_AF_ONLINK 0x0001
#define IPV6_AF_NEW 0x0002
#define IPV6_AF_STALE 0x0004
#define IPV6_AF_ADDED 0x0008
#define IPV6_AF_AUTOCONF 0x0010
#define IPV6_AF_DUPLICATED 0x0020
#define IPV6_AF_DADCOMPLETED 0x0040
#define IPV6_AF_DELEGATED 0x0080
#define IPV6_AF_DELEGATEDPFX 0x0100
#define IPV6_AF_NOREJECT 0x0200
#define IPV6_AF_REQUEST 0x0400
#define IPV6_AF_STATIC 0x0800
#define IPV6_AF_DELEGATEDLOG 0x1000
#define IPV6_AF_ONLINK (1U << 0)
#define IPV6_AF_NEW (1U << 1)
#define IPV6_AF_STALE (1U << 2)
#define IPV6_AF_ADDED (1U << 3)
#define IPV6_AF_AUTOCONF (1U << 4)
#define IPV6_AF_DUPLICATED (1U << 5)
#define IPV6_AF_DADCOMPLETED (1U << 6)
#define IPV6_AF_DELEGATED (1U << 7)
#define IPV6_AF_DELEGATEDPFX (1U << 8)
#define IPV6_AF_NOREJECT (1U << 9)
#define IPV6_AF_REQUEST (1U << 10)
#define IPV6_AF_STATIC (1U << 11)
#define IPV6_AF_DELEGATEDLOG (1U << 12)
#define IPV6_AF_RAPFX (1U << 13)
#define IPV6_AF_EXTENDED (1U << 14)
#ifdef IPV6_MANAGETEMPADDR
#define IPV6_AF_TEMPORARY 0X2000
#define IPV6_AF_TEMPORARY (1U << 15)
#endif
struct ll_callback {
@ -236,7 +226,6 @@ int ipv6_makestableprivate(struct in6_addr *addr,
const struct interface *ifp, int *dad_counter);
int ipv6_makeaddr(struct in6_addr *, struct interface *,
const struct in6_addr *, int);
int ipv6_makeprefix(struct in6_addr *, const struct in6_addr *, int);
int ipv6_mask(struct in6_addr *, int);
uint8_t ipv6_prefixlen(const struct in6_addr *);
int ipv6_userprefix( const struct in6_addr *, short prefix_len,
@ -244,6 +233,7 @@ int ipv6_userprefix( const struct in6_addr *, short prefix_len,
void ipv6_checkaddrflags(void *);
int ipv6_addaddr(struct ipv6_addr *, const struct timespec *);
ssize_t ipv6_addaddrs(struct ipv6_addrhead *addrs);
void ipv6_deleteaddr(struct ipv6_addr *);
void ipv6_freedrop_addrs(struct ipv6_addrhead *, int,
const struct interface *);
void ipv6_handleifa(struct dhcpcd_ctx *ctx, int, struct if_head *,
@ -253,13 +243,15 @@ struct ipv6_addr *ipv6_iffindaddr(struct interface *,
const struct in6_addr *, int);
int ipv6_hasaddr(const struct interface *);
int ipv6_findaddrmatch(const struct ipv6_addr *, const struct in6_addr *,
short);
unsigned int);
struct ipv6_addr *ipv6_findaddr(struct dhcpcd_ctx *,
const struct in6_addr *, short);
const struct in6_addr *, unsigned int);
struct ipv6_addr *ipv6_findmaskaddr(struct dhcpcd_ctx *,
const struct in6_addr *);
#define ipv6_linklocal(ifp) ipv6_iffindaddr((ifp), NULL, IN6_IFF_NOTUSEABLE)
int ipv6_addlinklocalcallback(struct interface *, void (*)(void *), void *);
struct ipv6_addr *ipv6_newaddr(struct interface *, struct in6_addr *, uint8_t,
unsigned int);
void ipv6_freeaddr(struct ipv6_addr *);
void ipv6_freedrop(struct interface *, int);
#define ipv6_free(ifp) ipv6_freedrop((ifp), 0)
@ -285,7 +277,6 @@ void ipv6_ctxfree(struct dhcpcd_ctx *);
bool inet6_getroutes(struct dhcpcd_ctx *, struct rt_head *);
#else
#define ipv6_init(a) (NULL)
#define ipv6_start(a) (-1)
#define ipv6_startstatic(a)
#define ipv6_staticdadcompleted(a) (0)

View File

@ -237,23 +237,29 @@ ipv6nd_makersprobe(struct interface *ifp)
{
struct rs_state *state;
struct nd_router_solicit *rs;
struct nd_opt_hdr *nd;
state = RS_STATE(ifp);
free(state->rs);
state->rslen = sizeof(*rs) + (size_t)ROUNDUP8(ifp->hwlen + 2);
state->rslen = sizeof(*rs);
if (ifp->hwlen != 0)
state->rslen += (size_t)ROUNDUP8(ifp->hwlen + 2);
state->rs = calloc(1, state->rslen);
if (state->rs == NULL)
return -1;
rs = (void *)state->rs;
rs = state->rs;
rs->nd_rs_type = ND_ROUTER_SOLICIT;
rs->nd_rs_code = 0;
rs->nd_rs_cksum = 0;
rs->nd_rs_reserved = 0;
nd = (struct nd_opt_hdr *)(state->rs + sizeof(*rs));
nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
nd->nd_opt_len = (uint8_t)((ROUNDUP8(ifp->hwlen + 2)) >> 3);
memcpy(nd + 1, ifp->hwaddr, ifp->hwlen);
//rs->nd_rs_code = 0;
//rs->nd_rs_cksum = 0;
//rs->nd_rs_reserved = 0;
if (ifp->hwlen != 0) {
struct nd_opt_hdr *nd;
nd = (struct nd_opt_hdr *)(state->rs + 1);
nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
nd->nd_opt_len = (uint8_t)((ROUNDUP8(ifp->hwlen + 2)) >> 3);
memcpy(nd + 1, ifp->hwaddr, ifp->hwlen);
}
return 0;
}
@ -398,7 +404,7 @@ 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)
unsigned int flags)
{
struct ra *rap;
struct ipv6_addr *ap;
@ -419,7 +425,7 @@ ipv6nd_iffindaddr(const struct interface *ifp, const struct in6_addr *addr,
struct ipv6_addr *
ipv6nd_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr,
short flags)
unsigned int flags)
{
struct ra *rap;
struct ipv6_addr *ap;
@ -612,7 +618,7 @@ ipv6nd_dadcompleted(const struct interface *ifp)
static void
ipv6nd_dadcallback(void *arg)
{
struct ipv6_addr *ap = arg, *rapap;
struct ipv6_addr *ia = arg, *rapap;
struct interface *ifp;
struct ra *rap;
int wascompleted, found;
@ -621,54 +627,54 @@ ipv6nd_dadcallback(void *arg)
const char *p;
int dadcounter;
ifp = ap->iface;
wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED);
ap->flags |= IPV6_AF_DADCOMPLETED;
if (ap->flags & IPV6_AF_DUPLICATED) {
ap->dadcounter++;
logwarnx("%s: DAD detected %s", ifp->name, ap->saddr);
ifp = ia->iface;
wascompleted = (ia->flags & IPV6_AF_DADCOMPLETED);
ia->flags |= IPV6_AF_DADCOMPLETED;
if (ia->flags & IPV6_AF_DUPLICATED) {
ia->dadcounter++;
logwarnx("%s: DAD detected %s", ifp->name, ia->saddr);
/* Try and make another stable private address.
* Because ap->dadcounter is always increamented,
* a different address is generated. */
/* XXX Cache DAD counter per prefix/id/ssid? */
if (ifp->options->options & DHCPCD_SLAACPRIVATE) {
if (ap->dadcounter >= IDGEN_RETRIES) {
if (ia->dadcounter >= IDGEN_RETRIES) {
logerrx("%s: unable to obtain a"
" stable private address",
ifp->name);
goto try_script;
}
loginfox("%s: deleting address %s",
ifp->name, ap->saddr);
if (if_address6(RTM_DELADDR, ap) == -1 &&
ifp->name, ia->saddr);
if (if_address6(RTM_DELADDR, ia) == -1 &&
errno != EADDRNOTAVAIL && errno != ENXIO)
logerr(__func__);
dadcounter = ap->dadcounter;
if (ipv6_makestableprivate(&ap->addr,
&ap->prefix, ap->prefix_len,
dadcounter = ia->dadcounter;
if (ipv6_makestableprivate(&ia->addr,
&ia->prefix, ia->prefix_len,
ifp, &dadcounter) == -1)
{
logerr("ipv6_makestableprivate");
return;
}
ap->dadcounter = dadcounter;
ap->flags &= ~(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED);
ap->flags |= IPV6_AF_NEW;
p = inet_ntop(AF_INET6, &ap->addr, buf, sizeof(buf));
ia->dadcounter = dadcounter;
ia->flags &= ~(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED);
ia->flags |= IPV6_AF_NEW;
p = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf));
if (p)
snprintf(ap->saddr,
sizeof(ap->saddr),
snprintf(ia->saddr,
sizeof(ia->saddr),
"%s/%d",
p, ap->prefix_len);
p, ia->prefix_len);
else
ap->saddr[0] = '\0';
ia->saddr[0] = '\0';
tv.tv_sec = 0;
tv.tv_nsec = (suseconds_t)
arc4random_uniform(IDGEN_DELAY * NSEC_PER_SEC);
timespecnorm(&tv);
eloop_timeout_add_tv(ifp->ctx->eloop, &tv,
ipv6nd_addaddr, ap);
ipv6nd_addaddr, ia);
return;
}
}
@ -688,7 +694,7 @@ try_script:
wascompleted = 0;
break;
}
if (rapap == ap)
if (rapap == ia)
found = 1;
}
@ -727,8 +733,6 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
struct nd_opt_mtu mtu;
struct nd_opt_rdnss rdnss;
uint8_t *p;
char buf[INET6_ADDRSTRLEN];
const char *cbp;
struct ra *rap;
struct in6_addr pi_prefix;
struct ipv6_addr *ap;
@ -937,48 +941,26 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
IN6_ARE_ADDR_EQUAL(&ap->prefix, &pi_prefix))
break;
if (ap == NULL) {
unsigned int flags;
if (!(pi.nd_opt_pi_flags_reserved &
ND_OPT_PI_FLAG_AUTO) &&
!(pi.nd_opt_pi_flags_reserved &
ND_OPT_PI_FLAG_ONLINK))
continue;
ap = calloc(1, sizeof(*ap));
if (ap == NULL) {
logerr(__func__);
break;
}
ap->iface = rap->iface;
ap->flags = IPV6_AF_NEW;
ap->prefix_len = pi.nd_opt_pi_prefix_len;
ap->prefix = pi_prefix;
flags = IPV6_AF_RAPFX;
if (pi.nd_opt_pi_flags_reserved &
ND_OPT_PI_FLAG_AUTO &&
ap->iface->options->options &
rap->iface->options->options &
DHCPCD_IPV6RA_AUTOCONF)
{
ap->flags |= IPV6_AF_AUTOCONF;
ap->dadcounter =
ipv6_makeaddr(&ap->addr, ifp,
&ap->prefix,
pi.nd_opt_pi_prefix_len);
if (ap->dadcounter == -1) {
free(ap);
break;
}
cbp = inet_ntop(AF_INET6,
&ap->addr,
buf, sizeof(buf));
if (cbp)
snprintf(ap->saddr,
sizeof(ap->saddr),
"%s/%d",
cbp, ap->prefix_len);
else
ap->saddr[0] = '\0';
} else {
memset(&ap->addr, 0, sizeof(ap->addr));
ap->saddr[0] = '\0';
}
flags |= IPV6_AF_AUTOCONF;
ap = ipv6_newaddr(rap->iface,
&pi_prefix, pi.nd_opt_pi_prefix_len, flags);
if (ap == NULL)
break;
ap->prefix = pi_prefix;
ap->dadcallback = ipv6nd_dadcallback;
ap->created = ap->acquired = rap->acquired;
TAILQ_INSERT_TAIL(&rap->addrs, ap, next);
@ -1010,7 +992,6 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
ntohl(pi.nd_opt_pi_valid_time);
ap->prefix_pltime =
ntohl(pi.nd_opt_pi_preferred_time);
ap->nsprobes = 0;
#ifdef IPV6_MANAGETEMPADDR
/* RFC4941 Section 3.3.3 */

View File

@ -55,18 +55,20 @@ struct ra {
TAILQ_HEAD(ra_head, ra);
struct rs_state {
unsigned char *rs;
struct nd_router_solicit *rs;
size_t rslen;
int rsprobes;
};
#define RS_STATE(a) ((struct rs_state *)(ifp)->if_data[IF_DATA_IPV6ND])
#define RS_STATE_RUNNING(a) (ipv6nd_hasra((a)) && ipv6nd_dadcompleted((a)))
#define RS_STATE(a) ((struct rs_state *)(ifp)->if_data[IF_DATA_IPV6ND])
#define RS_STATE_RUNNING(a) (ipv6nd_hasra((a)) && ipv6nd_dadcompleted((a)))
#define MAX_RTR_SOLICITATION_DELAY 1 /* seconds */
#define MAX_UNICAST_SOLICIT 3 /* 3 transmissions */
#define RTR_SOLICITATION_INTERVAL 4 /* seconds */
#define MAX_RTR_SOLICITATIONS 3 /* times */
#ifndef MAX_RTR_SOLICITATION_DELAY
#define MAX_RTR_SOLICITATION_DELAY 1 /* seconds */
#define MAX_UNICAST_SOLICIT 3 /* 3 transmissions */
#define RTR_SOLICITATION_INTERVAL 4 /* seconds */
#define MAX_RTR_SOLICITATIONS 3 /* times */
#endif
/* On carrier up, expire known routers after RTR_CARRIER_EXPIRE seconds. */
#define RTR_CARRIER_EXPIRE \
@ -74,13 +76,13 @@ struct rs_state {
(MAX_RTR_SOLICITATIONS + 1) * \
RTR_SOLICITATION_INTERVAL)
#define MAX_REACHABLE_TIME 3600000 /* milliseconds */
#define REACHABLE_TIME 30000 /* milliseconds */
#define RETRANS_TIMER 1000 /* milliseconds */
#define DELAY_FIRST_PROBE_TIME 5 /* seconds */
#define MAX_REACHABLE_TIME 3600000 /* milliseconds */
#define REACHABLE_TIME 30000 /* milliseconds */
#define RETRANS_TIMER 1000 /* milliseconds */
#define DELAY_FIRST_PROBE_TIME 5 /* seconds */
#define IPV6ND_REACHABLE (1 << 0)
#define IPV6ND_ROUTER (1 << 1)
#define IPV6ND_REACHABLE (1 << 0)
#define IPV6ND_ROUTER (1 << 1)
#ifdef INET6
void ipv6nd_printoptions(const struct dhcpcd_ctx *,
@ -88,9 +90,9 @@ void ipv6nd_printoptions(const struct dhcpcd_ctx *,
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);
const struct in6_addr *addr, unsigned int flags);
struct ipv6_addr *ipv6nd_findaddr(struct dhcpcd_ctx *,
const struct in6_addr *, short);
const struct in6_addr *, unsigned int);
void ipv6nd_freedrop_ra(struct ra *, int);
#define ipv6nd_free_ra(ra) ipv6nd_freedrop_ra((ra), 0)
#define ipv6nd_drop_ra(ra) ipv6nd_freedrop_ra((ra), 1)

View File

@ -197,18 +197,18 @@ sa_toprefix(const struct sockaddr *sa)
case AF_INET:
{
const struct sockaddr_in *sin;
int mask;
uint32_t mask;
sin = satocsin(sa);
if (sin->sin_addr.s_addr == INADDR_ANY) {
prefix = 0;
break;
}
mask = (int)ntohl(sin->sin_addr.s_addr);
prefix = 33 - ffs(mask); /* 33 - (1 .. 32) -> 32 .. 1 */
mask = ntohl(sin->sin_addr.s_addr);
prefix = 33 - ffs((int)mask); /* 33 - (1 .. 32) -> 32 .. 1 */
if (prefix < 32) { /* more than 1 bit in mask */
/* check for non-contig netmask */
if ((mask ^ (((1 << prefix)-1) << (32 - prefix))) != 0){
if ((mask^(((1U << prefix)-1) << (32 - prefix))) != 0) {
errno = EINVAL;
return -1; /* noncontig, no pfxlen */
}