Import dhcpcd-7.2.1 with the following changes:

*  auth: Use consttime_memequal to avoid latency attack
*  DHCP: Fix a potential 1 byte read overflow with DHO_OPTSOVERLOADED
*  DHCPv6: Fix a potential buffer overflow reading NA/TA addresses
This commit is contained in:
roy 2019-04-26 14:32:27 +00:00
parent 583ae9ed45
commit cdfaff8fa4
13 changed files with 249 additions and 116 deletions

View File

@ -0,0 +1,28 @@
/*
* Written by Matthias Drochner <drochner@NetBSD.org>.
* Public domain.
*/
#ifndef CONSTTIME_MEMEQUAL_H
#define CONSTTIME_MEMEQUAL_H
inline static int
consttime_memequal(const void *b1, const void *b2, size_t len)
{
const unsigned char *c1 = b1, *c2 = b2;
unsigned int res = 0;
while (len--)
res |= *c1++ ^ *c2++;
/*
* Map 0 to 1 and [1, 256) to 0 using only constant-time
* arithmetic.
*
* This is not simply `!res' because although many CPUs support
* branchless conditional moves and many compilers will take
* advantage of them, certain compilers generate branches on
* certain CPUs for `!res'.
*/
return (1 & ((res - 1) >> 8));
}
#endif /* CONSTTIME_MEMEQUAL_H */

View File

@ -13,6 +13,7 @@ IPV4LL=
INET6= INET6=
ARC4RANDOM= ARC4RANDOM=
CLOSEFROM= CLOSEFROM=
CONSTTIME_MEMEQUAL=
STRLCPY= STRLCPY=
UDEV= UDEV=
OS= OS=
@ -846,6 +847,27 @@ if [ "$STRTOI" = no ]; then
echo "#include \"compat/strtoi.h\"" >>$CONFIG_H echo "#include \"compat/strtoi.h\"" >>$CONFIG_H
fi fi
if [ -z "$CONSTTIME_MEMEQUAL" ]; then
printf "Testing for consttime_memequal ... "
cat <<EOF >_consttime_memequal.c
#include <string.h>
int main(void) {
return consttime_memequal("deadbeef", "deadbeef", 8);
}
EOF
if $XCC _consttime_memequal.c -o _consttime_memequal 2>&3; then
CONSTTIME_MEMEQUAL=yes
else
CONSTTIME_MEMEQUAL=no
fi
echo "$CONSTTIME_MEMEQUAL"
rm -f _consttime_memequal.c _consttime_memequal
fi
if [ "$CONSTTIME_MEMEQUAL" = no ]; then
echo "#include \"compat/consttime_memequal.h\"" \
>>$CONFIG_H
fi
if [ -z "$DPRINTF" ]; then if [ -z "$DPRINTF" ]; then
printf "Testing for dprintf ... " printf "Testing for dprintf ... "
cat <<EOF >_dprintf.c cat <<EOF >_dprintf.c

View File

