This commit is contained in:
roy 2020-04-02 12:41:47 +00:00
parent 9a245d3e64
commit 4982964f6e
16 changed files with 2221 additions and 1553 deletions

View File

@ -42,7 +42,7 @@ build_resolv_conf()
# Build the nameserver list
srvs=$(cd "$resolv_conf_dir"; \
key_get_value "nameserver " ${interfaces})
for x in $(uniqify ${srvs}); do
for x in $(uniqify $srvs); do
servers="${servers}nameserver $x$NL"
done
fi
@ -152,6 +152,7 @@ add_resolv_conf()
fi
fi
if [ -n "$new_domain_search" ]; then
new_domain_search=$(uniqify $new_domain_search)
if valid_domainname_list $new_domain_search; then
conf="${conf}search $new_domain_search$NL"
elif ! $warn; then
@ -159,6 +160,7 @@ add_resolv_conf()
"$new_domain_search"
fi
fi
new_domain_name_servers=$(uniqify $new_domain_name_servers)
for x in ${new_domain_name_servers}; do
conf="${conf}nameserver $x$NL"
done

View File

@ -1,161 +0,0 @@
# Set the hostname from DHCP data if required
# A hostname can either be a short hostname or a FQDN.
# hostname_fqdn=true
# hostname_fqdn=false
# hostname_fqdn=server
# A value of server means just what the server says, don't manipulate it.
# This could lead to an inconsistent hostname on a DHCPv4 and DHCPv6 network
# where the DHCPv4 hostname is short and the DHCPv6 has an FQDN.
# DHCPv6 has no hostname option.
# RFC4702 section 3.1 says FQDN should be prefered over hostname.
#
# As such, the default is hostname_fqdn=true so that a consistent hostname
# is always assigned.
: ${hostname_fqdn:=true}
# If we used to set the hostname, but relinquish control of it, we should
# reset to the default value.
: ${hostname_default=localhost}
# Some systems don't have hostname(1)
_hostname()
{
if [ -z "${1+x}" ]; then
if type hostname >/dev/null 2>&1; then
hostname
elif [ -r /proc/sys/kernel/hostname ]; then
read name </proc/sys/kernel/hostname && echo "$name"
elif sysctl kern.hostname >/dev/null 2>&1; then
sysctl -n kern.hostname
elif sysctl kernel.hostname >/dev/null 2>&1; then
sysctl -n kernel.hostname
else
return 1
fi
return $?
fi
# Always prefer hostname(1) if we have it
if type hostname >/dev/null 2>&1; then
hostname "$1"
elif [ -w /proc/sys/kernel/hostname ]; then
echo "$1" >/proc/sys/kernel/hostname
elif sysctl kern.hostname >/dev/null 2>&1; then
sysctl -w "kern.hostname=$1"
elif sysctl kernel.hostname >/dev/null 2>&1; then
sysctl -w "kernel.hostname=$1"
else
# We know this will fail, but it will now fail
# with an error to stdout
hostname "$1"
fi
}
set_hostname_vars()
{
hfqdn=false
hshort=false
case "$hostname_fqdn" in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|1) hfqdn=true;;
""|[Ss][Ee][Rr][Vv][Ee][Rr]) ;;
*) hshort=true;;
esac
}
need_hostname()
{
# Always load the hostname variable for future use
hostname="$(_hostname)"
case "$hostname" in
""|"(none)"|localhost|localhost.localdomain|"$hostname_default")
return 0;;
esac
case "$force_hostname" in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|1) return 0;;
esac
set_hostname_vars
if [ -n "$old_fqdn" ]; then
if ${hfqdn} || ! ${hshort}; then
[ "$hostname" = "$old_fqdn" ]
else
[ "$hostname" = "${old_fqdn%%.*}" ]
fi
elif [ -n "$old_host_name" ]; then
if ${hfqdn}; then
if [ -n "$old_domain_name" ] &&
[ "$old_host_name" = "${old_host_name#*.}" ]
then
[ "$hostname" = \
"$old_host_name.$old_domain_name" ]
else
[ "$hostname" = "$old_host_name" ]
fi
elif ${hshort}; then
[ "$hostname" = "${old_host_name%%.*}" ]
else
[ "$hostname" = "$old_host_name" ]
fi
else
# No old hostname
false
fi
}
try_hostname()
{
[ "$hostname" = "$1" ] && return 0
if valid_domainname "$1"; then
syslog info "Setting hostname: $1"
_hostname "$1"
else
syslog err "Invalid hostname: $1"
fi
}
set_hostname()
{
need_hostname || return
set_hostname_vars
if [ -n "$new_fqdn" ]; then
if ${hfqdn} || ! ${hshort}; then
try_hostname "$new_fqdn"
else
try_hostname "${new_fqdn%%.*}"
fi
elif [ -n "$new_host_name" ]; then
if ${hfqdn}; then
if [ -n "$new_domain_name" ] &&
[ "$new_host_name" = "${new_host_name#*.}" ]
then
try_hostname "$new_host_name.$new_domain_name"
else
try_hostname "$new_host_name"
fi
elif ${hshort}; then
try_hostname "${new_host_name%%.*}"
else
try_hostname "$new_host_name"
fi
elif [ -n "${hostname_default+x}" ]; then
try_hostname "$hostname_default"
fi
}
# For ease of use, map DHCP6 names onto our DHCP4 names
case "$reason" in
BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
new_fqdn="$new_dhcp6_fqdn"
old_fqdn="$old_dhcp6_fqdn"
;;
esac
if $if_up; then
set_hostname
fi

View File

@ -41,7 +41,7 @@ if [ -z "$ntp_service" ]; then
esac
fi
# Debian has a seperate file for DHCP config to avoid stamping on
# Debian has a separate file for DHCP config to avoid stamping on
# the master.
if [ "$ntp_service" = ntpd ] && type invoke-rc.d >/dev/null 2>&1; then
[ -e /var/lib/ntp ] || mkdir /var/lib/ntp

View File