@ -117,7 +117,11 @@ dhcp_auth_validate(struct authstate *state, const struct auth *auth,
m = vm; m = vm;
data = vdata; data = vdata;
/* Ensure that d is inside m which *may* not be the case for DHPCPv4 */ /* Ensure that d is inside m which *may* not be the case for DHCPv4.
* This can occur if the authentication option is split using
* DHCP long option from RFC 3399. Section 9 which does infact note that
* implementations should take this into account.
* Fixing this would be problematic, patches welcome. */
if (data < m || data > m + mlen || data + dlen > m + mlen) { if (data < m || data > m + mlen || data + dlen > m + mlen) {
errno = ERANGE; errno = ERANGE;
return NULL; return NULL;
@ -354,7 +358,7 @@ gottoken:
} }
free(mm); free(mm);
if (memcmp(d, &hmac_code, dlen)) { if (!consttime_memequal(d, &hmac_code, dlen)) {
errno = EPERM; errno = EPERM;
return NULL; return NULL;
} }

View File

@ -318,7 +318,7 @@ control_open(const char *ifname)
if ((fd = make_sock(&sa, ifname, 0)) != -1) { if ((fd = make_sock(&sa, ifname, 0)) != -1) {
socklen_t len; socklen_t len;
len = (socklen_t)SUN_LEN(&sa); len = (socklen_t)SUN_LEN(&sa);
if (connect(fd, (struct sockaddr *)&sa, len) == -1) { if (connect(fd, (struct sockaddr *)&sa, len) == -1) {
close(fd); close(fd);

View File

@ -28,7 +28,7 @@
#define CONFIG_H #define CONFIG_H
#define PACKAGE "dhcpcd" #define PACKAGE "dhcpcd"
#define VERSION "7.2.0" #define VERSION "7.2.1"
#ifndef CONFIG #ifndef CONFIG
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf" # define CONFIG SYSCONFDIR "/" PACKAGE ".conf"

View File

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.Dd September 15, 2018 .Dd April 24, 2019
.Dt DHCPCD.CONF 5 .Dt DHCPCD.CONF 5
.Os .Os
.Sh NAME .Sh NAME
@ -376,8 +376,7 @@ IPv6 address configuration for the internal network.
noipv6rs # disable routing solicitation noipv6rs # disable routing solicitation
denyinterfaces eth2 # Don't touch eth2 at all denyinterfaces eth2 # Don't touch eth2 at all
interface eth0 interface eth0
ipv6rs # enable routing solicitation get the ipv6rs # enable routing solicitation for eth0
# default IPv6 route
ia_na 1 # request an IPv6 address ia_na 1 # request an IPv6 address
ia_pd 2 eth1/0 # request a PD and assign it to eth1 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 ia_pd 3 eth2/1 eth3/2 # req a PD and assign it to eth2 and eth3

View File

@ -180,7 +180,9 @@ struct dhcpcd_ctx {
uint8_t *secret; uint8_t *secret;
size_t secret_len; size_t secret_len;
#ifndef __sun
int nd_fd; int nd_fd;
#endif
struct ra_head *ra_routers; struct ra_head *ra_routers;
int dhcp6_fd; int dhcp6_fd;

View File

@ -74,9 +74,9 @@ extern int getallifaddrs(sa_family_t, struct ifaddrs **, int64_t);
#endif #endif
#ifndef RT_ROUNDUP #ifndef RT_ROUNDUP
#define RT_ROUNDUP(a) \ #define RT_ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(int32_t) - 1))) : sizeof(int32_t))
#define RT_ADVANCE(x, n) (x += RT_ROUNDUP(salen(n))) #define RT_ADVANCE(x, n) ((x) += RT_ROUNDUP(salen((n))))
#endif #endif
#define COPYOUT(sin, sa) do { \ #define COPYOUT(sin, sa) do { \
@ -268,6 +268,7 @@ static boolean_t
if_newaddr(const char *ifname, void *arg) if_newaddr(const char *ifname, void *arg)
{ {
struct linkwalk *lw = arg; struct linkwalk *lw = arg;
int error;
struct ifaddrs *ifa; struct ifaddrs *ifa;
dlpi_handle_t dh; dlpi_handle_t dh;
dlpi_info_t dlinfo; dlpi_info_t dlinfo;
@ -276,7 +277,10 @@ if_newaddr(const char *ifname, void *arg)
struct sockaddr_dl *sdl; struct sockaddr_dl *sdl;
ifa = NULL; ifa = NULL;
if (dlpi_open(ifname, &dh, 0) != DLPI_SUCCESS) error = dlpi_open(ifname, &dh, 0);
if (error == DLPI_ENOLINK) /* Just vanished or in global zone */
return B_FALSE;
if (error != DLPI_SUCCESS)
goto failed1; goto failed1;
if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS)
goto failed; goto failed;
@ -317,7 +321,7 @@ if_newaddr(const char *ifname, void *arg)
ifa->ifa_next = lw->lw_ifa; ifa->ifa_next = lw->lw_ifa;
lw->lw_ifa = ifa; lw->lw_ifa = ifa;
dlpi_close(dh); dlpi_close(dh);
return (B_FALSE); return B_FALSE;
failed: failed:
dlpi_close(dh); dlpi_close(dh);
@ -328,7 +332,7 @@ failed:
} }
failed1: failed1:
lw->lw_error = errno; lw->lw_error = errno;
return (B_TRUE); return B_TRUE;
} }
/* Creates an empty sockaddr_dl for lo0. */ /* Creates an empty sockaddr_dl for lo0. */
@ -423,14 +427,16 @@ get_addrs(int type, const void *data, const struct sockaddr **sa)
{ {
const char *cp; const char *cp;
int i; int i;
const struct sockaddr **sap;
cp = data; cp = data;
for (i = 0; i < RTAX_MAX; i++) { for (i = 0; i < RTAX_MAX; i++) {
sap = &sa[i];
if (type & (1 << i)) { if (type & (1 << i)) {
sa[i] = (const struct sockaddr *)cp; *sap = (const struct sockaddr *)cp;
RT_ADVANCE(cp, sa[i]); RT_ADVANCE(cp, *sap);
} else } else
sa[i] = NULL; *sap = NULL;
} }
return 0; return 0;
} }
@ -520,6 +526,7 @@ if_route0(struct dhcpcd_ctx *ctx, struct rtm *rtmsg,
struct rt_msghdr *rtm; struct rt_msghdr *rtm;
char *bp = rtmsg->buffer; char *bp = rtmsg->buffer;
socklen_t sl; socklen_t sl;
bool gateway_unspec;
/* WARNING: Solaris will not allow you to delete RTF_KERNEL routes. /* WARNING: Solaris will not allow you to delete RTF_KERNEL routes.
* This includes subnet/prefix routes. */ * This includes subnet/prefix routes. */
@ -538,25 +545,28 @@ if_route0(struct dhcpcd_ctx *ctx, struct rtm *rtmsg,
rtm->rtm_flags = rt->rt_flags; rtm->rtm_flags = rt->rt_flags;
rtm->rtm_addrs = RTA_DST | RTA_GATEWAY; rtm->rtm_addrs = RTA_DST | RTA_GATEWAY;
gateway_unspec = sa_is_unspecified(&rt->rt_gateway);
if (cmd == RTM_ADD || cmd == RTM_CHANGE) { if (cmd == RTM_ADD || cmd == RTM_CHANGE) {
bool netmask_bcast = sa_is_allones(&rt->rt_netmask); bool netmask_bcast = sa_is_allones(&rt->rt_netmask);
rtm->rtm_flags |= RTF_UP; rtm->rtm_flags |= RTF_UP;
if (!(rtm->rtm_flags & RTF_REJECT) && if (!(rtm->rtm_flags & RTF_REJECT) &&
!sa_is_loopback(&rt->rt_gateway) && !sa_is_loopback(&rt->rt_gateway))
/* Solaris doesn't like interfaces on default routes. */
!sa_is_unspecified(&rt->rt_dest))
{ {
rtm->rtm_addrs |= RTA_IFP; rtm->rtm_addrs |= RTA_IFP;
#if 0 /* RTA_IFA is currently ignored by the kernel.
* RTA_SRC and RTF_SETSRC look like what we want,
* but they don't work with RTF_GATEWAY.
* We set RTA_IFA just in the hope that the
* kernel will one day support this. */
if (!sa_is_unspecified(&rt->rt_ifa)) if (!sa_is_unspecified(&rt->rt_ifa))
rtm->rtm_addrs |= RTA_IFA; rtm->rtm_addrs |= RTA_IFA;
#endif
} }
if (netmask_bcast) if (netmask_bcast)
rtm->rtm_flags |= RTF_HOST; rtm->rtm_flags |= RTF_HOST;
else else if (!gateway_unspec)
rtm->rtm_flags |= RTF_GATEWAY; rtm->rtm_flags |= RTF_GATEWAY;
/* Emulate the kernel by marking address generated /* Emulate the kernel by marking address generated
@ -575,7 +585,7 @@ if_route0(struct dhcpcd_ctx *ctx, struct rtm *rtmsg,
ADDSA(&rt->rt_dest); ADDSA(&rt->rt_dest);
if (sa_is_unspecified(&rt->rt_gateway)) if (gateway_unspec)
ADDSA(&rt->rt_ifa); ADDSA(&rt->rt_ifa);
else else
ADDSA(&rt->rt_gateway); ADDSA(&rt->rt_gateway);
@ -590,14 +600,13 @@ if_route0(struct dhcpcd_ctx *ctx, struct rtm *rtmsg,
ADDSA((struct sockaddr *)&sdl); ADDSA((struct sockaddr *)&sdl);
} }
if (rtm->rtm_addrs & RTA_IFA) { if (rtm->rtm_addrs & RTA_IFA)
ADDSA(&rt->rt_ifa);
rtm->rtm_addrs |= RTA_SRC;
}
if (rtm->rtm_addrs & RTA_SRC)
ADDSA(&rt->rt_ifa); ADDSA(&rt->rt_ifa);
#undef ADDSA #if 0
if (rtm->rtm_addrs & RTA_SRC)
ADDSA(&rt->rt_ifa);
#endif
rtm->rtm_msglen = (unsigned short)(bp - (char *)rtm); rtm->rtm_msglen = (unsigned short)(bp - (char *)rtm);
} }
@ -747,15 +756,19 @@ if_finishrt(struct dhcpcd_ctx *ctx, struct rt *rt)
rt->rt_mtu = 0; rt->rt_mtu = 0;
} }
static int static uint64_t
if_addrflags0(int fd, const char *ifname) if_addrflags0(int fd, const char *ifname, const struct sockaddr *sa)
{ {
struct lifreq lifr; struct lifreq lifr;
memset(&lifr, 0, sizeof(lifr)); memset(&lifr, 0, sizeof(lifr));
strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name)); strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1)
return -1; return 0;
if (ioctl(fd, SIOCGLIFADDR, &lifr) == -1)
return 0;
if (sa_cmp(sa, (struct sockaddr *)&lifr.lifr_addr) != 0)
return 0;
return lifr.lifr_flags; return lifr.lifr_flags;
} }
@ -804,13 +817,56 @@ if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
} }
} }
static bool
if_getalias(struct interface *ifp, const struct sockaddr *sa, char *alias)
{
struct ifaddrs *ifaddrs, *ifa;
struct interface *ifpx;
bool found;
ifaddrs = NULL;
if (getallifaddrs(sa->sa_family, &ifaddrs, 0) == -1)
return false;
found = false;
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
if (sa_cmp(sa, ifa->ifa_addr) != 0)
continue;
/* Check it's for the right interace. */
ifpx = if_find(ifp->ctx->ifaces, ifa->ifa_name);
if (ifp == ifpx) {
strlcpy(alias, ifa->ifa_name, IF_NAMESIZE);
found = true;
break;
}
}
freeifaddrs(ifaddrs);
return found;
}
static int
if_getbrdaddr(struct dhcpcd_ctx *ctx, const char *ifname, struct in_addr *brd)
{
struct lifreq lifr = { 0 };
int r;
memset(&lifr, 0, sizeof(lifr));
strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
errno = 0;
r = ioctl(ctx->pf_inet_fd, SIOCGLIFBRDADDR, &lifr, sizeof(lifr));
if (r != -1)
COPYOUT(*brd, (struct sockaddr *)&lifr.lifr_broadaddr);
return r;
}
static void static void
if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam) if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam)
{ {
struct interface *ifp; struct interface *ifp;
const struct sockaddr *sa, *rti_info[RTAX_MAX]; const struct sockaddr *sa, *rti_info[RTAX_MAX];
int flags; int flags;
const char *ifalias; char ifalias[IF_NAMESIZE];
/* XXX We have no way of knowing who generated these /* XXX We have no way of knowing who generated these
* messages wich truely sucks because we want to * messages wich truely sucks because we want to
@ -819,6 +875,7 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam)
return; return;
sa = (const void *)(ifam + 1); sa = (const void *)(ifam + 1);
get_addrs(ifam->ifam_addrs, sa, rti_info); get_addrs(ifam->ifam_addrs, sa, rti_info);
if ((sa = rti_info[RTAX_IFA]) == NULL) if ((sa = rti_info[RTAX_IFA]) == NULL)
return; return;
@ -835,31 +892,8 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam)
* ifam_alias * ifam_alias
* ifam_pid * ifam_pid
*/ */
if (ifam->ifam_type != RTM_DELADDR && !if_getalias(ifp, sa, ifalias))
ifalias = ifp->name; return;
if (ifam->ifam_type != RTM_DELADDR && sa->sa_family != AF_LINK) {
struct ifaddrs *ifaddrs, *ifa;
ifaddrs = NULL;
if (getallifaddrs(sa->sa_family, &ifaddrs, 0) == -1)
return;
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr != NULL) {
if (sa_cmp(sa, ifa->ifa_addr) == 0) {
/* Check it's for the right interace. */
struct interface *ifpx;
ifpx = if_find(ctx->ifaces,
ifa->ifa_name);
if (ifp == ifpx) {
ifalias = ifa->ifa_name;
break;
}
}
}
}
freeifaddrs(ifaddrs);
}
switch (sa->sa_family) { switch (sa->sa_family) {
case AF_LINK: case AF_LINK:
@ -882,12 +916,25 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam)
COPYOUT(mask, rti_info[RTAX_NETMASK]); COPYOUT(mask, rti_info[RTAX_NETMASK]);
COPYOUT(bcast, rti_info[RTAX_BRD]); COPYOUT(bcast, rti_info[RTAX_BRD]);
if (ifam->ifam_type != RTM_DELADDR) { if (ifam->ifam_type == RTM_DELADDR) {
flags = if_addrflags0(ctx->pf_inet_fd, ifalias); struct ipv4_addr *ia;
if (flags == -1)
break; ia = ipv4_iffindaddr(ifp, &addr, &mask);
} else if (ia == NULL)
flags = 0; return;
strlcpy(ifalias, ia->alias, sizeof(ifalias));
} else if (bcast.s_addr == INADDR_ANY) {
/* Work around a bug where broadcast
* address is not correctly reported. */
if (if_getbrdaddr(ctx, ifalias, &bcast) == -1)
return;
}
flags = if_addrflags(ifp, &addr, ifalias);
if (ifam->ifam_type == RTM_DELADDR) {
if (flags != -1)
return;
} else if (flags == -1)
return;
ipv4_handleifa(ctx, ipv4_handleifa(ctx,
ifam->ifam_type == RTM_CHGADDR ? ifam->ifam_type == RTM_CHGADDR ?
@ -907,15 +954,20 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam)
sin6 = (const void *)rti_info[RTAX_NETMASK]; sin6 = (const void *)rti_info[RTAX_NETMASK];
mask6 = sin6->sin6_addr; mask6 = sin6->sin6_addr;
if (ifam->ifam_type != RTM_DELADDR) { if (ifam->ifam_type == RTM_DELADDR) {
const struct priv *priv; struct ipv6_addr *ia;
priv = (struct priv *)ctx->priv; ia = ipv6_iffindaddr(ifp, &addr6, 0);
flags = if_addrflags0(priv->pf_inet6_fd, ifalias); if (ia == NULL)
if (flags == -1) return;
break; strlcpy(ifalias, ia->alias, sizeof(ifalias));
} else }
flags = 0; flags = if_addrflags6(ifp, &addr6, ifalias);
if (ifam->ifam_type == RTM_DELADDR) {
if (flags != -1)
return;
} else if (flags == -1)
return;
ipv6_handleifa(ctx, ipv6_handleifa(ctx,
ifam->ifam_type == RTM_CHGADDR ? ifam->ifam_type == RTM_CHGADDR ?
@ -1003,7 +1055,8 @@ if_octetstr(char *buf, const Octet_t *o, ssize_t len)
static int static int
if_addaddr(int fd, const char *ifname, if_addaddr(int fd, const char *ifname,
struct sockaddr_storage *addr, struct sockaddr_storage *mask) struct sockaddr_storage *addr, struct sockaddr_storage *mask,
struct sockaddr_storage *brd)
{ {
struct lifreq lifr; struct lifreq lifr;
@ -1020,6 +1073,13 @@ if_addaddr(int fd, const char *ifname,
if (ioctl(fd, SIOCSLIFADDR, &lifr) == -1) if (ioctl(fd, SIOCSLIFADDR, &lifr) == -1)
return -1; return -1;
/* Then assign the broadcast address. */
if (brd != NULL) {
lifr.lifr_broadaddr = *brd;
if (ioctl(fd, SIOCSLIFBRDADDR, &lifr) == -1)
return -1;
}
/* Now bring it up. */ /* Now bring it up. */
if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1)
return -1; return -1;
@ -1173,15 +1233,11 @@ out:
static int static int
if_unplumbif(const struct dhcpcd_ctx *ctx, int af, const char *ifname) if_unplumbif(const struct dhcpcd_ctx *ctx, int af, const char *ifname)
{ {
struct sockaddr_storage addr, mask; struct sockaddr_storage addr = { .ss_family = af };
int fd; int fd;
/* For the time being, don't unplumb the interface, just /* For the time being, don't unplumb the interface, just
* set the address to zero. */ * set the address to zero. */
memset(&addr, 0, sizeof(addr));
addr.ss_family = af;
memset(&mask, 0, sizeof(mask));
mask.ss_family = af;
switch (af) { switch (af) {
#ifdef INET #ifdef INET
case AF_INET: case AF_INET:
@ -1202,7 +1258,8 @@ if_unplumbif(const struct dhcpcd_ctx *ctx, int af, const char *ifname)
errno = EAFNOSUPPORT; errno = EAFNOSUPPORT;
return -1; return -1;
} }
return if_addaddr(fd, ifname, &addr, &mask); return if_addaddr(fd, ifname, &addr, &addr,
af == AF_INET ? &addr : NULL);
} }
static int static int
@ -1306,6 +1363,7 @@ if_walkrt6(struct dhcpcd_ctx *ctx, char *data, size_t len)
ipv6_mask(&in6, re->ipv6RoutePfxLength); ipv6_mask(&in6, re->ipv6RoutePfxLength);
sa_in6_init(&rt.rt_netmask, &in6); sa_in6_init(&rt.rt_netmask, &in6);
sa_in6_init(&rt.rt_gateway, &re->ipv6RouteNextHop); sa_in6_init(&rt.rt_gateway, &re->ipv6RouteNextHop);
sa_in6_init(&rt.rt_ifa, &re->ipv6RouteInfo.re_src_addr);
rt.rt_mtu = re->ipv6RouteInfo.re_max_frag; rt.rt_mtu = re->ipv6RouteInfo.re_max_frag;
if_octetstr(ifname, &re->ipv6RouteIfIndex, sizeof(ifname)); if_octetstr(ifname, &re->ipv6RouteIfIndex, sizeof(ifname));
rt.rt_ifp = if_find(ctx->ifaces, ifname); rt.rt_ifp = if_find(ctx->ifaces, ifname);
@ -1456,8 +1514,10 @@ bpf_send(const struct interface *ifp, __unused int fd, uint16_t protocol,
int int
if_address(unsigned char cmd, const struct ipv4_addr *ia) if_address(unsigned char cmd, const struct ipv4_addr *ia)
{ {
struct sockaddr_storage ss_addr, ss_mask; union {
struct sockaddr_in *sin_addr, *sin_mask; struct sockaddr sa;
struct sockaddr_storage ss;
} addr, mask, brd;
/* Either remove the alias or ensure it exists. */ /* Either remove the alias or ensure it exists. */
if (if_plumb(cmd, ia->iface->ctx, AF_INET, ia->alias) == -1) if (if_plumb(cmd, ia->iface->ctx, AF_INET, ia->alias) == -1)
@ -1474,24 +1534,24 @@ if_address(unsigned char cmd, const struct ipv4_addr *ia)
/* We need to update the index now */ /* We need to update the index now */
ia->iface->index = if_nametoindex(ia->alias); ia->iface->index = if_nametoindex(ia->alias);
sin_addr = (struct sockaddr_in *)&ss_addr; sa_in_init(&addr.sa, &ia->addr);
sin_addr->sin_family = AF_INET; sa_in_init(&mask.sa, &ia->mask);
sin_addr->sin_addr = ia->addr; sa_in_init(&brd.sa, &ia->brd);
sin_mask = (struct sockaddr_in *)&ss_mask; return if_addaddr(ia->iface->ctx->pf_inet_fd, ia->alias,
sin_mask->sin_family = AF_INET; &addr.ss, &mask.ss, &brd.ss);
sin_mask->sin_addr = ia->mask;
return if_addaddr(ia->iface->ctx->pf_inet_fd,
ia->alias, &ss_addr, &ss_mask);
} }
int int
if_addrflags(const struct interface *ifp, __unused const struct in_addr *addr, if_addrflags(const struct interface *ifp, const struct in_addr *addr,
const char *alias) const char *alias)
{ {
int flags, aflags; union sa_ss ss;
uint64_t aflags;
int flags;
aflags = if_addrflags0(ifp->ctx->pf_inet_fd, alias); sa_in_init(&ss.sa, addr);
if (aflags == -1) aflags = if_addrflags0(ifp->ctx->pf_inet_fd, alias, &ss.sa);
if (aflags == 0)
return -1; return -1;
flags = 0; flags = 0;
if (aflags & IFF_DUPLICATE) if (aflags & IFF_DUPLICATE)
@ -1505,9 +1565,12 @@ if_addrflags(const struct interface *ifp, __unused const struct in_addr *addr,
int int
if_address6(unsigned char cmd, const struct ipv6_addr *ia) if_address6(unsigned char cmd, const struct ipv6_addr *ia)
{ {
struct sockaddr_storage ss_addr, ss_mask; union {
struct sockaddr_in6 *sin6_addr, *sin6_mask; struct sockaddr sa;
struct priv *priv; struct sockaddr_in6 sin6;
struct sockaddr_storage ss;
} addr, mask;
const struct priv *priv;
int r; int r;
/* Either remove the alias or ensure it exists. */ /* Either remove the alias or ensure it exists. */
@ -1522,29 +1585,30 @@ if_address6(unsigned char cmd, const struct ipv6_addr *ia)
return -1; return -1;
} }
priv = (struct priv *)ia->iface->ctx->priv; sa_in6_init(&addr.sa, &ia->addr);
sin6_addr = (struct sockaddr_in6 *)&ss_addr; mask.sin6.sin6_family = AF_INET6;
sin6_addr->sin6_family = AF_INET6; ipv6_mask(&mask.sin6.sin6_addr, ia->prefix_len);
sin6_addr->sin6_addr = ia->addr; priv = (const struct priv *)ia->iface->ctx->priv;
sin6_mask = (struct sockaddr_in6 *)&ss_mask; r = if_addaddr(priv->pf_inet6_fd, ia->alias, &addr.ss, &mask.ss, NULL);
sin6_mask->sin6_family = AF_INET6;
ipv6_mask(&sin6_mask->sin6_addr, ia->prefix_len);
r = if_addaddr(priv->pf_inet6_fd,
ia->alias, &ss_addr, &ss_mask);
if (r == -1 && errno == EEXIST) if (r == -1 && errno == EEXIST)
return 0; return 0;
return r; return r;
} }
int int
if_addrflags6(const struct interface *ifp, __unused const struct in6_addr *addr, if_addrflags6(const struct interface *ifp, const struct in6_addr *addr,
const char *alias) const char *alias)
{ {
struct priv *priv; struct priv *priv;
int aflags, flags; union sa_ss ss;
uint64_t aflags;
int flags;
priv = (struct priv *)ifp->ctx->priv; priv = (struct priv *)ifp->ctx->priv;
aflags = if_addrflags0(priv->pf_inet6_fd, alias); sa_in6_init(&ss.sa, addr);
aflags = if_addrflags0(priv->pf_inet6_fd, alias, &ss.sa);
if (aflags == 0)
return -1;
flags = 0; flags = 0;
if (aflags & IFF_DUPLICATE) if (aflags & IFF_DUPLICATE)
flags |= IN6_IFF_DUPLICATED; flags |= IN6_IFF_DUPLICATED;

View File

@ -62,9 +62,8 @@
* While it supports DaD, to seems to only expose IFF_DUPLICATE * While it supports DaD, to seems to only expose IFF_DUPLICATE
* so we have no way of knowing if it's tentative or not. * so we have no way of knowing if it's tentative or not.
* I don't even know if Solaris has any special treatment for tentative. */ * I don't even know if Solaris has any special treatment for tentative. */
# define IN_IFF_TENTATIVE 0
# define IN_IFF_DUPLICATED 0x02 # define IN_IFF_DUPLICATED 0x02
# define IN_IFF_DETACHED 0 # define IN_IFF_NOTUSEABLE IN_IFF_DUPLICATED
#endif #endif
#ifdef IN_IFF_TENTATIVE #ifdef IN_IFF_TENTATIVE

View File

@ -232,7 +232,7 @@ static void
ipv4ll_probe(void *arg) ipv4ll_probe(void *arg)
{ {
#ifdef IN_IFF_TENTATIVE #ifdef IN_IFF_DUPLICATED
ipv4ll_probed(arg); ipv4ll_probed(arg);
#else #else
arp_probe(arg); arp_probe(arg);
@ -404,7 +404,7 @@ ipv4ll_start(void *arg)
if (ia == NULL) if (ia == NULL)
ia = ipv4_iffindlladdr(ifp); ia = ipv4_iffindlladdr(ifp);
#ifdef IN_IFF_TENTATIVE #ifdef IN_IFF_DUPLICATED
if (ia != NULL && ia->addr_flags & IN_IFF_DUPLICATED) { if (ia != NULL && ia->addr_flags & IN_IFF_DUPLICATED) {
ipv4_deladdr(ia, 0); ipv4_deladdr(ia, 0);
ia = NULL; ia = NULL;
@ -419,6 +419,8 @@ ipv4ll_start(void *arg)
ifp->name, inet_ntoa(ia->addr)); ifp->name, inet_ntoa(ia->addr));
return; return;
} }
#endif
#ifdef IN_IFF_DUPLICATED
loginfox("%s: using IPv4LL address %s", ifp->name, ia->saddr); loginfox("%s: using IPv4LL address %s", ifp->name, ia->saddr);
#endif #endif
ipv4ll_probed(astate); ipv4ll_probed(astate);
@ -429,7 +431,7 @@ ipv4ll_start(void *arg)
if (state->pickedaddr.s_addr == INADDR_ANY) if (state->pickedaddr.s_addr == INADDR_ANY)
state->pickedaddr.s_addr = ipv4ll_pickaddr(astate); state->pickedaddr.s_addr = ipv4ll_pickaddr(astate);
astate->addr = state->pickedaddr; astate->addr = state->pickedaddr;
#ifdef IN_IFF_TENTATIVE #ifdef IN_IFF_DUPLICATED
ipv4ll_probed(astate); ipv4ll_probed(astate);
#else #else
arp_probe(astate); arp_probe(astate);

View File

@ -137,7 +137,9 @@ ipv6_init(struct dhcpcd_ctx *ctx)
return -1; return -1;
TAILQ_INIT(ctx->ra_routers); TAILQ_INIT(ctx->ra_routers);
#ifndef __sun
ctx->nd_fd = -1; ctx->nd_fd = -1;
#endif
ctx->dhcp6_fd = -1; ctx->dhcp6_fd = -1;
return 0; return 0;
} }

View File

@ -44,9 +44,6 @@
# endif # endif
#endif #endif
#define ALLNODES "ff02::1"
#define ALLROUTERS "ff02::2"
#define EUI64_GBIT 0x01 #define EUI64_GBIT 0x01
#define EUI64_UBIT 0x02 #define EUI64_UBIT 0x02
#define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0) #define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
@ -77,6 +74,17 @@
(((d)->s6_addr32[3] ^ (a)->s6_addr32[3]) & (m)->s6_addr32[3]) == 0 ) (((d)->s6_addr32[3] ^ (a)->s6_addr32[3]) & (m)->s6_addr32[3]) == 0 )
#endif #endif
#ifndef IN6ADDR_LINKLOCAL_ALLNODES_INIT
#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \
{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}}
#endif
#ifndef IN6ADDR_LINKLOCAL_ALLROUTERS_INIT
#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \
{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}}
#endif
/* /*
* BSD kernels don't inform userland of DAD results. * BSD kernels don't inform userland of DAD results.
* See the discussion here: * See the discussion here:

View File

@ -61,6 +61,9 @@ struct rs_state {
size_t rslen; size_t rslen;
int rsprobes; int rsprobes;
uint32_t retrans; uint32_t retrans;
#ifdef __sun
int nd_fd;
#endif
}; };
#define RS_STATE(a) ((struct rs_state *)(ifp)->if_data[IF_DATA_IPV6ND]) #define RS_STATE(a) ((struct rs_state *)(ifp)->if_data[IF_DATA_IPV6ND])