@ -8,7 +8,7 @@ signature_base="# Generated by dhcpcd"
signature="$signature_base $from $ifname"
signature_base_end="# End of dhcpcd"
signature_end="$signature_base_end $from $ifname"
state_dir=@RUNDIR@/dhcpcd
state_dir=@RUNDIR@/hook-state
_detected_init=false
: ${if_up:=false}

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd: BPF arp and bootp filtering
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2020 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -93,6 +93,38 @@ bpf_frame_header_len(const struct interface *ifp)
}
}
void *
bpf_frame_header_src(const struct interface *ifp, void *fh, size_t *len)
{
uint8_t *f = fh;
switch (ifp->family) {
case ARPHRD_ETHER:
*len = sizeof(((struct ether_header *)0)->ether_shost);
return f + offsetof(struct ether_header, ether_shost);
default:
*len = 0;
errno = ENOTSUP;
return NULL;
}
}
void *
bpf_frame_header_dst(const struct interface *ifp, void *fh, size_t *len)
{
uint8_t *f = fh;
switch (ifp->family) {
case ARPHRD_ETHER:
*len = sizeof(((struct ether_header *)0)->ether_dhost);
return f + offsetof(struct ether_header, ether_dhost);
default:
*len = 0;
errno = ENOTSUP;
return NULL;
}
}
static const uint8_t etherbcastaddr[] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@ -215,7 +247,6 @@ ssize_t
bpf_read(struct interface *ifp, int fd, void *data, size_t len,
unsigned int *flags)
{
ssize_t fl = (ssize_t)bpf_frame_header_len(ifp);
ssize_t bytes;
struct ipv4_state *state = IPV4_STATE(ifp);
@ -250,10 +281,10 @@ bpf_read(struct interface *ifp, int fd, void *data, size_t len,
*flags |= BPF_BCAST;
else
*flags &= ~BPF_BCAST;
payload += fl;
bytes = (ssize_t)packet.bh_caplen - fl;
if ((size_t)bytes > len)
if (packet.bh_caplen > len)
bytes = (ssize_t)len;
else
bytes = (ssize_t)packet.bh_caplen;
memcpy(data, payload, (size_t)bytes);
next:
state->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen +
@ -464,6 +495,8 @@ bpf_arp(struct interface *ifp, int fd)
struct bpf_insn *bp;
struct iarp_state *state;
uint16_t arp_len;
struct arp_state *astate;
size_t naddrs;
if (fd == -1)
return 0;
@ -490,58 +523,60 @@ bpf_arp(struct interface *ifp, int fd)
false, ifp->hwaddr, ifp->hwlen);
state = ARP_STATE(ifp);
if (TAILQ_FIRST(&state->arp_states)) {
struct arp_state *astate;
size_t naddrs;
/* privsep may not have an initial state yet. */
if (state == NULL || TAILQ_FIRST(&state->arp_states) == NULL)
goto noaddrs;
/* Match sender protocol address */
BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND,
sizeof(struct arphdr) + ifp->hwlen);
bp++;
naddrs = 0;
TAILQ_FOREACH(astate, &state->arp_states, next) {
if (++naddrs > ARP_ADDRS_MAX) {
errno = ENOBUFS;
logerr(__func__);
break;
}
BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
htonl(astate->addr.s_addr), 0, 1);
bp++;
BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len);
bp++;
/* Match sender protocol address */
BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND,
sizeof(struct arphdr) + ifp->hwlen);
bp++;
naddrs = 0;
TAILQ_FOREACH(astate, &state->arp_states, next) {
if (IN_IS_ADDR_UNSPECIFIED(&astate->addr))
continue;
if (++naddrs > ARP_ADDRS_MAX) {
errno = ENOBUFS;
logerr(__func__);
break;
}
/* If we didn't match sender, then we're only interested in
* ARP probes to us, so check the null host sender. */
BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, INADDR_ANY, 1, 0);
BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
htonl(astate->addr.s_addr), 0, 1);
bp++;
BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
bp++;
/* Match target protocol address */
BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND,
(sizeof(struct arphdr)
+ (size_t)(ifp->hwlen * 2) + sizeof(in_addr_t)));
bp++;
naddrs = 0;
TAILQ_FOREACH(astate, &state->arp_states, next) {
if (++naddrs > ARP_ADDRS_MAX) {
/* Already logged error above. */
break;
}
BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
htonl(astate->addr.s_addr), 0, 1);
bp++;
BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len);
bp++;
}
/* Return nothing, no protocol address match. */
BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len);
bp++;
}
/* If we didn't match sender, then we're only interested in
* ARP probes to us, so check the null host sender. */
BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K, INADDR_ANY, 1, 0);
bp++;
BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
bp++;
/* Match target protocol address */
BPF_SET_STMT(bp, BPF_LD + BPF_W + BPF_IND,
(sizeof(struct arphdr)
+ (size_t)(ifp->hwlen * 2) + sizeof(in_addr_t)));
bp++;
naddrs = 0;
TAILQ_FOREACH(astate, &state->arp_states, next) {
if (++naddrs > ARP_ADDRS_MAX) {
/* Already logged error above. */
break;
}
BPF_SET_JUMP(bp, BPF_JMP + BPF_JEQ + BPF_K,
htonl(astate->addr.s_addr), 0, 1);
bp++;
BPF_SET_STMT(bp, BPF_RET + BPF_K, arp_len);
bp++;
}
noaddrs:
/* Return nothing, no protocol address match. */
BPF_SET_STMT(bp, BPF_RET + BPF_K, 0);
bp++;
return bpf_attach(fd, bpf, (unsigned int)(bp - bpf));
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
.\" SPDX-License-Identifier: BSD-2-Clause
.\"
.\" Copyright (c) 2006-2019 Roy Marples
.\" Copyright (c) 2006-2020 Roy Marples
.\" All rights reserved
.\"
.\" Redistribution and use in source and binary forms, with or without
@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd October 9, 2019
.Dd March 27, 2020
.Dt DHCPCD 8
.Os
.Sh NAME
@ -357,8 +357,9 @@ Some badly configured DHCP servers reject unknown vendorclassids.
To work around it, try and impersonate Windows by using the MSFT vendorclassid.
.It Fl j , Fl Fl logfile Ar logfile
Writes to the specified
.Ar logfile
rather than
.Ar logfile .
.Nm
still writes to
.Xr syslog 3 .
The
.Ar logfile
@ -683,10 +684,9 @@ To test INFORM the interface needs to be configured with the desired address
before starting
.Nm .
.It Fl U , Fl Fl dumplease Ar interface
Dumps the last lease for the
Dumps the current lease for the
.Ar interface
to stdout.
If omitted, standard input is used to read a DHCP wire formatted message.
Use the
.Fl 4
or
@ -804,20 +804,20 @@ lease and use the file's mtime as when it was issued.
Stores the monotonic counter used in the
.Ar replay
field in Authentication Options.
.It Pa @RUNDIR@/dhcpcd.pid
.It Pa @RUNDIR@/pid
Stores the PID of
.Nm
running on all interfaces.
.It Pa @RUNDIR@/dhcpcd\- Ns Ar interface Ns .pid
.It Pa @RUNDIR@/ Ns Ar interface Ns .pid
Stores the PID of
.Nm
running on the
.Ar interface .
.It Pa @RUNDIR@/dhcpcd.sock
.It Pa @RUNDIR@/sock
Control socket to the master daemon.
.It Pa @RUNDIR@/dhcpcd.unpriv.sock
.It Pa @RUNDIR@/unpriv.sock
Unprivileged socket to the master daemon, only allows state retrieval.
.It Pa @RUNDIR@/dhcpcd\- Ns Ar interface Ns .sock
.It Pa @RUNDIR@/ Ns Ar interface Ns .sock
Control socket to per interface daemon.
.El
.Sh SEE ALSO
@ -833,9 +833,17 @@ 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\ 6355,
RFC\ 6603, RFC\ 6704, RFC\ 7217, RFC\ 7550.
RFC\ 6603, RFC\ 6704, RFC\ 7217, RFC\ 7550, RFC\ 7844.
.Sh AUTHORS
.An Roy Marples Aq Mt roy@marples.name
.Sh BUGS
If
.Nm
is running in a
.Xr chroot 2
then re-opening the
.Fl Fl logfile
from SIGUSR2 may not work.
.Pp
Please report them to
.Lk http://roy.marples.name/projects/dhcpcd

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* BSD interface driver for dhcpcd
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2020 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -58,8 +58,6 @@
#endif
#ifdef __DragonFly__
# include <netproto/802_11/ieee80211_ioctl.h>
#elif __APPLE__
/* FIXME: Add apple includes so we can work out SSID */
#else
# include <net80211/ieee80211.h>
# include <net80211/ieee80211_ioctl.h>
@ -92,6 +90,7 @@
#include "ipv6.h"
#include "ipv6nd.h"
#include "logerr.h"
#include "privsep.h"
#include "route.h"
#include "sa.h"
@ -106,6 +105,7 @@ static const char * const ifnames_ignore[] = {
"bridge",
"fwe", /* Firewire */
"tap",
"xvif", /* XEN DOM0 -> guest interface */
NULL
};
@ -214,6 +214,69 @@ if_closesockets_os(struct dhcpcd_ctx *ctx)
priv = (struct priv *)ctx->priv;
if (priv->pf_inet6_fd != -1)
close(priv->pf_inet6_fd);
free(priv);
ctx->priv = NULL;
}
#if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
static int
if_ioctllink(struct dhcpcd_ctx *ctx, unsigned long req, void *data, size_t len)
{
int s;
int retval;
#ifdef PRIVSEP
if (ctx->options & DHCPCD_PRIVSEP)
return (int)ps_root_ioctllink(ctx, req, data, len);
#else
UNUSED(ctx);
#endif
s = socket(PF_LINK, SOCK_DGRAM, 0);
if (s == -1)
return -1;
retval = ioctl(s, req, data, len);
close(s);
return retval;
}
#endif
int
if_setmac(struct interface *ifp, void *mac, uint8_t maclen)
{
if (ifp->hwlen != maclen) {
errno = EINVAL;
return -1;
}
#if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
struct if_laddrreq iflr = { .flags = IFLR_ACTIVE };
struct sockaddr_dl *sdl = satosdl(&iflr.addr);
int retval;
strlcpy(iflr.iflr_name, ifp->name, sizeof(iflr.iflr_name));
sdl->sdl_family = AF_LINK;
sdl->sdl_len = sizeof(*sdl);
sdl->sdl_alen = maclen;
memcpy(LLADDR(sdl), mac, maclen);
retval = if_ioctllink(ifp->ctx, SIOCALIFADDR, &iflr, sizeof(iflr));
/* Try and remove the old address */
memcpy(LLADDR(sdl), ifp->hwaddr, ifp->hwlen);
if_ioctllink(ifp->ctx, SIOCDLIFADDR, &iflr, sizeof(iflr));
return retval;
#else
struct ifreq ifr = {
.ifr_addr.sa_family = AF_LINK,
.ifr_addr.sa_len = maclen,
};
strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
memcpy(ifr.ifr_addr.sa_data, mac, maclen);
return if_ioctl(ifp->ctx, SIOCSIFLLADDR, &ifr, sizeof(ifr));
#endif
}
static bool
@ -692,11 +755,42 @@ if_route(unsigned char cmd, const struct rt *rt)
#undef ADDSA
rtm->rtm_msglen = (unsigned short)(bp - (char *)rtm);
#ifdef PRIVSEP
if (ctx->options & DHCPCD_PRIVSEP) {
if (ps_root_route(ctx, rtm, rtm->rtm_msglen) == -1)
return -1;
return 0;
}
#endif
if (write(ctx->link_fd, rtm, rtm->rtm_msglen) == -1)
return -1;
return 0;
}
static bool
if_realroute(const struct rt_msghdr *rtm)
{
#ifdef RTF_CLONED
if (rtm->rtm_flags & RTF_CLONED)
return false;
#endif
#ifdef RTF_WASCLONED
if (rtm->rtm_flags & RTF_WASCLONED)
return false;
#endif
#ifdef RTF_LOCAL
if (rtm->rtm_flags & RTF_LOCAL)
return false;
#endif
#ifdef RTF_BROADCAST
if (rtm->rtm_flags & RTF_BROADCAST)
return false;
#endif
return true;
}
static int
if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, const struct rt_msghdr *rtm)
{
@ -710,30 +804,6 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, const struct rt_msghdr *rtm)
errno = EINVAL;
return -1;
}
#ifdef RTF_CLONED
if (rtm->rtm_flags & RTF_CLONED) {
errno = ENOTSUP;
return -1;
}
#endif
#ifdef RTF_WASCLONED
if (rtm->rtm_flags & RTF_WASCLONED) {
errno = ENOTSUP;
return -1;
}
#endif
#ifdef RTF_LOCAL
if (rtm->rtm_flags & RTF_LOCAL) {
errno = ENOTSUP;
return -1;
}
#endif
#ifdef RTF_BROADCAST
if (rtm->rtm_flags & RTF_BROADCAST) {
errno = ENOTSUP;
return -1;
}
#endif
if (get_addrs(rtm->rtm_addrs, (const char *)rtm + sizeof(*rtm),
rtm->rtm_msglen - sizeof(*rtm), rti_info) == -1)
@ -820,6 +890,8 @@ if_initrt(struct dhcpcd_ctx *ctx, rb_tree_t *kroutes, int af)
errno = EINVAL;
break;
}
if (!if_realroute(rtm))
continue;
if (if_copyrt(ctx, &rt, rtm) != 0)
continue;
if ((rtn = rt_new(rt.rt_ifp)) == NULL) {
@ -840,6 +912,7 @@ if_address(unsigned char cmd, const struct ipv4_addr *ia)
{
int r;
struct in_aliasreq ifra;
struct dhcpcd_ctx *ctx = ia->iface->ctx;
memset(&ifra, 0, sizeof(ifra));
strlcpy(ifra.ifra_name, ia->iface->name, sizeof(ifra.ifra_name));
@ -855,8 +928,8 @@ if_address(unsigned char cmd, const struct ipv4_addr *ia)
ADDADDR(&ifra.ifra_broadaddr, &ia->brd);
#undef ADDADDR
r = ioctl(ia->iface->ctx->pf_inet_fd,
cmd == RTM_DELADDR ? SIOCDIFADDR : SIOCAIFADDR, &ifra);
r = if_ioctl(ctx,
cmd == RTM_DELADDR ? SIOCDIFADDR : SIOCAIFADDR, &ifra,sizeof(ifra));
return r;
}
@ -925,14 +998,26 @@ ifa_getscope(const struct sockaddr_in6 *sin)
#endif
}
static int
if_ioctl6(struct dhcpcd_ctx *ctx, unsigned long req, void *data, size_t len)
{
struct priv *priv;
#ifdef PRIVSEP
if (ctx->options & DHCPCD_PRIVSEP)
return (int)ps_root_ioctl6(ctx, req, data, len);
#endif
priv = ctx->priv;
return ioctl(priv->pf_inet6_fd, req, data, len);
}
int
if_address6(unsigned char cmd, const struct ipv6_addr *ia)
{
struct in6_aliasreq ifa;
struct in6_addr mask;
struct priv *priv;
priv = (struct priv *)ia->iface->ctx->priv;
struct dhcpcd_ctx *ctx = ia->iface->ctx;
memset(&ifa, 0, sizeof(ifa));
strlcpy(ifa.ifra_name, ia->iface->name, sizeof(ifa.ifra_name));
@ -1004,7 +1089,7 @@ if_address6(unsigned char cmd, const struct ipv6_addr *ia)
if (cmd == RTM_NEWADDR && !(ia->flags & IPV6_AF_ADDED)) {
ifa.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
ifa.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
(void)ioctl(priv->pf_inet6_fd, SIOCAIFADDR_IN6, &ifa);
(void)if_ioctl6(ctx, SIOCAIFADDR_IN6, &ifa, sizeof(ifa));
}
#endif
@ -1025,8 +1110,9 @@ if_address6(unsigned char cmd, const struct ipv6_addr *ia)
ifa.ifra_lifetime.ia6t_pltime = ia->prefix_pltime;
#endif
return ioctl(priv->pf_inet6_fd,
cmd == RTM_DELADDR ? SIOCDIFADDR_IN6 : SIOCAIFADDR_IN6, &ifa);
return if_ioctl6(ctx,
cmd == RTM_DELADDR ? SIOCDIFADDR_IN6 : SIOCAIFADDR_IN6,
&ifa, sizeof(ifa));
}
int
@ -1159,6 +1245,14 @@ if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
if (rtm->rtm_errno != 0)
return 0;
/* Ignore messages from ourself. */
#ifdef PRIVSEP
if (ctx->ps_root_pid != 0) {
if (rtm->rtm_pid == ctx->ps_root_pid)
return 0;
}
#endif
if (if_copyrt(ctx, &rt, rtm) == -1)
return errno == ENOTSUP ? 0 : -1;
@ -1182,7 +1276,7 @@ if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
}
#endif
if (rtm->rtm_type != RTM_MISS)
if (rtm->rtm_type != RTM_MISS && if_realroute(rtm))
rt_recvrt(rtm->rtm_type, &rt, rtm->rtm_pid);
return 0;
}
@ -1199,6 +1293,28 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam)
errno = EINVAL;
return -1;
}
#ifdef HAVE_IFAM_PID
/* Ignore address deletions from ourself.
* We need to process address flag changes though. */
if (ifam->ifam_type == RTM_DELADDR) {
#ifdef PRIVSEP
if (ctx->ps_root_pid != 0) {
if (ifam->ifam_pid == ctx->ps_root_pid)
return 0;
} else
#endif
/* address management is done via ioctl,
* so SO_USELOOPBACK has no effect,
* so we do need to check the pid. */
if (ifam->ifam_pid == getpid())
return 0;
}
pid = ifam->ifam_pid;
#else
pid = 0;
#endif
if (~ifam->ifam_addrs & RTA_IFA)
return 0;
if ((ifp = if_findindex(ctx->ifaces, ifam->ifam_index)) == NULL)
@ -1208,12 +1324,6 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam)
ifam->ifam_msglen - sizeof(*ifam), rti_info) == -1)
return -1;
#ifdef HAVE_IFAM_PID
pid = ifam->ifam_pid;
#else
pid = 0;
#endif
switch (rti_info[RTAX_IFA]->sa_family) {
case AF_LINK:
{
@ -1334,7 +1444,7 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam)
*/
flags = if_addrflags6(ifp, &addr6, NULL);
if (flags == -1) {
if (errno != EADDRNOTAVAIL)
if (errno != ENXIO && errno != EADDRNOTAVAIL)
logerr("%s: if_addrflags6", __func__);
if (ifam->ifam_type != RTM_DELADDR)
break;
@ -1394,6 +1504,73 @@ if_dispatch(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
return 0;
}
static int
if_missfilter0(struct dhcpcd_ctx *ctx, struct interface *ifp,
struct sockaddr *sa)
{
size_t salen = (size_t)RT_ROUNDUP(sa->sa_len);
size_t newlen = ctx->rt_missfilterlen + salen;
size_t diff = salen - (sa->sa_len);
uint8_t *cp;
if (ctx->rt_missfiltersize < newlen) {
void *n = realloc(ctx->rt_missfilter, newlen);
if (n == NULL)
return -1;
ctx->rt_missfilter = n;
ctx->rt_missfiltersize = newlen;
}
#ifdef INET6
if (sa->sa_family == AF_INET6)
ifa_setscope(satosin6(sa), ifp->index);
#endif
cp = ctx->rt_missfilter + ctx->rt_missfilterlen;
memcpy(cp, sa, sa->sa_len);
if (diff != 0)
memset(cp + sa->sa_len, 0, diff);
ctx->rt_missfilterlen += salen;
#ifdef INET6
if (sa->sa_family == AF_INET6)
ifa_setscope(satosin6(sa), 0);
#endif
return 0;
}
int
if_missfilter(struct interface *ifp, struct sockaddr *sa)
{
return if_missfilter0(ifp->ctx, ifp, sa);
}
int
if_missfilter_apply(struct dhcpcd_ctx *ctx)
{
#ifdef RO_MISSFILTER
if (ctx->rt_missfilterlen == 0) {
struct sockaddr sa = {
.sa_family = AF_UNSPEC,
.sa_len = sizeof(sa),
};
if (if_missfilter0(ctx, NULL, &sa) == -1)
return -1;
}
return setsockopt(ctx->link_fd, PF_ROUTE, RO_MISSFILTER,
ctx->rt_missfilter, (socklen_t)ctx->rt_missfilterlen);
#else
#warning kernel does not support RTM_MISS DST filtering
UNUSED(ctx);
errno = ENOTSUP;
return -1;
#endif
}
__CTASSERT(offsetof(struct rt_msghdr, rtm_msglen) == 0);
int
if_handlelink(struct dhcpcd_ctx *ctx)
@ -1475,19 +1652,20 @@ int
if_applyra(const struct ra *rap)
{
#ifdef SIOCSIFINFO_IN6
struct in6_ndireq ndi = { .ndi.chlim = 0 };
struct priv *priv = rap->iface->ctx->priv;
struct in6_ndireq nd = { .ndi.chlim = 0 };
struct dhcpcd_ctx *ctx = rap->iface->ctx;
struct priv *priv = ctx->priv;
int error;
strlcpy(ndi.ifname, rap->iface->name, sizeof(ndi.ifname));
if (ioctl(priv->pf_inet6_fd, SIOCGIFINFO_IN6, &ndi) == -1)
strlcpy(nd.ifname, rap->iface->name, sizeof(nd.ifname));
if (ioctl(priv->pf_inet6_fd, SIOCGIFINFO_IN6, &nd, sizeof(nd)) == -1)
return -1;
ndi.ndi.linkmtu = rap->mtu;
ndi.ndi.chlim = rap->hoplimit;
ndi.ndi.retrans = rap->retrans;
ndi.ndi.basereachable = rap->reachable;
error = ioctl(priv->pf_inet6_fd, SIOCSIFINFO_IN6, &ndi);
nd.ndi.linkmtu = rap->mtu;
nd.ndi.chlim = rap->hoplimit;
nd.ndi.retrans = rap->retrans;
nd.ndi.basereachable = rap->reachable;
error = if_ioctl6(ctx, SIOCSIFINFO_IN6, &nd, sizeof(nd));
if (error == -1 && errno == EINVAL) {
/*
* Very likely that this is caused by a dodgy MTU
@ -1496,8 +1674,8 @@ if_applyra(const struct ra *rap)
* Doesn't really matter as we fix the MTU against the
* routes we add as not all OS support SIOCSIFINFO_IN6.
*/
ndi.ndi.linkmtu = 0;
error = ioctl(priv->pf_inet6_fd, SIOCSIFINFO_IN6, &ndi);
nd.ndi.linkmtu = 0;
error = if_ioctl6(ctx, SIOCSIFINFO_IN6, &nd, sizeof(nd));
}
return error;
#else
@ -1508,7 +1686,7 @@ if_applyra(const struct ra *rap)
}
#ifdef IPV6_MANAGETEMPADDR
#ifndef IPV6CTL_TEMPVLTIME
#if !defined(IPV6CTL_TEMPVLTIME) && !defined(__OpenBSD__)
#define get_inet6_sysctlbyname(code) inet6_sysctlbyname(code, 0, 0)
#define set_inet6_sysctlbyname(code, val) inet6_sysctlbyname(code, val, 1)
static int
@ -1528,6 +1706,40 @@ inet6_sysctlbyname(const char *name, int val, int action)
}
#endif
#ifdef __OpenBSD__
int
ip6_use_tempaddr(const char *ifname)
{
int s, r;
struct ifreq ifr;
s = socket(PF_INET6, SOCK_DGRAM, 0); /* XXX Not efficient */
if (s == -1)
return -1;
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
r = ioctl(s, SIOCGIFXFLAGS, &ifr);
close(s);
if (r == -1)
return -1;
return ifr.ifr_flags & IFXF_INET6_NOPRIVACY ? 0 : 1;
}
int
ip6_temp_preferred_lifetime(__unused const char *ifname)
{
return ND6_PRIV_PREFERRED_LIFETIME;
}
int
ip6_temp_valid_lifetime(__unused const char *ifname)
{
return ND6_PRIV_VALID_LIFETIME;
}
#else /* __OpenBSD__ */
int
ip6_use_tempaddr(__unused const char *ifname)
{
@ -1566,6 +1778,7 @@ ip6_temp_valid_lifetime(__unused const char *ifname)
#endif
return val < 0 ? TEMP_VALID_LIFETIME : val;
}
#endif /* !__OpenBSD__ */
#endif
int
@ -1583,25 +1796,26 @@ ip6_forwarding(__unused const char *ifname)
#ifdef SIOCIFAFATTACH
static int
af_attach(int s, const struct interface *ifp, int af)
if_af_attach(const struct interface *ifp, int af)
{
struct if_afreq ifar;
strlcpy(ifar.ifar_name, ifp->name, sizeof(ifar.ifar_name));
ifar.ifar_af = af;
return ioctl(s, SIOCIFAFATTACH, (void *)&ifar);
return if_ioctl6(ifp->ctx, SIOCIFAFATTACH, &ifar, sizeof(ifar));
}
#endif
#ifdef SIOCGIFXFLAGS
static int
set_ifxflags(int s, const struct interface *ifp)
if_set_ifxflags(const struct interface *ifp)
{
struct ifreq ifr;
int flags;
struct priv *priv = ifp->ctx->priv;
strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
if (ioctl(s, SIOCGIFXFLAGS, (void *)&ifr) == -1)
if (ioctl(priv->pf_inet6_fd, SIOCGIFXFLAGS, &ifr) == -1)
return -1;
flags = ifr.ifr_flags;
#ifdef IFXF_NOINET6
@ -1628,7 +1842,7 @@ set_ifxflags(int s, const struct interface *ifp)
if (ifr.ifr_flags == flags)
return 0;
ifr.ifr_flags = flags;
return ioctl(s, SIOCSIFXFLAGS, (void *)&ifr);
return if_ioctl6(ifp->ctx, SIOCSIFXFLAGS, &ifr, sizeof(ifr));
}
#endif
@ -1711,7 +1925,8 @@ if_setup_inet6(const struct interface *ifp)
#ifdef ND6_NDI_FLAGS
if (nd.ndi.flags != (uint32_t)flags) {
nd.ndi.flags = (uint32_t)flags;
if (ioctl(s, SIOCSIFINFO_FLAGS, &nd) == -1)
if (if_ioctl6(ifp->ctx, SIOCSIFINFO_FLAGS,
&nd, sizeof(nd)) == -1)
logerr("%s: SIOCSIFINFO_FLAGS", ifp->name);
}
#endif
@ -1720,12 +1935,12 @@ if_setup_inet6(const struct interface *ifp)
* last action undertaken to ensure kernel RS and
* LLADDR auto configuration are disabled where applicable. */
#ifdef SIOCIFAFATTACH
if (af_attach(s, ifp, AF_INET6) == -1)
logerr("%s: af_attach", ifp->name);
if (if_af_attach(ifp, AF_INET6) == -1)
logerr("%s: if_af_attach", ifp->name);
#endif
#ifdef SIOCGIFXFLAGS
if (set_ifxflags(s, ifp) == -1)
if (if_set_ifxflags(ifp) == -1)
logerr("%s: set_ifxflags", ifp->name);
#endif
@ -1738,10 +1953,12 @@ if_setup_inet6(const struct interface *ifp)
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
if (ioctl(s, SIOCSRTRFLUSH_IN6, &ifr) == -1 &&
if (if_ioctl6(ifp->ctx, SIOCSRTRFLUSH_IN6,
&ifr, sizeof(ifr)) == -1 &&
errno != ENOTSUP)
logwarn("SIOCSRTRFLUSH_IN6");
if (ioctl(s, SIOCSPFXFLUSH_IN6, &ifr) == -1 &&
if (if_ioctl6(ifp->ctx, SIOCSPFXFLUSH_IN6,
&ifr, sizeof(ifr)) == -1 &&
errno != ENOTSUP)
logwarn("SIOCSPFXFLUSH_IN6");
}

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2020 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -66,7 +66,7 @@
#define O_NOIPV6RS O_BASE + 5
#define O_IPV6RA_FORK O_BASE + 6
#define O_LINK_RCVBUF O_BASE + 7
// unused O_BASE + 8
#define O_ANONYMOUS O_BASE + 8
#define O_NOALIAS O_BASE + 9
#define O_IA_NA O_BASE + 10
#define O_IA_TA O_BASE + 11
@ -106,6 +106,7 @@
#define O_LASTLEASE_EXTEND O_BASE + 46
#define O_INACTIVE O_BASE + 47
#define O_MUDURL O_BASE + 48
#define O_MSUSERCLASS O_BASE + 49
const struct option cf_options[] = {
{"background", no_argument, NULL, 'b'},
@ -129,6 +130,9 @@ const struct option cf_options[] = {
{"inform6", optional_argument, NULL, O_INFORM6},
{"timeout", required_argument, NULL, 't'},
{"userclass", required_argument, NULL, 'u'},
#ifndef SMALL
{"msuserclass", required_argument, NULL, O_MSUSERCLASS},
#endif
{"vendor", required_argument, NULL, 'v'},
{"waitip", optional_argument, NULL, 'w'},
{"exit", no_argument, NULL, 'x'},
@ -161,6 +165,7 @@ const struct option cf_options[] = {
{"oneshot", no_argument, NULL, '1'},
{"ipv4only", no_argument, NULL, '4'},
{"ipv6only", no_argument, NULL, '6'},
{"anonymous", no_argument, NULL, O_ANONYMOUS},
{"arping", required_argument, NULL, O_ARPING},
{"destination", required_argument, NULL, O_DESTINATION},
{"fallback", required_argument, NULL, O_FALLBACK},
@ -286,6 +291,7 @@ add_environ(char ***array, const char *value, int uniq)
#define PARSE_STRING_NULL 1
#define PARSE_HWADDR 2
#define parse_string(a, b, c) parse_str((a), (b), (c), PARSE_STRING)
#define parse_nstring(a, b, c) parse_str((a), (b), (c), PARSE_STRING_NULL)
#define parse_hwaddr(a, b, c) parse_str((a), (b), (c), PARSE_HWADDR)
static ssize_t
parse_str(char *sbuf, size_t slen, const char *str, int flags)
@ -722,7 +728,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
ARG_REQUIRED;
if (ifo->script != default_script)
free(ifo->script);
s = parse_str(NULL, 0, arg, PARSE_STRING_NULL);
s = parse_nstring(NULL, 0, arg);
if (s == 0) {
ifo->script = NULL;
break;
@ -733,7 +739,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
logerr(__func__);
return -1;
}
s = parse_str(ifo->script, dl, arg, PARSE_STRING_NULL);
s = parse_nstring(ifo->script, dl, arg);
if (s == -1 ||
ifo->script[0] == '\0' ||
strcmp(ifo->script, "/dev/null") == 0)
@ -754,7 +760,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
ifo->options |= DHCPCD_HOSTNAME;
break;
}
s = parse_string(ifo->hostname, HOSTNAME_MAX_LEN, arg);
s = parse_nstring(ifo->hostname, sizeof(ifo->hostname), arg);
if (s == -1) {
logerr("%s: hostname", __func__);
return -1;
@ -763,7 +769,6 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
logerrx("hostname cannot begin with .");
return -1;
}
ifo->hostname[s] = '\0';
if (ifo->hostname[0] == '\0')
ifo->options &= ~DHCPCD_HOSTNAME;
else
@ -874,16 +879,16 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
break;
case 't':
ARG_REQUIRED;
ifo->timeout = (time_t)strtoi(arg, NULL, 0, 0, INT32_MAX, &e);
ifo->timeout = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
if (e) {
logerrx("failed to convert timeout %s", arg);
return -1;
}
break;
case 'u':
s = USERCLASS_MAX_LEN - ifo->userclass[0] - 1;
dl = sizeof(ifo->userclass) - ifo->userclass[0] - 1;
s = parse_string((char *)ifo->userclass +
ifo->userclass[0] + 2, (size_t)s, arg);
ifo->userclass[0] + 2, dl, arg);
if (s == -1) {
logerr("userclass");
return -1;
@ -893,6 +898,19 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
ifo->userclass[0] = (uint8_t)(ifo->userclass[0] + s +1);
}
break;
#ifndef SMALL
case O_MSUSERCLASS:
/* Some Microsoft DHCP servers expect userclass to be an
* opaque blob. This is not RFC 3004 compliant. */
s = parse_string((char *)ifo->userclass + 1,
sizeof(ifo->userclass) - 1, arg);
if (s == -1) {
logerr("msuserclass");
return -1;
}
ifo->userclass[0] = (uint8_t)s;
break;
#endif
case 'v':
ARG_REQUIRED;
p = strchr(arg, ',');
@ -967,7 +985,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
break;
case 'y':
ARG_REQUIRED;
ifo->reboot = (time_t)strtoi(arg, NULL, 0, 0, UINT32_MAX, &e);
ifo->reboot = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
if (e) {
logerr("failed to convert reboot %s", arg);
return -1;
@ -1165,7 +1183,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
np = strchr(p, '/');
if (np)
*np++ = '\0';
if (inet_pton(AF_INET6, p, &ifo->req_addr6) == 1) {
if ((i = inet_pton(AF_INET6, p, &ifo->req_addr6)) == 1) {
if (np) {
ifo->req_prefix_len = (uint8_t)strtou(np,
NULL, 0, 0, 128, &e);
@ -1178,6 +1196,14 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
} else
ifo->req_prefix_len = 128;
}
if (np)
*(--np) = '\0';
if (i != 1) {
logerrx("invalid AF_INET6: %s", p);
memset(&ifo->req_addr6, 0,
sizeof(ifo->req_addr6));
return -1;
}
} else
add_environ(&ifo->config, arg, 1);
break;
@ -1238,6 +1264,34 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
break;
case O_NOIPV6:
ifo->options &= ~DHCPCD_IPV6;
break;
case O_ANONYMOUS:
ifo->options |= DHCPCD_ANONYMOUS;
ifo->options &= ~DHCPCD_HOSTNAME;
ifo->fqdn = FQDN_DISABLE;
/* Block everything */
memset(ifo->nomask, 0xff, sizeof(ifo->nomask));
memset(ifo->nomask6, 0xff, sizeof(ifo->nomask6));
/* Allow the bare minimum through */
del_option_mask(ifo->nomask, DHO_SUBNETMASK);
del_option_mask(ifo->nomask, DHO_CSR);
del_option_mask(ifo->nomask, DHO_ROUTER);
del_option_mask(ifo->nomask, DHO_DNSSERVER);
del_option_mask(ifo->nomask, DHO_DNSDOMAIN);
del_option_mask(ifo->nomask, DHO_BROADCAST);
del_option_mask(ifo->nomask, DHO_STATICROUTE);
del_option_mask(ifo->nomask, DHO_SERVERID);
del_option_mask(ifo->nomask, DHO_RENEWALTIME);
del_option_mask(ifo->nomask, DHO_REBINDTIME);
del_option_mask(ifo->nomask, DHO_DNSSEARCH);
del_option_mask(ifo->nomask6, D6_OPTION_DNS_SERVERS);
del_option_mask(ifo->nomask6, D6_OPTION_DOMAIN_LIST);
del_option_mask(ifo->nomask6, D6_OPTION_SOL_MAX_RT);
del_option_mask(ifo->nomask6, D6_OPTION_INF_MAX_RT);
break;
#ifdef INET
case O_ARPING:
@ -1398,8 +1452,8 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
p = strchr(arg, '/');
if (p)
*p++ = '\0';
if (inet_pton(AF_INET6, arg, &ia->addr) == -1) {
logerr("%s", arg);
if (inet_pton(AF_INET6, arg, &ia->addr) != 1) {
logerrx("invalid AF_INET6: %s", arg);
memset(&ia->addr, 0, sizeof(ia->addr));
}
if (p && ia->ia_type == D6_OPTION_IA_PD) {
@ -1972,52 +2026,42 @@ err_sla:
return -1;
}
*fp++ = '\0';
token = malloc(sizeof(*token));
token = calloc(1, sizeof(*token));
if (token == NULL) {
logerr(__func__);
free(token);
return -1;
}
if (parse_uint32(&token->secretid, arg) == -1) {
logerrx("%s: not a number", arg);
free(token);
return -1;
goto invalid_token;
}
arg = fp;
fp = strend(arg);
if (fp == NULL) {
logerrx("authtoken requies an a key");
free(token);
return -1;
goto invalid_token;
}
*fp++ = '\0';
s = parse_string(NULL, 0, arg);
if (s == -1) {
logerr("realm_len");
free(token);
return -1;
goto invalid_token;
}
if (s) {
if (s != 0) {
token->realm_len = (size_t)s;
token->realm = malloc(token->realm_len);
if (token->realm == NULL) {
logerr(__func__);
free(token);
return -1;
goto invalid_token;
}
parse_string((char *)token->realm, token->realm_len,
arg);
} else {
token->realm_len = 0;
token->realm = NULL;
}
arg = fp;
fp = strend(arg);
if (fp == NULL) {
logerrx("authtoken requies an expiry date");
free(token->realm);
free(token);
return -1;
goto invalid_token;
}
*fp++ = '\0';
if (*arg == '"') {
@ -2034,15 +2078,11 @@ err_sla:
memset(&tm, 0, sizeof(tm));
if (strptime(arg, "%Y-%m-%d %H:%M", &tm) == NULL) {
logerrx("%s: invalid date time", arg);
free(token->realm);
free(token);
return -1;
goto invalid_token;
}
if ((token->expire = mktime(&tm)) == (time_t)-1) {
logerr("%s: mktime", __func__);
free(token->realm);
free(token);
return -1;
goto invalid_token;
}
}
arg = fp;
@ -2052,19 +2092,25 @@ err_sla:
logerr("token_len");
else
logerrx("authtoken needs a key");
free(token->realm);
free(token);
return -1;
goto invalid_token;
}
token->key_len = (size_t)s;
token->key = malloc(token->key_len);
if (token->key == NULL) {
logerr(__func__);
goto invalid_token;
}
parse_string((char *)token->key, token->key_len, arg);
TAILQ_INSERT_TAIL(&ifo->auth.tokens, token, next);
break;
invalid_token:
free(token->realm);
free(token);
#else
logerrx("no authentication support");
return -1;
#endif
break;
return -1;
case O_AUTHNOTREQUIRED:
ifo->auth.options &= ~DHCPCD_AUTH_REQUIRE;
break;
@ -2491,6 +2537,11 @@ read_config(struct dhcpcd_ctx *ctx,
}
/* Parse our options file */
#ifdef PRIVSEP
if (ctx->options & DHCPCD_PRIVSEP &&
ps_root_copychroot(ctx, ctx->cffile) == -1)
logwarn("%s: ps_root_copychroot `%s'", __func__, ctx->cffile);
#endif
fp = fopen(ctx->cffile, "r");
if (fp == NULL) {
/* dhcpcd can continue without it, but no DNS options

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2020 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -57,9 +57,10 @@
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#define ELOOP_QUEUE 7
#define ELOOP_QUEUE ELOOP_IPV6
#include "common.h"
#include "if.h"
#include "dhcpcd.h"
@ -380,25 +381,14 @@ ipv6_makeaddr(struct in6_addr *addr, struct interface *ifp,
static int
ipv6_makeprefix(struct in6_addr *prefix, const struct in6_addr *addr, int len)
{
int bytes, bits;
struct in6_addr mask;
size_t i;
if (len < 0 || len > 128) {
errno = EINVAL;
if (ipv6_mask(&mask, len) == -1)
return -1;
}
bytes = len / NBBY;
bits = len % NBBY;
memcpy(&prefix->s6_addr, &addr->s6_addr, (size_t)bytes);
if (bits != 0) {
/* Coverify false positive.
* bytelen cannot be 16 if bitlen is non zero */
/* coverity[overrun-local] */
prefix->s6_addr[bytes] =
(uint8_t)(prefix->s6_addr[bytes] >> (NBBY - bits));
}
memset((char *)prefix->s6_addr + bytes, 0,
sizeof(prefix->s6_addr) - (size_t)bytes);
*prefix = *addr;
for (i = 0; i < sizeof(prefix->s6_addr); i++)
prefix->s6_addr[i] &= mask.s6_addr[i];
return 0;
}
@ -568,11 +558,8 @@ ipv6_checkaddrflags(void *arg)
&ia->addr, ia->prefix_len, flags, 0);
} else {
/* Still tentative? Check again in a bit. */
struct timespec tv;
ms_to_ts(&tv, RETRANS_TIMER / 2);
eloop_timeout_add_tv(ia->iface->ctx->eloop, &tv,
ipv6_checkaddrflags, ia);
eloop_timeout_add_msec(ia->iface->ctx->eloop,
RETRANS_TIMER / 2, ipv6_checkaddrflags, ia);
}
}
#endif
@ -581,7 +568,10 @@ static void
ipv6_deletedaddr(struct ipv6_addr *ia)
{
#ifdef SMALL
#ifdef PRIVSEP
if (!(ia->iface->ctx->options & DHCPCD_MASTER))
ps_inet_closedhcp6(ia);
#elif defined(SMALL)
UNUSED(ia);
#else
/* NOREJECT is set if we delegated exactly the prefix to another
@ -627,7 +617,7 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
{
struct interface *ifp;
uint32_t pltime, vltime;
__printflike(1, 2) void (*logfunc)(const char *, ...);
int loglevel;
#ifdef ND6_ADVERTISE
bool vltime_was_zero = ia->prefix_vltime == 0;
#endif
@ -663,33 +653,31 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
(ia->prefix_pltime != ND6_INFINITE_LIFETIME ||
ia->prefix_vltime != ND6_INFINITE_LIFETIME))
{
uint32_t elapsed;
struct timespec n;
if (now == NULL) {
clock_gettime(CLOCK_MONOTONIC, &n);
now = &n;
}
timespecsub(now, &ia->acquired, &n);
elapsed = (uint32_t)eloop_timespec_diff(now, &ia->acquired,
NULL);
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 (ia->prefix_pltime > pltime)
if (elapsed > ia->prefix_pltime)
ia->prefix_pltime = 0;
else
ia->prefix_pltime -= elapsed;
}
if (ia->prefix_vltime != ND6_INFINITE_LIFETIME) {
ia->prefix_vltime -= (uint32_t)n.tv_sec;
/* This should never happen. */
if (ia->prefix_vltime > vltime) {
logerrx("%s: %s: lifetime overflow",
ifp->name, ia->saddr);
ia->prefix_vltime = ia->prefix_pltime = 0;
}
if (elapsed > ia->prefix_vltime)
ia->prefix_vltime = 0;
else
ia->prefix_vltime -= elapsed;
}
}
logfunc = ia->flags & IPV6_AF_NEW ? loginfox : logdebugx;
logfunc("%s: adding %saddress %s", ifp->name,
loglevel = ia->flags & IPV6_AF_NEW ? LOG_INFO : LOG_DEBUG;
logmessage(loglevel, "%s: adding %saddress %s", ifp->name,
#ifdef IPV6_AF_TEMPORARY
ia->flags & IPV6_AF_TEMPORARY ? "temporary " : "",
#else
@ -726,7 +714,7 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
ia->prefix_vltime &&
ip6_use_tempaddr(ifp->name))
eloop_timeout_add_sec(ifp->ctx->eloop,
(time_t)ia->prefix_pltime - REGEN_ADVANCE,
ia->prefix_pltime - REGEN_ADVANCE,
ipv6_regentempaddr, ia);
#endif
@ -745,11 +733,8 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
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(ifp->ctx->eloop,
&tv, ipv6_checkaddrflags, ia);
eloop_timeout_add_msec(ifp->ctx->eloop,
RETRANS_TIMER / 2, ipv6_checkaddrflags, ia);
}
#endif
@ -932,7 +917,7 @@ ipv6_doaddr(struct ipv6_addr *ia, struct timespec *now)
if (ia->flags & IPV6_AF_ADDED)
ipv6_deleteaddr(ia);
eloop_q_timeout_delete(ia->iface->ctx->eloop,
0, NULL, ia);
ELOOP_QUEUE_ALL, NULL, ia);
if (ia->flags & IPV6_AF_REQUEST) {
ia->flags &= ~IPV6_AF_ADDED;
return 0;
@ -974,6 +959,7 @@ ipv6_addaddrs(struct ipv6_addrhead *iaddrs)
void
ipv6_freeaddr(struct ipv6_addr *ia)
{
struct eloop *eloop = ia->iface->ctx->eloop;
#ifndef SMALL
struct ipv6_addr *iad;
@ -989,10 +975,10 @@ ipv6_freeaddr(struct ipv6_addr *ia)
if (ia->dhcp6_fd != -1) {
close(ia->dhcp6_fd);
eloop_event_delete(ia->iface->ctx->eloop, ia->dhcp6_fd);
eloop_event_delete(eloop, ia->dhcp6_fd);
}
eloop_q_timeout_delete(ia->iface->ctx->eloop, 0, NULL, ia);
eloop_q_timeout_delete(eloop, ELOOP_QUEUE_ALL, NULL, ia);
free(ia->na);
free(ia);
}
@ -1207,12 +1193,9 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) || ia->dadcallback) {
#ifdef IPV6_POLLADDRFLAG
if (ia->addr_flags & IN6_IFF_TENTATIVE) {
struct timespec tv;
ms_to_ts(&tv, RETRANS_TIMER / 2);
eloop_timeout_add_tv(
eloop_timeout_add_msec(
ia->iface->ctx->eloop,
&tv, ipv6_checkaddrflags, ia);
RETRANS_TIMER / 2, ipv6_checkaddrflags, ia);
break;
}
#endif
@ -1509,12 +1492,9 @@ ipv6_tryaddlinklocal(struct interface *ifp)
if (ia != NULL) {
#ifdef IPV6_POLLADDRFLAG
if (ia->addr_flags & IN6_IFF_TENTATIVE) {
struct timespec tv;
ms_to_ts(&tv, RETRANS_TIMER / 2);
eloop_timeout_add_tv(
eloop_timeout_add_msec(
ia->iface->ctx->eloop,
&tv, ipv6_checkaddrflags, ia);
RETRANS_TIMER / 2, ipv6_checkaddrflags, ia);
}
#endif
return 0;
@ -1529,18 +1509,28 @@ struct ipv6_addr *
ipv6_newaddr(struct interface *ifp, const struct in6_addr *addr,
uint8_t prefix_len, unsigned int flags)
{
struct ipv6_addr *ia;
struct ipv6_addr *ia, *iaf;
char buf[INET6_ADDRSTRLEN];
const char *cbp;
bool tempaddr;
int addr_flags;
#ifdef IPV6_AF_TEMPORARY
tempaddr = flags & IPV6_AF_TEMPORARY;
#else
tempaddr = false;
#endif
/* 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;
if (flags & IPV6_AF_AUTOCONF)
iaf = ipv6nd_iffindprefix(ifp, addr, prefix_len);
else
iaf = ipv6_iffindaddr(ifp, addr, 0);
if (iaf != NULL) {
addr_flags = iaf->addr_flags;
flags |= IPV6_AF_ADDED;
} else
addr_flags = IN6_IFF_TENTATIVE;
ia = calloc(1, sizeof(*ia));
@ -1559,21 +1549,19 @@ ipv6_newaddr(struct interface *ifp, const struct in6_addr *addr,
TAILQ_INIT(&ia->pd_pfxs);
#endif
#ifdef IPV6_AF_TEMPORARY
tempaddr = ia->flags & IPV6_AF_TEMPORARY;
#else
tempaddr = false;
#endif
if (prefix_len == 128)
goto makepfx;
else 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;
if (iaf != NULL)
memcpy(&ia->addr, &iaf->addr, sizeof(ia->addr));
else {
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;
#ifdef __sun
@ -1819,9 +1807,9 @@ ipv6_handleifa_addrs(int cmd,
ia->iface->name, pid, ia->saddr);
ia->flags &= ~IPV6_AF_ADDED;
}
ipv6_deletedaddr(ia);
if (ia->flags & IPV6_AF_DELEGATED) {
TAILQ_REMOVE(addrs, ia, next);
ipv6_deletedaddr(ia);
ipv6_freeaddr(ia);
}
break;
@ -1877,7 +1865,7 @@ static void
ipv6_regen_desync(struct interface *ifp, int force)
{
struct ipv6_state *state;
time_t max;
unsigned int max, pref;
state = IPV6_STATE(ifp);
@ -1885,15 +1873,14 @@ ipv6_regen_desync(struct interface *ifp, int force)
* greater than TEMP_VALID_LIFETIME - REGEN_ADVANCE.
* I believe this is an error and it should be never be greateter than
* TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE. */
max = ip6_temp_preferred_lifetime(ifp->name) - REGEN_ADVANCE;
pref = (unsigned int)ip6_temp_preferred_lifetime(ifp->name);
max = pref - REGEN_ADVANCE;
if (state->desync_factor && !force && state->desync_factor < max)
return;
if (state->desync_factor == 0)
state->desync_factor =
(time_t)arc4random_uniform(MIN(MAX_DESYNC_FACTOR,
(uint32_t)max));
max = ip6_temp_preferred_lifetime(ifp->name) -
state->desync_factor - REGEN_ADVANCE;
arc4random_uniform(MIN(MAX_DESYNC_FACTOR, max));
max = pref - state->desync_factor - REGEN_ADVANCE;
eloop_timeout_add_sec(ifp->ctx->eloop, max, ipv6_regentempifid, ifp);
}
@ -2048,8 +2035,8 @@ again:
ipv6_regen_desync(ia->iface, 0);
/* RFC4941 Section 3.3.4 */
i = (uint32_t)(ip6_temp_preferred_lifetime(ia0->iface->name) -
state->desync_factor);
i = (uint32_t)ip6_temp_preferred_lifetime(ia0->iface->name) -
state->desync_factor;
ia->prefix_pltime = MIN(ia0->prefix_pltime, i);
i = (uint32_t)ip6_temp_valid_lifetime(ia0->iface->name);
ia->prefix_vltime = MIN(ia0->prefix_vltime, i);
@ -2078,7 +2065,7 @@ ipv6_settemptime(struct ipv6_addr *ia, int flags)
ap->prefix_pltime &&
IN6_ARE_ADDR_EQUAL(&ia->prefix, &ap->prefix))
{
time_t max, ext;
unsigned int max, ext;
if (flags == 0) {
if (ap->prefix_pltime -
@ -2107,10 +2094,11 @@ ipv6_settemptime(struct ipv6_addr *ia, int flags)
/* RFC4941 Section 3.3.2
* Extend temporary times, but ensure that they
* never last beyond the system limit. */
ext = ia->acquired.tv_sec + (time_t)ia->prefix_pltime;
max = ap->created.tv_sec +
ext = (unsigned int)ia->acquired.tv_sec
+ ia->prefix_pltime;
max = (unsigned int)(ap->created.tv_sec +
ip6_temp_preferred_lifetime(ap->iface->name) -
state->desync_factor;
state->desync_factor);
if (ext < max)
ap->prefix_pltime = ia->prefix_pltime;
else
@ -2118,9 +2106,10 @@ ipv6_settemptime(struct ipv6_addr *ia, int flags)
(uint32_t)(max - ia->acquired.tv_sec);
valid:
ext = ia->acquired.tv_sec + (time_t)ia->prefix_vltime;
max = ap->created.tv_sec +
ip6_temp_valid_lifetime(ap->iface->name);
ext = (unsigned int)ia->acquired.tv_sec +
ia->prefix_vltime;
max = (unsigned int)(ap->created.tv_sec +
ip6_temp_valid_lifetime(ap->iface->name));
if (ext < max)
ap->prefix_vltime = ia->prefix_vltime;
else
@ -2342,6 +2331,9 @@ inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
struct ra *rap;
const struct ipv6_addr *addr;
if (ctx->ra_routers == NULL)
return 0;
TAILQ_FOREACH(rap, ctx->ra_routers, next) {
if (rap->expired)
continue;

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2020 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -69,6 +69,8 @@
/* Interface identifier length. Prefix + this == 128 for autoconf */
#define ipv6_ifidlen(ifp) 64
#define IA6_CANAUTOCONF(ia) \
((ia)->prefix_len + ipv6_ifidlen((ia)->iface) == 128)
#ifndef IN6_ARE_MASKED_ADDR_EQUAL
#define IN6_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \
@ -108,6 +110,11 @@
# undef IPV6_POLLADDRFLAG
#endif
/* Of course OpenBSD has their own special name. */
#if !defined(IN6_IFF_TEMPORARY) && defined(IN6_IFF_PRIVACY)
#define IN6_IFF_TEMPORARY IN6_IFF_PRIVACY
#endif
#ifdef __sun
/* Solaris lacks these defines.
* While it supports DaD, to seems to only expose IFF_DUPLICATE
@ -237,7 +244,7 @@ struct ipv6_state {
struct ll_callback_head ll_callbacks;
#ifdef IPV6_MANAGETEMPADDR
time_t desync_factor;
uint32_t desync_factor;
uint8_t randomseed0[8]; /* upper 64 bits of MD5 digest */
uint8_t randomseed1[8]; /* lower 64 bits */
uint8_t randomid[8];

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - IPv6 ND handling
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2020 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -41,9 +41,10 @@
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#define ELOOP_QUEUE 3
#define ELOOP_QUEUE ELOOP_IPV6ND
#include "common.h"
#include "dhcpcd.h"
#include "dhcp-common.h"
@ -53,6 +54,7 @@
#include "ipv6.h"
#include "ipv6nd.h"
#include "logerr.h"
#include "privsep.h"
#include "route.h"
#include "script.h"
@ -235,7 +237,7 @@ eexit:
}
#ifdef __sun
static int
int
ipv6nd_open(struct interface *ifp)
{
int fd;
@ -272,7 +274,7 @@ ipv6nd_open(struct interface *ifp)
return fd;
}
#else
static int
int
ipv6nd_open(struct dhcpcd_ctx *ctx)
{
int fd;
@ -285,7 +287,8 @@ ipv6nd_open(struct dhcpcd_ctx *ctx)
return -1;
ctx->nd_fd = fd;
eloop_event_add(ctx->eloop, fd, ipv6nd_handledata, ctx);
if (!(IN_PRIVSEP(ctx)))
eloop_event_add(ctx->eloop, fd, ipv6nd_handledata, ctx);
return fd;
}
#endif
@ -363,6 +366,13 @@ ipv6nd_sendrsprobe(void *arg)
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
logdebugx("%s: sending Router Solicitation", ifp->name);
#ifdef PRIVSEP
if (IN_PRIVSEP(ifp->ctx)) {
if (ps_inet_sendnd(ifp, &msg) == -1)
logerr(__func__);
goto sent;
}
#endif
#ifdef __sun
s = state->nd_fd;
#else
@ -376,13 +386,14 @@ ipv6nd_sendrsprobe(void *arg)
* associate with an access point. */
}
#ifdef PRIVSEP
sent:
#endif
if (state->rsprobes++ < MAX_RTR_SOLICITATIONS)
eloop_timeout_add_sec(ifp->ctx->eloop,
RTR_SOLICITATION_INTERVAL, ipv6nd_sendrsprobe, ifp);
else {
else
logwarnx("%s: no IPv6 Routers available", ifp->name);
ipv6nd_drop(ifp);
}
}
#ifdef ND6_ADVERTISE
@ -424,6 +435,14 @@ ipv6nd_sendadvertisement(void *arg)
cm->cmsg_len = CMSG_LEN(sizeof(pi));
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
logdebugx("%s: sending NA for %s", ifp->name, ia->saddr);
#ifdef PRIVSEP
if (IN_PRIVSEP(ifp->ctx)) {
if (ps_inet_sendnd(ifp, &msg) == -1)
logerr(__func__);
goto sent;
}
#endif
#ifdef __sun
s = state->nd_fd;
#else
@ -432,6 +451,9 @@ ipv6nd_sendadvertisement(void *arg)
if (sendmsg(s, &msg, 0) == -1)
logerr(__func__);
#ifdef PRIVSEP
sent:
#endif
if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) {
eloop_timeout_add_sec(ctx->eloop,
state->retrans / 1000, ipv6nd_sendadvertisement, ia);
@ -531,19 +553,13 @@ ipv6nd_expire(void *arg)
{
struct interface *ifp = arg;
struct ra *rap;
struct ipv6_addr *ia;
struct timespec now = { .tv_sec = 1 };
if (ifp->ctx->ra_routers == NULL)
return;
TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
if (rap->iface == ifp)
continue;
rap->acquired = now;
TAILQ_FOREACH(ia, &rap->addrs, next) {
ia->acquired = now;
}
if (rap->iface == ifp && rap->willexpire)
rap->doexpire = true;
}
ipv6nd_expirera(ifp);
}
@ -551,9 +567,17 @@ ipv6nd_expire(void *arg)
void
ipv6nd_startexpire(struct interface *ifp)
{
struct ra *rap;
eloop_timeout_add_sec(ifp->ctx->eloop, RTR_CARRIER_EXPIRE,
ipv6nd_expire, ifp);
if (ifp->ctx->ra_routers == NULL)
return;
TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
if (rap->iface == ifp)
rap->willexpire = true;
}
eloop_q_timeout_add_sec(ifp->ctx->eloop, ELOOP_IPV6RA_EXPIRE,
RTR_CARRIER_EXPIRE, ipv6nd_expire, ifp);
}
static int
@ -584,19 +608,22 @@ ipv6nd_sortrouters(struct dhcpcd_ctx *ctx)
while ((ra1 = TAILQ_FIRST(ctx->ra_routers)) != NULL) {
TAILQ_REMOVE(ctx->ra_routers, ra1, next);
TAILQ_FOREACH(ra2, &sorted_routers, next) {
if (ra1->iface->metric < ra2->iface->metric)
if (ra1->iface->metric > ra2->iface->metric)
continue;
if (ra1->expired && !ra2->expired)
continue;
if (ra1->willexpire && !ra2->willexpire)
continue;
if (ra1->lifetime == 0 && ra2->lifetime != 0)
continue;
if (!ra1->isreachable && ra2->reachable)
continue;
if (ipv6nd_rtpref(ra1) < ipv6nd_rtpref(ra2))
if (ipv6nd_rtpref(ra1) <= ipv6nd_rtpref(ra2))
continue;
/* All things being equal, prefer older routers. */
if (timespeccmp(&ra1->acquired, &ra2->acquired, >=))
continue;
/* We don't need to check time, becase newer
* routers are always added to the tail and then
* sorted. */
TAILQ_INSERT_BEFORE(ra2, ra1, next);
break;
}
@ -719,6 +746,40 @@ ipv6nd_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr,
return NULL;
}
static struct ipv6_addr *
ipv6nd_rapfindprefix(struct ra *rap,
const struct in6_addr *pfx, uint8_t pfxlen)
{
struct ipv6_addr *ia;
TAILQ_FOREACH(ia, &rap->addrs, next) {
if (ia->prefix_vltime == 0)
continue;
if (ia->prefix_len == pfxlen &&
IN6_ARE_ADDR_EQUAL(&ia->prefix, pfx))
break;
}
return ia;
}
struct ipv6_addr *
ipv6nd_iffindprefix(struct interface *ifp,
const struct in6_addr *pfx, uint8_t pfxlen)
{
struct ra *rap;
struct ipv6_addr *ia;
ia = NULL;
TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
if (rap->iface != ifp)
continue;
ia = ipv6nd_rapfindprefix(rap, pfx, pfxlen);
if (ia != NULL)
break;
}
return ia;
}
static void
ipv6nd_removefreedrop_ra(struct ra *rap, int remove_ra, int drop_ra)
{
@ -786,10 +847,10 @@ ipv6nd_free(struct interface *ifp)
return n;
}
static int
static void
ipv6nd_scriptrun(struct ra *rap)
{
int hasdns, hasaddress, pid;
int hasdns, hasaddress;
struct ipv6_addr *ap;
hasaddress = 0;
@ -807,7 +868,7 @@ ipv6nd_scriptrun(struct ra *rap)
logdebugx("%s: waiting for Router Advertisement"
" DAD to complete",
rap->iface->name);
return 0;
return;
}
}
}
@ -820,19 +881,16 @@ ipv6nd_scriptrun(struct ra *rap)
}
script_runreason(rap->iface, "ROUTERADVERT");
pid = 0;
if (hasdns && (hasaddress ||
!(rap->flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER))))
pid = dhcpcd_daemonise(rap->iface->ctx);
dhcpcd_daemonise(rap->iface->ctx);
#if 0
else if (options & DHCPCD_DAEMONISE &&
!(options & DHCPCD_DAEMONISED) && new_data)
logwarnx("%s: did not fork due to an absent"
" RDNSS option in the RA",
ifp->name);
}
#endif
return pid;
}
static void
@ -869,7 +927,6 @@ ipv6nd_dadcallback(void *arg)
struct interface *ifp;
struct ra *rap;
int wascompleted, found;
struct timespec tv;
char buf[INET6_ADDRSTRLEN];
const char *p;
int dadcounter;
@ -885,7 +942,11 @@ ipv6nd_dadcallback(void *arg)
* 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 (ifp->options->options & DHCPCD_SLAACPRIVATE &&
IA6_CANAUTOCONF(ia))
{
unsigned int delay;
if (ia->dadcounter >= IDGEN_RETRIES) {
logerrx("%s: unable to obtain a"
" stable private address",
@ -916,11 +977,8 @@ ipv6nd_dadcallback(void *arg)
p, ia->prefix_len);
else
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,
delay = arc4random_uniform(IDGEN_DELAY * MSEC_PER_SEC);
eloop_timeout_add_msec(ifp->ctx->eloop, delay,
ipv6nd_addaddr, ia);
return;
}
@ -949,8 +1007,7 @@ try_script:
logdebugx("%s: Router Advertisement DAD "
"completed",
rap->iface->name);
if (ipv6nd_scriptrun(rap))
return;
ipv6nd_scriptrun(rap);
}
}
#ifdef ND6_ADVERTISE
@ -959,6 +1016,30 @@ try_script:
}
}
static struct ipv6_addr *
ipv6nd_findmarkstale(struct ra *rap, struct ipv6_addr *ia, bool mark)
{
struct dhcpcd_ctx *ctx = ia->iface->ctx;
struct ra *rap2;
struct ipv6_addr *ia2;
TAILQ_FOREACH(rap2, ctx->ra_routers, next) {
if (rap2 == rap ||
rap2->iface != rap->iface ||
rap2->expired)
continue;
TAILQ_FOREACH(ia2, &rap2->addrs, next) {
if (!IN6_ARE_ADDR_EQUAL(&ia->prefix, &ia2->prefix))
continue;
if (!(ia2->flags & IPV6_AF_STALE))
return ia2;
if (mark)
ia2->prefix_pltime = 0;
}
}
return NULL;
}
#ifndef DHCP6
/* If DHCPv6 is compiled out, supply a shim to provide an error message
* if IPv6RA requests DHCPv6. */
@ -989,14 +1070,14 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
uint8_t *p;
struct ra *rap;
struct in6_addr pi_prefix;
struct ipv6_addr *ap;
struct ipv6_addr *ia;
struct dhcp_opt *dho;
bool new_rap, new_data, has_address;
uint32_t old_lifetime;
int ifmtu;
__printflike(1, 2) void (*logfunc)(const char *, ...);
int loglevel;
#ifdef IPV6_MANAGETEMPADDR
uint8_t new_ap;
bool new_ia;
#endif
if (ifp == NULL) {
@ -1093,8 +1174,11 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
* routers like to decrease the advertised valid and preferred times
* in accordance with the own prefix times which would result in too
* much needless log spam. */
logfunc = new_data || !rap->isreachable ? loginfox : logdebugx,
logfunc("%s: Router Advertisement from %s", ifp->name, rap->sfrom);
if (rap->willexpire)
new_data = true;
loglevel = new_data || !rap->isreachable ? LOG_INFO : LOG_DEBUG,
logmessage(loglevel, "%s: Router Advertisement from %s",
ifp->name, rap->sfrom);
clock_gettime(CLOCK_MONOTONIC, &rap->acquired);
rap->flags = nd_ra->nd_ra_flags_reserved;
@ -1117,7 +1201,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
rap->retrans = ntohl(nd_ra->nd_ra_retransmit);
else
rap->retrans = RETRANS_TIMER;
rap->expired = false;
rap->expired = rap->willexpire = rap->doexpire = false;
rap->hasdns = false;
rap->isreachable = true;
has_address = false;
@ -1126,8 +1210,8 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
#ifdef IPV6_AF_TEMPORARY
ipv6_markaddrsstale(ifp, IPV6_AF_TEMPORARY);
#endif
TAILQ_FOREACH(ap, &rap->addrs, next) {
ap->flags |= IPV6_AF_STALE;
TAILQ_FOREACH(ia, &rap->addrs, next) {
ia->flags |= IPV6_AF_STALE;
}
len -= sizeof(struct nd_router_advert);
@ -1177,15 +1261,15 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
switch (ndo.nd_opt_type) {
case ND_OPT_PREFIX_INFORMATION:
logfunc = new_data ? logerrx : logdebugx;
loglevel = new_data ? LOG_ERR : LOG_DEBUG;
if (ndo.nd_opt_len != 4) {
logfunc("%s: invalid option len for prefix",
logmessage(loglevel, "%s: invalid option len for prefix",
ifp->name);
continue;
}
memcpy(&pi, p, sizeof(pi));
if (pi.nd_opt_pi_prefix_len > 128) {
logfunc("%s: invalid prefix len", ifp->name);
logmessage(loglevel, "%s: invalid prefix len", ifp->name);
continue;
}
/* nd_opt_pi_prefix is not aligned. */
@ -1194,20 +1278,18 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
if (IN6_IS_ADDR_MULTICAST(&pi_prefix) ||
IN6_IS_ADDR_LINKLOCAL(&pi_prefix))
{
logfunc("%s: invalid prefix in RA", ifp->name);
logmessage(loglevel, "%s: invalid prefix in RA", ifp->name);
continue;
}
if (ntohl(pi.nd_opt_pi_preferred_time) >
ntohl(pi.nd_opt_pi_valid_time))
{
logfunc("%s: pltime > vltime", ifp->name);
logmessage(loglevel, "%s: pltime > vltime", ifp->name);
continue;
}
TAILQ_FOREACH(ap, &rap->addrs, next)
if (ap->prefix_len ==pi.nd_opt_pi_prefix_len &&
IN6_ARE_ADDR_EQUAL(&ap->prefix, &pi_prefix))
break;
if (ap == NULL) {
ia = ipv6nd_rapfindprefix(rap,
&pi_prefix, pi.nd_opt_pi_prefix_len);
if (ia == NULL) {
unsigned int flags;
flags = IPV6_AF_RAPFX;
@ -1217,15 +1299,15 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
DHCPCD_IPV6RA_AUTOCONF)
flags |= IPV6_AF_AUTOCONF;
ap = ipv6_newaddr(rap->iface,
ia = ipv6_newaddr(rap->iface,
&pi_prefix, pi.nd_opt_pi_prefix_len, flags);
if (ap == NULL)
if (ia == NULL)
break;
ap->prefix = pi_prefix;
ia->prefix = pi_prefix;
if (flags & IPV6_AF_AUTOCONF)
ap->dadcallback = ipv6nd_dadcallback;
ap->created = ap->acquired = rap->acquired;
TAILQ_INSERT_TAIL(&rap->addrs, ap, next);
ia->dadcallback = ipv6nd_dadcallback;
ia->created = ia->acquired = rap->acquired;
TAILQ_INSERT_TAIL(&rap->addrs, ia, next);
#ifdef IPV6_MANAGETEMPADDR
/* New address to dhcpcd RA handling.
@ -1234,44 +1316,44 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
* extend the existing one rather than
* create a new one */
if (flags & IPV6_AF_AUTOCONF &&
ipv6_iffindaddr(ifp, &ap->addr,
ipv6_iffindaddr(ifp, &ia->addr,
IN6_IFF_NOTUSEABLE) &&
ipv6_settemptime(ap, 0))
new_ap = 0;
ipv6_settemptime(ia, 0))
new_ia = false;
else
new_ap = 1;
new_ia = true;
#endif
} else {
#ifdef IPV6_MANAGETEMPADDR
new_ap = 0;
new_ia = false;
#endif
ap->flags &= ~IPV6_AF_STALE;
ap->acquired = rap->acquired;
ia->flags &= ~IPV6_AF_STALE;
ia->acquired = rap->acquired;
}
if (pi.nd_opt_pi_flags_reserved &
ND_OPT_PI_FLAG_ONLINK)
ap->flags |= IPV6_AF_ONLINK;
ap->prefix_vltime =
ia->flags |= IPV6_AF_ONLINK;
ia->prefix_vltime =
ntohl(pi.nd_opt_pi_valid_time);
ap->prefix_pltime =
ia->prefix_pltime =
ntohl(pi.nd_opt_pi_preferred_time);
if (ap->prefix_vltime != 0 &&
ap->flags & IPV6_AF_AUTOCONF)
if (ia->prefix_vltime != 0 &&
ia->flags & IPV6_AF_AUTOCONF)
has_address = true;
#ifdef IPV6_MANAGETEMPADDR
/* RFC4941 Section 3.3.3 */
if (ap->flags & IPV6_AF_AUTOCONF &&
ip6_use_tempaddr(ap->iface->name) &&
ipv6_ifidlen(ap->iface) + ap->prefix_len == 128)
if (ia->flags & IPV6_AF_AUTOCONF &&
ip6_use_tempaddr(ia->iface->name) &&
IA6_CANAUTOCONF(ia))
{
if (!new_ap) {
if (ipv6_settemptime(ap, 1) == NULL)
new_ap = 1;
if (!new_ia) {
if (ipv6_settemptime(ia, 1) == NULL)
new_ia = true;
}
if (new_ap && ap->prefix_pltime) {
if (ipv6_createtempaddr(ap,
&ap->acquired) == NULL)
if (new_ia && ia->prefix_pltime) {
if (ipv6_createtempaddr(ia,
&ia->acquired) == NULL)
logerr("ipv6_createtempaddr");
}
}
@ -1280,13 +1362,13 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
case ND_OPT_MTU:
if (len < sizeof(mtu)) {
logfunc("%s: short MTU option", ifp->name);
logmessage(loglevel, "%s: short MTU option", ifp->name);
break;
}
memcpy(&mtu, p, sizeof(mtu));
mtu.nd_opt_mtu_mtu = ntohl(mtu.nd_opt_mtu_mtu);
if (mtu.nd_opt_mtu_mtu < IPV6_MMTU) {
logfunc("%s: invalid MTU %d",
logmessage(loglevel, "%s: invalid MTU %d",
ifp->name, mtu.nd_opt_mtu_mtu);
break;
}
@ -1294,7 +1376,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
if (ifmtu == -1)
logerr("if_getmtu");
else if (mtu.nd_opt_mtu_mtu > (uint32_t)ifmtu) {
logfunc("%s: advertised MTU %d"
logmessage(loglevel, "%s: advertised MTU %d"
" is greater than link MTU %d",
ifp->name, mtu.nd_opt_mtu_mtu, ifmtu);
rap->mtu = (uint32_t)ifmtu;
@ -1303,7 +1385,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
break;
case ND_OPT_RDNSS:
if (len < sizeof(rdnss)) {
logfunc("%s: short RDNSS option", ifp->name);
logmessage(loglevel, "%s: short RDNSS option", ifp->name);
break;
}
memcpy(&rdnss, p, sizeof(rdnss));
@ -1333,6 +1415,19 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
}
}
TAILQ_FOREACH(ia, &rap->addrs, next) {
if (!(ia->flags & IPV6_AF_STALE) || ia->prefix_pltime == 0)
continue;
if (ipv6nd_findmarkstale(rap, ia, false) != NULL)
continue;
ipv6nd_findmarkstale(rap, ia, true);
logdebugx("%s: %s: became stale", ifp->name, ia->saddr);
/* Technically this violates RFC 4861 6.3.4,
* but we need a mechanism to tell the kernel to
* try and prefer other addresses. */
ia->prefix_pltime = 0;
}
if (new_data && !has_address && rap->lifetime && !ipv6_anyglobal(ifp))
logwarnx("%s: no global addresses for default route",
ifp->name);
@ -1353,8 +1448,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
#endif
rt_build(ifp->ctx, AF_INET6);
if (ipv6nd_scriptrun(rap))
return;
ipv6nd_scriptrun(rap);
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
eloop_timeout_delete(ifp->ctx->eloop, NULL, rap); /* reachable timer */
@ -1397,7 +1491,8 @@ ipv6nd_hasralifetime(const struct interface *ifp, bool lifetime)
if (ifp->ctx->ra_routers) {
TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next)
if (rap->iface == ifp && !rap->expired &&
if (rap->iface == ifp &&
!rap->expired &&
(!lifetime ||rap->lifetime))
return true;
}
@ -1405,15 +1500,16 @@ ipv6nd_hasralifetime(const struct interface *ifp, bool lifetime)
}
bool
ipv6nd_hasradhcp(const struct interface *ifp)
ipv6nd_hasradhcp(const struct interface *ifp, bool managed)
{
const struct ra *rap;
if (ifp->ctx->ra_routers) {
TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
if (rap->iface == ifp &&
!rap->expired &&
(rap->flags &(ND_RA_FLAG_MANAGED|ND_RA_FLAG_OTHER)))
!rap->expired && !rap->willexpire &&
((managed && rap->flags & ND_RA_FLAG_MANAGED) ||
(!managed && rap->flags & ND_RA_FLAG_OTHER)))
return true;
}
}
@ -1548,7 +1644,7 @@ ipv6nd_env(FILE *fp, const struct interface *ifp)
ia->prefix_vltime == 0)
continue;
if (efprintf(fp, "%s_addr%zu=%s",
ndprefix, j++, ia->saddr) == -1)
ndprefix, ++j, ia->saddr) == -1)
return -1;
}
}
@ -1577,7 +1673,8 @@ ipv6nd_expirera(void *arg)
{
struct interface *ifp;
struct ra *rap, *ran;
struct timespec now, lt, expire, next;
struct timespec now;
uint32_t elapsed;
bool expired, valid;
struct ipv6_addr *ia;
size_t len, olen;
@ -1588,23 +1685,21 @@ ipv6nd_expirera(void *arg)
#endif
struct nd_opt_dnssl dnssl;
struct nd_opt_rdnss rdnss;
uint32_t ltime;
unsigned int next = 0, ltime;
size_t nexpired = 0;
ifp = arg;
clock_gettime(CLOCK_MONOTONIC, &now);
expired = false;
timespecclear(&next);
TAILQ_FOREACH_SAFE(rap, ifp->ctx->ra_routers, next, ran) {
if (rap->iface != ifp || rap->expired)
continue;
valid = false;
if (rap->lifetime) {
lt.tv_sec = (time_t)rap->lifetime;
lt.tv_nsec = 0;
timespecadd(&rap->acquired, &lt, &expire);
if (timespeccmp(&now, &expire, >)) {
elapsed = (uint32_t)eloop_timespec_diff(&now,
&rap->acquired, NULL);
if (elapsed > rap->lifetime || rap->doexpire) {
if (!rap->expired) {
logwarnx("%s: %s: router expired",
ifp->name, rap->sfrom);
@ -1613,10 +1708,9 @@ ipv6nd_expirera(void *arg)
}
} else {
valid = true;
timespecsub(&expire, &now, &lt);
if (!timespecisset(&next) ||
timespeccmp(&next, &lt, >))
next = lt;
ltime = rap->lifetime - elapsed;
if (next == 0 || ltime < next)
next = ltime;
}
}
@ -1626,17 +1720,21 @@ ipv6nd_expirera(void *arg)
TAILQ_FOREACH(ia, &rap->addrs, next) {
if (ia->prefix_vltime == 0)
continue;
if (ia->prefix_vltime == ND6_INFINITE_LIFETIME) {
if (ia->prefix_vltime == ND6_INFINITE_LIFETIME &&
!rap->doexpire)
{
valid = true;
continue;
}
lt.tv_sec = (time_t)ia->prefix_vltime;
lt.tv_nsec = 0;
timespecadd(&ia->acquired, &lt, &expire);
if (timespeccmp(&now, &expire, >)) {
elapsed = (uint32_t)eloop_timespec_diff(&now,
&ia->acquired, NULL);
if (elapsed > ia->prefix_vltime || rap->doexpire) {
if (ia->flags & IPV6_AF_ADDED) {
logwarnx("%s: expired address %s",
ia->iface->name, ia->saddr);
logwarnx("%s: expired %s %s",
ia->iface->name,
ia->flags & IPV6_AF_AUTOCONF ?
"address" : "prefix",
ia->saddr);
if (if_address6(RTM_DELADDR, ia)== -1 &&
errno != EADDRNOTAVAIL &&
errno != ENXIO)
@ -1647,15 +1745,16 @@ ipv6nd_expirera(void *arg)
~(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED);
expired = true;
} else {
timespecsub(&expire, &now, &lt);
if (!timespecisset(&next) ||
timespeccmp(&next, &lt, >))
next = lt;
valid = true;
ltime = ia->prefix_vltime - elapsed;
if (next == 0 || ltime < next)
next = ltime;
}
}
/* Work out expiry for ND options */
elapsed = (uint32_t)eloop_timespec_diff(&now,
&rap->acquired, NULL);
len = rap->data_len - sizeof(struct nd_router_advert);
for (p = rap->data + sizeof(struct nd_router_advert);
len >= sizeof(ndo);
@ -1700,26 +1799,25 @@ ipv6nd_expirera(void *arg)
if (ltime == 0)
continue;
if (rap->doexpire) {
expired = true;
continue;
}
if (ltime == ND6_INFINITE_LIFETIME) {
valid = true;
continue;
}
lt.tv_sec = (time_t)ntohl(ltime);
lt.tv_nsec = 0;
timespecadd(&rap->acquired, &lt, &expire);
if (timespeccmp(&now, &expire, >)) {
ltime = ntohl(ltime);
if (elapsed > ltime) {
expired = true;
continue;
}
timespecsub(&expire, &now, &lt);
if (!timespecisset(&next) ||
timespeccmp(&next, &lt, >))
{
next = lt;
valid = true;
}
valid = true;
ltime -= elapsed;
if (next == 0 || ltime < next)
next = ltime;
}
if (valid)
@ -1731,11 +1829,12 @@ ipv6nd_expirera(void *arg)
ipv6nd_free_ra(rap);
}
if (timespecisset(&next))
eloop_timeout_add_tv(ifp->ctx->eloop,
&next, ipv6nd_expirera, ifp);
if (next != 0)
eloop_timeout_add_sec(ifp->ctx->eloop,
next, ipv6nd_expirera, ifp);
if (expired) {
logwarnx("%s: part of Router Advertisement expired", ifp->name);
logwarnx("%s: part of a Router Advertisement expired",
ifp->name);
rt_build(ifp->ctx, AF_INET6);
script_runreason(ifp, "ROUTERADVERT");
}
@ -1764,7 +1863,7 @@ ipv6nd_drop(struct interface *ifp)
}
}
static void
void
ipv6nd_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg)
{
struct sockaddr_in6 *from = (struct sockaddr_in6 *)msg->msg_name;
@ -1866,17 +1965,19 @@ ipv6nd_startrs1(void *arg)
#endif
}
if (!(IN_PRIVSEP(ifp->ctx))) {
#ifdef __sun
if (ipv6nd_open(ifp) == -1) {
logerr(__func__);
return;
}
if (ipv6nd_open(ifp) == -1) {
logerr(__func__);
return;
}
#else
if (ipv6nd_open(ifp->ctx) == -1) {
logerr(__func__);
return;
}
if (ipv6nd_open(ifp->ctx) == -1) {
logerr(__func__);
return;
}
#endif
}
/* Always make a new probe as the underlying hardware
* address could have changed. */
@ -1894,7 +1995,7 @@ ipv6nd_startrs1(void *arg)
void
ipv6nd_startrs(struct interface *ifp)
{
struct timespec tv;
unsigned int delay;
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
if (!(ifp->options->options & DHCPCD_INITIAL_DELAY)) {
@ -1902,12 +2003,9 @@ ipv6nd_startrs(struct interface *ifp)
return;
}
tv.tv_sec = 0;
tv.tv_nsec = (suseconds_t)arc4random_uniform(
MAX_RTR_SOLICITATION_DELAY * NSEC_PER_SEC);
timespecnorm(&tv);
delay = arc4random_uniform(MAX_RTR_SOLICITATION_DELAY * MSEC_PER_SEC);
logdebugx("%s: delaying IPv6 router solicitation for %0.1f seconds",
ifp->name, timespec_to_double(&tv));
eloop_timeout_add_tv(ifp->ctx->eloop, &tv, ipv6nd_startrs1, ifp);
ifp->name, (float)delay / MSEC_PER_SEC);
eloop_timeout_add_msec(ifp->ctx->eloop, delay, ipv6nd_startrs1, ifp);
return;
}

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* logerr: errx with logging
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2020 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -207,24 +207,20 @@ vlogmessage(int pri, const char *fmt, va_list args)
if (!(ctx->log_opts & LOGERR_LOG))
return len;
#ifdef SMALL
#ifndef SMALL
if (ctx->log_file != NULL &&
(pri != LOG_DEBUG || (ctx->log_opts & LOGERR_DEBUG)))
len = vlogprintf_r(ctx, ctx->log_file, fmt, args);
#endif
vsyslog(pri, fmt, args);
return len;
#else
if (ctx->log_file == NULL) {
vsyslog(pri, fmt, args);
return len;
}
if (pri == LOG_DEBUG && !(ctx->log_opts & LOGERR_DEBUG))
return len;
return vlogprintf_r(ctx, ctx->log_file, fmt, args);
#endif
}
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5))
#pragma GCC diagnostic pop
#endif
__printflike(2, 3) static void
__printflike(2, 3) void
logmessage(int pri, const char *fmt, ...)
{
va_list args;
@ -244,8 +240,18 @@ vlogerrmessage(int pri, const char *fmt, va_list args)
logmessage(pri, "%s: %s", buf, strerror(_errno));
}
__printflike(2, 3) void
logerrmessage(int pri, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vlogerrmessage(pri, fmt, args);
va_end(args);
}
void
logdebug(const char *fmt, ...)
log_debug(const char *fmt, ...)
{
va_list args;
@ -255,7 +261,7 @@ logdebug(const char *fmt, ...)
}
void
logdebugx(const char *fmt, ...)
log_debugx(const char *fmt, ...)
{
va_list args;
@ -265,7 +271,7 @@ logdebugx(const char *fmt, ...)
}
void
loginfo(const char *fmt, ...)
log_info(const char *fmt, ...)
{
va_list args;
@ -275,7 +281,7 @@ loginfo(const char *fmt, ...)
}
void
loginfox(const char *fmt, ...)
log_infox(const char *fmt, ...)
{
va_list args;
@ -285,7 +291,7 @@ loginfox(const char *fmt, ...)
}
void
logwarn(const char *fmt, ...)
log_warn(const char *fmt, ...)
{
va_list args;
@ -295,7 +301,7 @@ logwarn(const char *fmt, ...)
}
void
logwarnx(const char *fmt, ...)
log_warnx(const char *fmt, ...)
{
va_list args;
@ -305,7 +311,7 @@ logwarnx(const char *fmt, ...)
}
void
logerr(const char *fmt, ...)
log_err(const char *fmt, ...)
{
va_list args;
@ -315,7 +321,7 @@ logerr(const char *fmt, ...)
}
void
logerrx(const char *fmt, ...)
log_errx(const char *fmt, ...)
{
va_list args;
@ -324,6 +330,14 @@ logerrx(const char *fmt, ...)
va_end(args);
}
unsigned int
loggetopts(void)
{
struct logctx *ctx = &_logctx;
return ctx->log_opts;
}
void
logsetopts(unsigned int opts)
{

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/* stSPDX-License-Identifier: BSD-2-Clause */
/*
* dhcpcd - DHCP client daemon
* Copyright (c) 2006-2019 Roy Marples <roy@marples.name>
* Copyright (c) 2006-2020 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@ -36,6 +36,7 @@
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <pwd.h>
#include <signal.h>
#include <spawn.h>
#include <stdarg.h>
@ -47,18 +48,15 @@
#include "common.h"
#include "dhcp.h"
#include "dhcp6.h"
#include "eloop.h"
#include "if.h"
#include "if-options.h"
#include "ipv4ll.h"
#include "ipv6nd.h"
#include "logerr.h"
#include "privsep.h"
#include "script.h"
/* Allow the OS to define another script env var name */
#ifndef RC_SVCNAME
#define RC_SVCNAME "RC_SVCNAME"
#endif
#define DEFAULT_PATH "/usr/bin:/usr/sbin:/bin:/sbin"
static const char * const if_params[] = {
@ -85,7 +83,7 @@ if_printoptions(void)
printf(" - %s\n", *p);
}
static int
pid_t
script_exec(const struct dhcpcd_ctx *ctx, char *const *argv, char *const *env)
{
pid_t pid = 0;
@ -173,7 +171,7 @@ efprintf(FILE *fp, const char *fmt, ...)
return r;
}
static char **
char **
script_buftoenv(struct dhcpcd_ctx *ctx, char *buf, size_t len)
{
char **env, **envp, *bufp, *endp;
@ -216,14 +214,14 @@ script_buftoenv(struct dhcpcd_ctx *ctx, char *buf, size_t len)
}
static long
make_env(const struct interface *ifp, const char *reason)
make_env(struct dhcpcd_ctx *ctx, const struct interface *ifp,
const char *reason)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
FILE *fp;
long buf_pos, i;
char *path;
int protocol = PROTO_LINK;
const struct if_options *ifo = ifp->options;
const struct if_options *ifo;
const struct interface *ifp2;
int af;
#ifdef INET
@ -262,6 +260,25 @@ make_env(const struct interface *ifp, const char *reason)
}
#endif
/* Needed for scripts */
path = getenv("PATH");
if (efprintf(fp, "PATH=%s", path == NULL ? DEFAULT_PATH:path) == -1)
goto eexit;
if (efprintf(fp, "reason=%s", reason) == -1)
goto eexit;
if (efprintf(fp, "pid=%d", getpid()) == -1)
goto eexit;
#ifdef PRIVSEP
if (ctx->options & DHCPCD_PRIVSEP && ctx->ps_user != NULL) {
if (efprintf(fp, "chroot=%s", ctx->ps_user->pw_dir) == -1)
goto eexit;
}
if (strcmp(reason, "CHROOT") == 0)
goto make;
#endif
ifo = ifp->options;
#ifdef INET
state = D_STATE(ifp);
#ifdef IPV4LL
@ -272,7 +289,10 @@ make_env(const struct interface *ifp, const char *reason)
d6_state = D6_CSTATE(ifp);
#endif
if (strcmp(reason, "TEST") == 0) {
if (1 == 2) {}
if (1 == 2) {
/* This space left intentionally blank
* as all the below statements are optional. */
}
#ifdef INET6
#ifdef DHCP6
else if (d6_state && d6_state->new)
@ -316,19 +336,11 @@ make_env(const struct interface *ifp, const char *reason)
protocol = PROTO_DHCP;
#endif
/* Needed for scripts */
path = getenv("PATH");
if (efprintf(fp, "PATH=%s", path == NULL ? DEFAULT_PATH:path) == -1)
goto eexit;
if (efprintf(fp, "interface=%s", ifp->name) == -1)
goto eexit;
if (efprintf(fp, "reason=%s", reason) == -1)
goto eexit;
if (ifp->ctx->options & DHCPCD_DUMPLEASE)
goto dumplease;
if (efprintf(fp, "pid=%d", getpid()) == -1)
goto eexit;
if (efprintf(fp, "ifcarrier=%s",
ifp->carrier == LINK_UNKNOWN ? "unknown" :
ifp->carrier == LINK_UP ? "up" : "down") == -1)
@ -492,6 +504,9 @@ dumplease:
goto eexit;
}
#ifdef PRIVSEP
make:
#endif
/* Convert buffer to argv */
fflush(fp);
@ -520,7 +535,7 @@ dumplease:
if (script_buftoenv(ctx, ctx->script_buf, (size_t)buf_pos) == NULL)
goto eexit;
return buf_pos - 1;
return buf_pos;
eexit:
logerr(__func__);
@ -538,16 +553,15 @@ send_interface1(struct fd_list *fd, const struct interface *ifp,
struct dhcpcd_ctx *ctx = ifp->ctx;
long len;
len = make_env(ifp, reason);
len = make_env(ifp->ctx, ifp, reason);
if (len == -1)
return -1;
return control_queue(fd, ctx->script_buf, (size_t)len, 1);
return control_queue(fd, ctx->script_buf, (size_t)len, 1);
}
int
send_interface(struct fd_list *fd, const struct interface *ifp)
send_interface(struct fd_list *fd, const struct interface *ifp, int af)
{
const char *reason;
int retval = 0;
#ifdef INET
const struct dhcp_state *d;
@ -556,80 +570,92 @@ send_interface(struct fd_list *fd, const struct interface *ifp)
const struct dhcp6_state *d6;
#endif
switch (ifp->carrier) {
case LINK_UP:
reason = "CARRIER";
break;
case LINK_DOWN:
case LINK_DOWN_IFFUP:
reason = "NOCARRIER";
break;
default:
reason = "UNKNOWN";
break;
}
if (send_interface1(fd, ifp, reason) == -1)
retval = -1;
#ifdef INET
if (D_STATE_RUNNING(ifp)) {
d = D_CSTATE(ifp);
if (send_interface1(fd, ifp, d->reason) == -1)
retval = -1;
}
#ifdef IPV4LL
if (IPV4LL_STATE_RUNNING(ifp)) {
if (send_interface1(fd, ifp, "IPV4LL") == -1)
retval = -1;
}
#ifndef AF_LINK
#define AF_LINK AF_PACKET
#endif
if (af == AF_UNSPEC || af == AF_LINK) {
const char *reason;
switch (ifp->carrier) {
case LINK_UP:
reason = "CARRIER";
break;
case LINK_DOWN:
case LINK_DOWN_IFFUP:
reason = "NOCARRIER";
break;
default:
reason = "UNKNOWN";
break;
}
if (fd != NULL) {
if (send_interface1(fd, ifp, reason) == -1)
retval = -1;
} else
retval++;
}
#ifdef INET
if (af == AF_UNSPEC || af == AF_INET) {
if (D_STATE_RUNNING(ifp)) {
d = D_CSTATE(ifp);
if (fd != NULL) {
if (send_interface1(fd, ifp, d->reason) == -1)
retval = -1;
} else
retval++;
}
#ifdef IPV4LL
if (IPV4LL_STATE_RUNNING(ifp)) {
if (fd != NULL) {
if (send_interface1(fd, ifp, "IPV4LL") == -1)
retval = -1;
} else
retval++;
}
#endif
}
#endif
#ifdef INET6
if (IPV6_STATE_RUNNING(ifp)) {
if (send_interface1(fd, ifp, "STATIC6") == -1)
retval = -1;
}
if (RS_STATE_RUNNING(ifp)) {
if (send_interface1(fd, ifp, "ROUTERADVERT") == -1)
retval = -1;
}
if (af == AF_UNSPEC || af == AF_INET6) {
if (IPV6_STATE_RUNNING(ifp)) {
if (fd != NULL) {
if (send_interface1(fd, ifp, "STATIC6") == -1)
retval = -1;
} else
retval++;
}
if (RS_STATE_RUNNING(ifp)) {
if (fd != NULL) {
if (send_interface1(fd, ifp,
"ROUTERADVERT") == -1)
retval = -1;
} else
retval++;
}
#ifdef DHCP6
if (D6_STATE_RUNNING(ifp)) {
d6 = D6_CSTATE(ifp);
if (send_interface1(fd, ifp, d6->reason) == -1)
retval = -1;
}
if (D6_STATE_RUNNING(ifp)) {
d6 = D6_CSTATE(ifp);
if (fd != NULL) {
if (send_interface1(fd, ifp, d6->reason) == -1)
retval = -1;
} else
retval++;
}
#endif
}
#endif
return retval;
}
int
script_runreason(const struct interface *ifp, const char *reason)
static int
script_run(struct dhcpcd_ctx *ctx, char **argv)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
char *argv[2];
pid_t pid;
int status = 0;
struct fd_list *fd;
if (ifp->options->script == NULL &&
TAILQ_FIRST(&ifp->ctx->control_fds) == NULL)
return 0;
/* Make our env */
if (make_env(ifp, reason) == -1) {
logerr(__func__);
return -1;
}
if (ifp->options->script == NULL)
goto send_listeners;
argv[0] = ifp->options->script;
argv[1] = NULL;
logdebugx("%s: executing `%s' %s", ifp->name, argv[0], reason);
pid = script_exec(ctx, argv, ctx->script_env);
if (pid == -1)
@ -652,6 +678,45 @@ script_runreason(const struct interface *ifp, const char *reason)
__func__, argv[0], strsignal(WTERMSIG(status)));
}
return WEXITSTATUS(status);
}
int
script_runreason(const struct interface *ifp, const char *reason)
{
struct dhcpcd_ctx *ctx = ifp->ctx;
char *argv[2];
int status = 0;
struct fd_list *fd;
if (ifp->options->script == NULL &&
TAILQ_FIRST(&ifp->ctx->control_fds) == NULL)
return 0;
/* Make our env */
if (make_env(ifp->ctx, ifp, reason) == -1) {
logerr(__func__);
return -1;
}
if (ifp->options->script == NULL)
goto send_listeners;
argv[0] = ifp->options->script;
argv[1] = NULL;
logdebugx("%s: executing `%s' %s", ifp->name, argv[0], reason);
#ifdef PRIVSEP
if (ctx->options & DHCPCD_PRIVSEP) {
if (ps_root_script(ifp,
ctx->script_buf, ctx->script_buflen) == -1)
logerr(__func__);
goto send_listeners;
}
#endif
status = script_run(ctx, argv);
send_listeners:
/* Send to our listeners */
status = 0;
@ -665,5 +730,25 @@ send_listeners:
status = 1;
}
return WEXITSTATUS(status);
return status;
}
#ifdef PRIVSEP
int
script_runchroot(struct dhcpcd_ctx *ctx, char *script)
{
char *argv[2];
/* Make our env */
if (make_env(ctx, NULL, "CHROOT") == -1) {
logerr(__func__);
return -1;
}
argv[0] = script;
argv[1] = NULL;
logdebugx("executing `%s' %s", argv[0], "CHROOT");
return script_run(ctx, argv);
}
#endif