Update to dhcpcd-10.0.7 with the following changes:

* DHCP: use request_time, fallback_time and ipv4ll_time rather than reboot timeout
* DHCP6: Wait for IRT to elapse before requesting advertisments
* DHCPv6: Don't re-INFORM if the RA changes
* privsep: Reduce fd use
* dhcpcd: Add support for arp persist defence
* Move dhcp(v4) packet size check earlier
* Define the Azure Endpoint and other site-specific options
* add RFC4191 support by @goertzenator in #297
* dhcpcd: Respect IPV6_PREFERRED_ONLY flag regardless of state
* Fix time_offset to be int to match RFC-2132
* hooks/30-hostname: Exit with 0 if setting hostname is not needed
This commit is contained in:
roy 2024-05-24 11:28:00 +00:00
parent a7f052dc0d
commit e355904211
26 changed files with 562 additions and 143 deletions

View File

@ -106,8 +106,8 @@ if [ "$ifwireless" = "1" ] && \
command -v wpa_cli >/dev/null 2>&1
then
case "$reason" in
PREINIT) wpa_supplicant_start;;
RECONFIGURE) wpa_supplicant_reconfigure;;
DEPARTED) wpa_supplicant_stop;;
PREINIT) wpa_supplicant_start;;
RECONFIGURE) wpa_supplicant_reconfigure;;
DEPARTED|STOPPED) wpa_supplicant_stop;;
esac
fi

View File

@ -118,7 +118,7 @@ set_hostname()
*) hshort=true;;
esac
need_hostname || return
need_hostname || return 0
if [ -n "$new_fqdn" ]; then
if ${hfqdn} || ! ${hshort}; then

View File

@ -173,12 +173,24 @@ arp_found(struct arp_state *astate, const struct arp_msg *amsg)
* the other IPv4LL client will receieve two ARP
* messages.
* If another conflict happens within DEFEND_INTERVAL
* then we must drop our address and negotiate a new one. */
* then we must drop our address and negotiate a new one.
* If DHCPCD_ARP_PERSISTDEFENCE is set, that enables
* RFC5227 section 2.4.c behaviour. Upon conflict
* detection, the host records the time that the
* conflicting ARP packet was received, and then
* broadcasts one single ARP Announcement. The host then
* continues to use the address normally. All further
* conflict notifications within the DEFEND_INTERVAL are
* ignored. */
clock_gettime(CLOCK_MONOTONIC, &now);
if (timespecisset(&astate->defend) &&
eloop_timespec_diff(&now, &astate->defend, NULL) < DEFEND_INTERVAL)
{
logwarnx("%s: %d second defence failed for %s",
ifp->name, DEFEND_INTERVAL, inet_ntoa(astate->addr));
if (ifp->options->options & DHCPCD_ARP_PERSISTDEFENCE)
return;
}
else if (arp_request(astate, &astate->addr) == -1)
logerr(__func__);
else {

View File

@ -29,7 +29,7 @@
#define DEFS_H
#define PACKAGE "dhcpcd"
#define VERSION "10.0.6"
#define VERSION "10.0.7"
#ifndef PRIVSEP_USER
# define PRIVSEP_USER "_" PACKAGE

View File

@ -1877,13 +1877,13 @@ dhcp_discover(void *arg)
dhcp_new_xid(ifp);
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
if (!(state->added & STATE_EXPIRED)) {
if (ifo->fallback)
if (ifo->fallback && ifo->fallback_time)
eloop_timeout_add_sec(ifp->ctx->eloop,
ifo->reboot, dhcp_fallback, ifp);
ifo->fallback_time, dhcp_fallback, ifp);
#ifdef IPV4LL
else if (ifo->options & DHCPCD_IPV4LL)
eloop_timeout_add_sec(ifp->ctx->eloop,
ifo->reboot, ipv4ll_start, ifp);
ifo->ipv4ll_time, ipv4ll_start, ifp);
#endif
}
if (ifo->options & DHCPCD_REQUEST)
@ -1914,11 +1914,13 @@ dhcp_request(void *arg)
{
struct interface *ifp = arg;
struct dhcp_state *state = D_STATE(ifp);
struct if_options *ifo = ifp->options;
state->state = DHS_REQUEST;
// Handle the server being silent to our request.
eloop_timeout_add_sec(ifp->ctx->eloop, ifp->options->reboot,
dhcp_requestfailed, ifp);
if (ifo->request_time != 0)
eloop_timeout_add_sec(ifp->ctx->eloop, ifo->request_time,
dhcp_requestfailed, ifp);
send_request(ifp);
}
@ -1944,7 +1946,11 @@ dhcp_expire(void *arg)
static void
dhcp_decline(struct interface *ifp)
{
struct dhcp_state *state = D_STATE(ifp);
// Set the expired state so we send over BPF as this could be
// an address defence failure.
state->added |= STATE_EXPIRED;
send_message(ifp, DHCP_DECLINE, NULL);
}
#endif
@ -2098,8 +2104,12 @@ static void
dhcp_arp_defend_failed(struct arp_state *astate)
{
struct interface *ifp = astate->iface;
struct dhcp_state *state = D_STATE(ifp);
if (!(ifp->options->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
dhcp_decline(ifp);
dhcp_drop(ifp, "EXPIRED");
dhcp_unlink(ifp->ctx, state->leasefile);
dhcp_start1(ifp);
}
#endif
@ -2740,7 +2750,7 @@ dhcp_reboot(struct interface *ifp)
/* Need to add this before dhcp_expire and friends. */
if (!ifo->fallback && ifo->options & DHCPCD_IPV4LL)
eloop_timeout_add_sec(ifp->ctx->eloop,
ifo->reboot, ipv4ll_start, ifp);
ifo->ipv4ll_time, ipv4ll_start, ifp);
#endif
if (ifo->options & DHCPCD_LASTLEASE && state->lease.frominfo)
@ -3199,8 +3209,8 @@ dhcp_handledhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len,
if (has_option_mask(ifo->requestmask, DHO_IPV6_PREFERRED_ONLY)) {
if (get_option_uint32(ifp->ctx, &v6only_time, bootp, bootp_len,
DHO_IPV6_PREFERRED_ONLY) == 0 &&
(state->state == DHS_DISCOVER || state->state == DHS_REBOOT))
DHO_IPV6_PREFERRED_ONLY) == 0 && (state->state == DHS_DISCOVER ||
state->state == DHS_REBOOT || state->state == DHS_NONE))
{
char v6msg[128];
@ -3524,12 +3534,6 @@ dhcp_handlebootp(struct interface *ifp, struct bootp *bootp, size_t len,
{
size_t v;
if (len < offsetof(struct bootp, vend)) {
logerrx("%s: truncated packet (%zu) from %s",
ifp->name, len, inet_ntoa(*from));
return;
}
/* Unlikely, but appeases sanitizers. */
if (len > FRAMELEN_MAX) {
logerrx("%s: packet exceeded frame length (%zu) from %s",
@ -3662,6 +3666,13 @@ dhcp_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg)
logerr(__func__);
return;
}
if (iov->iov_len < offsetof(struct bootp, vend)) {
logerrx("%s: truncated packet (%zu) from %s",
ifp->name, iov->iov_len, inet_ntoa(from->sin_addr));
return;
}
state = D_CSTATE(ifp);
if (state == NULL) {
/* Try re-directing it to another interface. */

View File

@ -181,6 +181,7 @@ static void dhcp6_bind(struct interface *, const char *, const char *);
static void dhcp6_failinform(void *);
static void dhcp6_recvaddr(void *, unsigned short);
static void dhcp6_startdecline(struct interface *);
static void dhcp6_startrequest(struct interface *);
#ifdef SMALL
#define dhcp6_hasprefixdelegation(a) (0)
@ -1428,10 +1429,37 @@ dhcp6_sendinform(void *arg)
}
static void
dhcp6_senddiscover(void *arg)
dhcp6_senddiscover2(void *arg)
{
dhcp6_sendmessage(arg, dhcp6_senddiscover);
dhcp6_sendmessage(arg, dhcp6_senddiscover2);
}
static void
dhcp6_senddiscover1(void *arg)
{
/*
* So the initial RT has elapsed.
* If we have any ADVERTs we can now REQUEST them.
* RFC 8415 15 and 18.2.1
*/
struct interface *ifp = arg;
struct dhcp6_state *state = D6_STATE(ifp);
if (state->recv == NULL || state->recv->type != DHCP6_ADVERTISE)
dhcp6_sendmessage(arg, dhcp6_senddiscover2);
else
dhcp6_startrequest(ifp);
}
static void
dhcp6_senddiscover(void *arg)
{
struct interface *ifp = arg;
struct dhcp6_state *state = D6_STATE(ifp);
dhcp6_sendmessage(arg,
state->IMD != 0 ? dhcp6_senddiscover : dhcp6_senddiscover1);
}
static void
@ -1890,7 +1918,6 @@ dhcp6_startrebind(void *arg)
#endif
}
static void
dhcp6_startrequest(struct interface *ifp)
{
@ -3461,6 +3488,16 @@ dhcp6_recvif(struct interface *ifp, const char *sfrom,
valid_op = false;
break;
}
if (state->recv_len && state->recv->type == DHCP6_ADVERTISE) {
/* We already have an advertismemnt.
* RFC 8415 says we have to wait for the IRT to elapse.
* To keep the same behaviour we won't do anything with
* this. In the future we should make a lists of
* ADVERTS and pick the "best" one. */
logdebugx("%s: discarding ADVERTISMENT from %s",
ifp->name, sfrom);
return;
}
/* RFC7083 */
o = dhcp6_findmoption(r, len, D6_OPTION_SOL_MAX_RT, &ol);
if (o && ol == sizeof(uint32_t)) {
@ -3586,7 +3623,7 @@ dhcp6_recvif(struct interface *ifp, const char *sfrom,
else
loginfox("%s: ADV %s from %s",
ifp->name, ia->saddr, sfrom);
dhcp6_startrequest(ifp);
// We will request when the IRT elapses
return;
}
@ -3791,7 +3828,7 @@ dhcp6_openraw(void)
{
int fd, v;
fd = socket(PF_INET6, SOCK_RAW | SOCK_CXNB, IPPROTO_UDP);
fd = xsocket(PF_INET6, SOCK_RAW | SOCK_CXNB, IPPROTO_UDP);
if (fd == -1)
return -1;
@ -3965,20 +4002,16 @@ dhcp6_start(struct interface *ifp, enum DH6S init_state)
case DH6S_INIT:
goto gogogo;
case DH6S_INFORM:
/* RFC 8415 21.23
* If D6_OPTION_INFO_REFRESH_TIME does not exist
* then we MUST refresh by IRT_DEFAULT seconds
* and should not be influenced by only the
* pl/vl time of the RA changing. */
if (state->state == DH6S_INIT ||
state->state == DH6S_INFORMED ||
(state->state == DH6S_DISCOVER &&
!(ifp->options->options & DHCPCD_IA_FORCED) &&
!ipv6nd_hasradhcp(ifp, true)))
{
/* We don't want log spam when the RA
* has just adjusted it's prefix times. */
if (state->state != DH6S_INFORMED) {
state->new_start = true;
state->failed = false;
}
dhcp6_startinform(ifp);
}
break;
case DH6S_REQUEST:
if (ifp->options->options & DHCPCD_DHCP6 &&
@ -4254,6 +4287,7 @@ dhcp6_env(FILE *fp, const char *prefix, const struct interface *ifp,
#ifndef SMALL
const struct dhcp6_state *state;
const struct ipv6_addr *ap;
bool first;
#endif
if (m == NULL)
@ -4355,10 +4389,13 @@ delegated:
return 1;
if (fprintf(fp, "%s_delegated_dhcp6_prefix=", prefix) == -1)
return -1;
first = true;
TAILQ_FOREACH(ap, &state->addrs, next) {
if (ap->delegating_prefix == NULL)
continue;
if (ap != TAILQ_FIRST(&state->addrs)) {
if (first)
first = false;
else {
if (fputc(' ', fp) == EOF)
return -1;
}

View File

@ -118,7 +118,7 @@ const char dhcpcd_embedded_conf[] =
#else
"define 1 request ipaddress subnet_mask\n"
"define 121 rfc3442 classless_static_routes\n"
"define 2 uint32 time_offset\n"
"define 2 int32 time_offset\n"
"define 3 request array ipaddress routers\n"
"define 4 array ipaddress time_servers\n"
"define 5 array ipaddress ien116_name_servers\n"
@ -299,8 +299,37 @@ const char dhcpcd_embedded_conf[] =
"encap 0 string nvt\n"
"encap 1 binhex vpn_id\n"
"encap 255 flag global\n"
"define 245 ipaddress azureendpoint\n"
"define 249 rfc3442 ms_classless_static_routes\n"
"define 252 uri wpad_url\n"
"define 224 binhex site_specific_224\n"
"define 225 binhex site_specific_225\n"
"define 226 binhex site_specific_226\n"
"define 227 binhex site_specific_227\n"
"define 228 binhex site_specific_228\n"
"define 229 binhex site_specific_229\n"
"define 230 binhex site_specific_230\n"
"define 231 binhex site_specific_231\n"
"define 232 binhex site_specific_232\n"
"define 233 binhex site_specific_233\n"
"define 234 binhex site_specific_234\n"
"define 235 binhex site_specific_235\n"
"define 236 binhex site_specific_236\n"
"define 237 binhex site_specific_237\n"
"define 238 binhex site_specific_238\n"
"define 239 binhex site_specific_239\n"
"define 240 binhex site_specific_240\n"
"define 241 binhex site_specific_241\n"
"define 242 binhex site_specific_242\n"
"define 243 binhex site_specific_243\n"
"define 244 binhex site_specific_244\n"
"define 246 binhex site_specific_246\n"
"define 247 binhex site_specific_247\n"
"define 248 binhex site_specific_248\n"
"define 250 binhex site_specific_250\n"
"define 251 binhex site_specific_251\n"
"define 253 binhex site_specific_253\n"
"define 254 binhex site_specific_254\n"
"definend 1 binhex source_address\n"
"definend 2 binhex target_address\n"
"definend 3 index embed prefix_information\n"

View File

@ -30,7 +30,7 @@
#define INITDEFINENDS 6
#define INITDEFINE6S 14
#else
#define INITDEFINES 128
#define INITDEFINES 157
#define INITDEFINENDS 7
#define INITDEFINE6S 74
#endif

View File

@ -401,30 +401,43 @@ dhcpcd_daemonise(struct dhcpcd_ctx *ctx)
}
static void
dhcpcd_drop(struct interface *ifp, int stop)
dhcpcd_drop_af(struct interface *ifp, int stop, int af)
{
if (af == AF_UNSPEC || af == AF_INET6) {
#ifdef DHCP6
dhcp6_drop(ifp, stop ? NULL : "EXPIRE6");
dhcp6_drop(ifp, stop ? NULL : "EXPIRE6");
#endif
#ifdef INET6
ipv6nd_drop(ifp);
ipv6_drop(ifp);
ipv6nd_drop(ifp);
ipv6_drop(ifp);
#endif
}
if (af == AF_UNSPEC || af == AF_INET) {
#ifdef IPV4LL
ipv4ll_drop(ifp);
ipv4ll_drop(ifp);
#endif
#ifdef INET
dhcp_drop(ifp, stop ? "STOP" : "EXPIRE");
dhcp_drop(ifp, stop ? "STOP" : "EXPIRE");
#endif
#ifdef ARP
arp_drop(ifp);
arp_drop(ifp);
}
#endif
#if !defined(DHCP6) && !defined(DHCP)
UNUSED(stop);
#endif
}
static void
dhcpcd_drop(struct interface *ifp, int stop)
{
dhcpcd_drop_af(ifp, stop, AF_UNSPEC);
}
static void
stop_interface(struct interface *ifp, const char *reason)
{
@ -1512,7 +1525,8 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd,
int argc, char **argv)
{
struct interface *ifp;
unsigned long long opts;
struct if_options *ifo;
unsigned long long opts, orig_opts;
int opt, oi, oifind, do_reboot, do_renew, af = AF_UNSPEC;
size_t len, l, nifaces;
char *tmp, *p;
@ -1641,20 +1655,40 @@ dumperr:
}
if (opts & (DHCPCD_EXITING | DHCPCD_RELEASE)) {
if (oifind == argc) {
if (oifind == argc && af == AF_UNSPEC) {
stop_all_interfaces(ctx, opts);
eloop_exit(ctx->eloop, EXIT_SUCCESS);
return 0;
}
for (oi = oifind; oi < argc; oi++) {
if ((ifp = if_find(ctx->ifaces, argv[oi])) == NULL)
continue;
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
if (!ifp->active)
continue;
ifp->options->options |= opts;
for (oi = oifind; oi < argc; oi++) {
if (strcmp(ifp->name, argv[oi]) == 0)
break;
}
if (oi == argc)
continue;
ifo = ifp->options;
orig_opts = ifo->options;
ifo->options |= opts;
if (opts & DHCPCD_RELEASE)
ifp->options->options &= ~DHCPCD_PERSISTENT;
stop_interface(ifp, NULL);
ifo->options &= ~DHCPCD_PERSISTENT;
switch (af) {
case AF_INET:
ifo->options &= ~DHCPCD_IPV4;
break;
case AF_INET6:
ifo->options &= ~DHCPCD_IPV6;
break;
}
if (af != AF_UNSPEC)
dhcpcd_drop_af(ifp, 1, af);
else
stop_interface(ifp, NULL);
ifo->options = orig_opts;
}
return 0;
}
@ -1947,6 +1981,7 @@ main(int argc, char **argv, char **envp)
}
memset(&ctx, 0, sizeof(ctx));
closefrom(STDERR_FILENO + 1);
ifo = NULL;
ctx.cffile = CONFIG;
@ -1976,7 +2011,7 @@ main(int argc, char **argv, char **envp)
ctx.dhcp6_wfd = -1;
#endif
#ifdef PRIVSEP
ctx.ps_log_fd = -1;
ctx.ps_log_fd = ctx.ps_log_root_fd = -1;
TAILQ_INIT(&ctx.ps_processes);
#endif
@ -2173,11 +2208,11 @@ printpidfile:
ctx.options |= DHCPCD_MANAGER;
/*
* If we are given any interfaces, we
* If we are given any interfaces or a family, we
* cannot send a signal as that would impact
* other interfaces.
*/
if (optind != argc)
if (optind != argc || family != AF_UNSPEC)
sig = 0;
}
if (ctx.options & DHCPCD_PRINT_PIDFILE) {
@ -2427,9 +2462,14 @@ printpidfile:
goto run_loop;
}
#ifdef DEBUG_FD
loginfox("forkfd %d", ctx.fork_fd);
#endif
/* We have now forked, setsid, forked once more.
* From this point on, we are the controlling daemon. */
logdebugx("spawned manager process on PID %d", getpid());
start_manager:
ctx.options |= DHCPCD_STARTED;
if ((pid = pidfile_lock(ctx.pidfile)) != 0) {
@ -2647,10 +2687,6 @@ exit1:
free(ctx.script_env);
rt_dispose(&ctx);
free(ctx.duid);
if (ctx.link_fd != -1) {
eloop_event_delete(ctx.eloop, ctx.link_fd);
close(ctx.link_fd);
}
if_closesockets(&ctx);
free_globals(&ctx);
#ifdef INET6

View File

@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd December 18, 2023
.Dd May 24, 2024
.Dt DHCPCD.CONF 5
.Os
.Sh NAME
@ -305,6 +305,10 @@ You can use this option to stop this from happening.
.It Ic fallback Ar profile
Fall back to using this profile if DHCP fails.
This allows you to configure a static profile instead of using ZeroConf.
.It Ic fallback_time Ar seconds
Start fallback after
.Ar seconds .
The default is 5 seconds.
.It Ic hostname Ar name
Sends the hostname
.Ar name
@ -442,6 +446,11 @@ encodes the FQDN hostname as specified in
.It Ic interface Ar interface
Subsequent options are only parsed for this
.Ar interface .
.It Ic ipv4ll_time Ar seconds
Wait for
.Ar seconds
before starting IPv4LL.
The default is 5 seconds.
.It Ic ipv6ra_autoconf
Generate SLAAC addresses for each Prefix advertised by an IPv6
Router Advertisement message with the Auto flag set.
@ -510,6 +519,8 @@ adding a new IPv4 address.
.It Ic noarp
Don't send any ARP requests.
This also disables IPv4LL.
.It Ic arp_persistdefence
Keep the IP address even if defence fails upon IP Address conflict.
.It Ic noauthrequired
Don't require authentication even though we requested it.
Also allows FORCERENEW and RECONFIGURE messages without authentication.
@ -647,6 +658,11 @@ Use
.Ar script
instead of the default
.Pa /libexec/dhcpcd-run-hooks .
.It Ic request_time Ar seconds
Request the lease for
.Ar seconds
before going back to DISCOVER.
The default is 180 seconds.
.It Ic ssid Ar ssid
Subsequent options are only parsed for this wireless
.Ar ssid .

View File

@ -197,6 +197,18 @@ if_opensockets_os(struct dhcpcd_ctx *ctx)
&n, sizeof(n)) == -1)
logerr("%s: SO_USELOOPBACK", __func__);
#ifdef PRIVSEP
if (ctx->options & DHCPCD_PRIVSEPROOT) {
/* We only want to write to this socket, so set
* a small as possible buffer size. */
socklen_t smallbuf = 1;
if (setsockopt(ctx->link_fd, SOL_SOCKET, SO_RCVBUF,
&smallbuf, (socklen_t)sizeof(smallbuf)) == -1)
logerr("%s: setsockopt(SO_RCVBUF)", __func__);
}
#endif
#if defined(RO_MSGFILTER)
if (setsockopt(ctx->link_fd, PF_ROUTE, RO_MSGFILTER,
&msgfilter, sizeof(msgfilter)) == -1)
@ -220,9 +232,8 @@ if_opensockets_os(struct dhcpcd_ctx *ctx)
ps_rights_limit_fd_sockopt(ctx->link_fd);
#endif
#if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
priv->pf_link_fd = socket(PF_LINK, SOCK_DGRAM, 0);
priv->pf_link_fd = xsocket(PF_LINK, SOCK_DGRAM, 0);
if (priv->pf_link_fd == -1)
logerr("%s: socket(PF_LINK)", __func__);
#endif
@ -235,13 +246,20 @@ if_closesockets_os(struct dhcpcd_ctx *ctx)
struct priv *priv;
priv = (struct priv *)ctx->priv;
if (priv == NULL)
return;
#ifdef INET6
if (priv->pf_inet6_fd != -1)
if (priv->pf_inet6_fd != -1) {
close(priv->pf_inet6_fd);
priv->pf_inet6_fd = -1;
}
#endif
#if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) /*NetBSD */
if (priv->pf_link_fd != -1)
if (priv->pf_link_fd != -1) {
close(priv->pf_link_fd);
priv->pf_link_fd = -1;
}
#endif
free(priv);
ctx->priv = NULL;

View File

@ -168,6 +168,10 @@ const struct option cf_options[] = {
{"link_rcvbuf", required_argument, NULL, O_LINK_RCVBUF},
{"configure", no_argument, NULL, O_CONFIGURE},
{"noconfigure", no_argument, NULL, O_NOCONFIGURE},
{"arp_persistdefence", no_argument, NULL, O_ARP_PERSISTDEFENCE},
{"request_time", required_argument, NULL, O_REQUEST_TIME},
{"fallback_time", required_argument, NULL, O_FALLBACK_TIME},
{"ipv4ll_time", required_argument, NULL, O_IPV4LL_TIME},
{NULL, 0, NULL, '\0'}
};
@ -2337,6 +2341,38 @@ invalid_token:
case O_NOCONFIGURE:
ifo->options &= ~DHCPCD_CONFIGURE;
break;
case O_ARP_PERSISTDEFENCE:
ifo->options |= DHCPCD_ARP_PERSISTDEFENCE;
break;
case O_REQUEST_TIME:
ARG_REQUIRED;
ifo->request_time =
(uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
if (e) {
logerrx("invalid request time: %s", arg);
return -1;
}
break;
#ifdef INET
case O_FALLBACK_TIME:
ARG_REQUIRED;
ifo->request_time =
(uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
if (e) {
logerrx("invalid fallback time: %s", arg);
return -1;
}
break;
case O_IPV4LL_TIME:
ARG_REQUIRED;
ifo->ipv4ll_time =
(uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
if (e) {
logerrx("invalid ipv4ll time: %s", arg);
return -1;
}
break;
#endif
default:
return 0;
}
@ -2420,6 +2456,11 @@ default_config(struct dhcpcd_ctx *ctx)
ifo->options |= DHCPCD_IF_UP | DHCPCD_LINK | DHCPCD_INITIAL_DELAY;
ifo->timeout = DEFAULT_TIMEOUT;
ifo->reboot = DEFAULT_REBOOT;
ifo->request_time = DEFAULT_REQUEST;
#ifdef INET
ifo->fallback_time = DEFAULT_FALLBACK;
ifo->ipv4ll_time = DEFAULT_IPV4LL;
#endif
ifo->metric = -1;
ifo->auth.options |= DHCPCD_AUTH_REQUIRE;
rb_tree_init(&ifo->routes, &rt_compare_list_ops);
@ -2461,7 +2502,7 @@ read_config(struct dhcpcd_ctx *ctx,
default_options |= DHCPCD_CONFIGURE | DHCPCD_DAEMONISE |
DHCPCD_GATEWAY;
#ifdef INET
skip = socket(PF_INET, SOCK_DGRAM, 0);
skip = xsocket(PF_INET, SOCK_DGRAM, 0);
if (skip != -1) {
close(skip);
default_options |= DHCPCD_IPV4 | DHCPCD_ARP |
@ -2469,7 +2510,7 @@ read_config(struct dhcpcd_ctx *ctx,
}
#endif
#ifdef INET6
skip = socket(PF_INET6, SOCK_DGRAM, 0);
skip = xsocket(PF_INET6, SOCK_DGRAM, 0);
if (skip != -1) {
close(skip);
default_options |= DHCPCD_IPV6 | DHCPCD_IPV6RS |

View File

@ -49,6 +49,9 @@
#define DEFAULT_TIMEOUT 30
#define DEFAULT_REBOOT 5
#define DEFAULT_REQUEST 180 /* secs to request, mirror DHCP6 */
#define DEFAULT_FALLBACK 5 /* secs until fallback */
#define DEFAULT_IPV4LL 5 /* secs until ipv4ll */
#ifndef HOSTNAME_MAX_LEN
#define HOSTNAME_MAX_LEN 250 /* 255 - 3 (FQDN) - 2 (DNS enc) */
@ -65,6 +68,7 @@
#define DHCPCD_GATEWAY (1ULL << 3)
#define DHCPCD_STATIC (1ULL << 4)
#define DHCPCD_DEBUG (1ULL << 5)
#define DHCPCD_ARP_PERSISTDEFENCE (1ULL << 6)
#define DHCPCD_LASTLEASE (1ULL << 7)
#define DHCPCD_INFORM (1ULL << 8)
#define DHCPCD_REQUEST (1ULL << 9)
@ -183,6 +187,10 @@
#define O_CONFIGURE O_BASE + 50
#define O_NOCONFIGURE O_BASE + 51
#define O_RANDOMISE_HWADDR O_BASE + 52
#define O_ARP_PERSISTDEFENCE O_BASE + 53
#define O_REQUEST_TIME O_BASE + 54
#define O_FALLBACK_TIME O_BASE + 55
#define O_IPV4LL_TIME O_BASE + 56
extern const struct option cf_options[];
@ -234,6 +242,9 @@ struct if_options {
uint32_t leasetime;
uint32_t timeout;
uint32_t reboot;
uint32_t request_time;
uint32_t fallback_time;
uint32_t ipv4ll_time;
unsigned long long options;
bool randomise_hwaddr;

View File

@ -132,17 +132,18 @@ void
if_closesockets(struct dhcpcd_ctx *ctx)
{
if (ctx->pf_inet_fd != -1)
close(ctx->pf_inet_fd);
#ifdef PF_LINK
if (ctx->pf_link_fd != -1)
close(ctx->pf_link_fd);
#endif
if (ctx->priv) {
if_closesockets_os(ctx);
free(ctx->priv);
if (ctx->link_fd != -1) {
eloop_event_delete(ctx->eloop, ctx->link_fd);
close(ctx->link_fd);
ctx->link_fd = -1;
}
if (ctx->pf_inet_fd != -1) {
close(ctx->pf_inet_fd);
ctx->pf_inet_fd = -1;
}
if_closesockets_os(ctx);
}
int
@ -982,6 +983,10 @@ xsocket(int domain, int type, int protocol)
if ((s = socket(domain, type, protocol)) == -1)
return -1;
#ifdef DEBUG_FD
logerrx("pid %d fd=%d domain=%d type=%d protocol=%d",
getpid(), s, domain, type, protocol);
#endif
#ifndef HAVE_SOCK_CLOEXEC
if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(s, F_GETFD)) == -1 ||
@ -1023,6 +1028,10 @@ xsocketpair(int domain, int type, int protocol, int fd[2])
if ((s = socketpair(domain, type, protocol, fd)) == -1)
return -1;
#ifdef DEBUG_FD
logerrx("pid %d fd[0]=%d fd[1]=%d", getpid(), fd[0], fd[1]);
#endif
#ifndef HAVE_SOCK_CLOEXEC
if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(fd[0], F_GETFD)) == -1 ||
fcntl(fd[0], F_SETFD, xflags | FD_CLOEXEC) == -1))

View File

@ -2318,7 +2318,9 @@ inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
{
struct rt *rt;
struct ra *rap;
const struct routeinfo *rinfo;
const struct ipv6_addr *addr;
struct in6_addr netmask;
if (ctx->ra_routers == NULL)
return 0;
@ -2326,6 +2328,27 @@ inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
TAILQ_FOREACH(rap, ctx->ra_routers, next) {
if (rap->expired)
continue;
/* add rfc4191 route information routes */
TAILQ_FOREACH (rinfo, &rap->rinfos, next) {
if(rinfo->lifetime == 0)
continue;
if ((rt = inet6_makeroute(rap->iface, rap)) == NULL)
continue;
in6_addr_fromprefix(&netmask, rinfo->prefix_len);
sa_in6_init(&rt->rt_dest, &rinfo->prefix);
sa_in6_init(&rt->rt_netmask, &netmask);
sa_in6_init(&rt->rt_gateway, &rap->from);
#ifdef HAVE_ROUTE_PREF
rt->rt_pref = ipv6nd_rtpref(rinfo->flags);
#endif
rt_proto_add(routes, rt);
}
/* add subnet routes */
TAILQ_FOREACH(addr, &rap->addrs, next) {
if (addr->prefix_vltime == 0)
continue;
@ -2333,11 +2356,13 @@ inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
if (rt) {
rt->rt_dflags |= RTDF_RA;
#ifdef HAVE_ROUTE_PREF
rt->rt_pref = ipv6nd_rtpref(rap);
rt->rt_pref = ipv6nd_rtpref(rap->flags);
#endif
rt_proto_add(routes, rt);
}
}
/* add default route */
if (rap->lifetime == 0)
continue;
if (ipv6_anyglobal(rap->iface) == NULL)
@ -2347,7 +2372,7 @@ inet6_raroutes(rb_tree_t *routes, struct dhcpcd_ctx *ctx)
continue;
rt->rt_dflags |= RTDF_RA;
#ifdef HAVE_ROUTE_PREF
rt->rt_pref = ipv6nd_rtpref(rap);
rt->rt_pref = ipv6nd_rtpref(rap->flags);
#endif
rt_proto_add(routes, rt);
}

View File

@ -71,6 +71,20 @@
#define ND_OPT_PI_FLAG_ROUTER 0x20 /* Router flag in PI */
#endif
#ifndef ND_OPT_RI
#define ND_OPT_RI 24
struct nd_opt_ri { /* Route Information option RFC4191 */
uint8_t nd_opt_ri_type;
uint8_t nd_opt_ri_len;
uint8_t nd_opt_ri_prefixlen;
uint8_t nd_opt_ri_flags_reserved;
uint32_t nd_opt_ri_lifetime;
struct in6_addr nd_opt_ri_prefix;
};
__CTASSERT(sizeof(struct nd_opt_ri) == 24);
#define OPT_RI_FLAG_PREFERENCE(flags) ((flags & 0x18) >> 3)
#endif
#ifndef ND_OPT_RDNSS
#define ND_OPT_RDNSS 25
struct nd_opt_rdnss { /* RDNSS option RFC 6106 */
@ -132,6 +146,8 @@ __CTASSERT(sizeof(struct nd_opt_dnssl) == 8);
//
static void ipv6nd_handledata(void *, unsigned short);
static struct routeinfo *routeinfo_findalloc(struct ra *, const struct in6_addr *, uint8_t);
static void routeinfohead_free(struct routeinfohead *);
/*
* Android ships buggy ICMP6 filter headers.
@ -612,10 +628,10 @@ ipv6nd_startexpire(struct interface *ifp)
}
int
ipv6nd_rtpref(struct ra *rap)
ipv6nd_rtpref(uint8_t flags)
{
switch (rap->flags & ND_RA_FLAG_RTPREF_MASK) {
switch (flags & ND_RA_FLAG_RTPREF_MASK) {
case ND_RA_FLAG_RTPREF_HIGH:
return RTPREF_HIGH;
case ND_RA_FLAG_RTPREF_MEDIUM:
@ -624,7 +640,7 @@ ipv6nd_rtpref(struct ra *rap)
case ND_RA_FLAG_RTPREF_LOW:
return RTPREF_LOW;
default:
logerrx("%s: impossible RA flag %x", __func__, rap->flags);
logerrx("%s: impossible RA flag %x", __func__, flags);
return RTPREF_INVALID;
}
/* NOTREACHED */
@ -649,7 +665,7 @@ ipv6nd_sortrouters(struct dhcpcd_ctx *ctx)
continue;
if (!ra1->isreachable && ra2->reachable)
continue;
if (ipv6nd_rtpref(ra1) <= ipv6nd_rtpref(ra2))
if (ipv6nd_rtpref(ra1->flags) <= ipv6nd_rtpref(ra2->flags))
continue;
/* All things being equal, prefer older routers. */
/* We don't need to check time, becase newer
@ -827,6 +843,7 @@ ipv6nd_removefreedrop_ra(struct ra *rap, int remove_ra, int drop_ra)
if (remove_ra)
TAILQ_REMOVE(rap->iface->ctx->ra_routers, rap, next);
ipv6_freedrop_addrs(&rap->addrs, drop_ra, NULL);
routeinfohead_free(&rap->rinfos);
free(rap->data);
free(rap);
}
@ -1105,6 +1122,8 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
struct nd_opt_prefix_info pi;
struct nd_opt_mtu mtu;
struct nd_opt_rdnss rdnss;
struct nd_opt_ri ri;
struct routeinfo *rinfo;
uint8_t *p;
struct ra *rap;
struct in6_addr pi_prefix;
@ -1206,6 +1225,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
rap->from = from->sin6_addr;
strlcpy(rap->sfrom, sfrom, sizeof(rap->sfrom));
TAILQ_INIT(&rap->addrs);
TAILQ_INIT(&rap->rinfos);
new_rap = true;
rap->isreachable = true;
} else
@ -1237,9 +1257,6 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
rap->flags = nd_ra->nd_ra_flags_reserved;
old_lifetime = rap->lifetime;
rap->lifetime = ntohs(nd_ra->nd_ra_router_lifetime);
if (!new_rap && rap->lifetime == 0 && old_lifetime != 0)
logwarnx("%s: %s: no longer a default router (lifetime = 0)",
ifp->name, rap->sfrom);
if (nd_ra->nd_ra_curhoplimit != 0)
rap->hoplimit = nd_ra->nd_ra_curhoplimit;
else
@ -1502,6 +1519,46 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
rdnss.nd_opt_rdnss_len > 1)
rap->hasdns = 1;
break;
case ND_OPT_RI:
if (ndo.nd_opt_len > 3) {
logmessage(loglevel, "%s: invalid route info option",
ifp->name);
break;
}
memset(&ri, 0, sizeof(ri));
memcpy(&ri, p, olen); /* may be smaller than sizeof(ri), pad with zero */
if(ri.nd_opt_ri_prefixlen > 128) {
logmessage(loglevel, "%s: invalid route info prefix length",
ifp->name);
break;
}
/* rfc4191 3.1 - RI for ::/0 applies to default route */
if(ri.nd_opt_ri_prefixlen == 0) {
rap->lifetime = ntohl(ri.nd_opt_ri_lifetime);
/* Update preference leaving other flags intact */
rap->flags = ((rap->flags & (~ (unsigned int)ND_RA_FLAG_RTPREF_MASK))
| ri.nd_opt_ri_flags_reserved) & 0xff;
break;
}
/* Update existing route info instead of rebuilding all routes so that
previously announced but now absent routes can stay alive. To kill a
route early, an RI with lifetime=0 needs to be received (rfc4191 3.1)*/
rinfo = routeinfo_findalloc(rap, &ri.nd_opt_ri_prefix, ri.nd_opt_ri_prefixlen);
if(rinfo == NULL) {
logerr(__func__);
break;
}
/* Update/initialize other route info params */
rinfo->flags = ri.nd_opt_ri_flags_reserved;
rinfo->lifetime = ntohl(ri.nd_opt_ri_lifetime);
rinfo->acquired = rap->acquired;
break;
default:
continue;
}
@ -1537,6 +1594,10 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx,
ia->prefix_pltime = 0;
}
if (!new_rap && rap->lifetime == 0 && old_lifetime != 0)
logwarnx("%s: %s: no longer a default router (lifetime = 0)",
ifp->name, rap->sfrom);
if (new_data && !has_address && rap->lifetime && !ipv6_anyglobal(ifp))
logwarnx("%s: no global addresses for default route",
ifp->name);
@ -1699,7 +1760,7 @@ ipv6nd_env(FILE *fp, const struct interface *ifp)
return -1;
if (efprintf(fp, "%s_hoplimit=%u", ndprefix, rap->hoplimit) == -1)
return -1;
pref = ipv6nd_rtpref(rap);
pref = ipv6nd_rtpref(rap->flags);
if (efprintf(fp, "%s_flags=%s%s%s%s%s", ndprefix,
rap->flags & ND_RA_FLAG_MANAGED ? "M" : "",
rap->flags & ND_RA_FLAG_OTHER ? "O" : "",
@ -1804,6 +1865,7 @@ ipv6nd_expirera(void *arg)
uint32_t elapsed;
bool expired, valid;
struct ipv6_addr *ia;
struct routeinfo *rinfo, *rinfob;
size_t len, olen;
uint8_t *p;
struct nd_opt_hdr ndo;
@ -1823,7 +1885,8 @@ ipv6nd_expirera(void *arg)
if (rap->iface != ifp || rap->expired)
continue;
valid = false;
if (rap->lifetime) {
/* lifetime may be set to infinite by rfc4191 route information */
if (rap->lifetime && rap->lifetime != ND6_INFINITE_LIFETIME) {
elapsed = (uint32_t)eloop_timespec_diff(&now,
&rap->acquired, NULL);
if (elapsed >= rap->lifetime || rap->doexpire) {
@ -1879,6 +1942,20 @@ ipv6nd_expirera(void *arg)
}
}
/* Expire route information */
TAILQ_FOREACH_SAFE(rinfo, &rap->rinfos, next, rinfob) {
if (rinfo->lifetime == ND6_INFINITE_LIFETIME &&
!rap->doexpire)
continue;
elapsed = (uint32_t)eloop_timespec_diff(&now,
&rinfo->acquired, NULL);
if (elapsed >= rinfo->lifetime || rap->doexpire) {
logwarnx("%s: expired route %s",
rap->iface->name, rinfo->sprefix);
TAILQ_REMOVE(&rap->rinfos, rinfo, next);
}
}
/* Work out expiry for ND options */
elapsed = (uint32_t)eloop_timespec_diff(&now,
&rap->acquired, NULL);
@ -2135,3 +2212,43 @@ ipv6nd_startrs(struct interface *ifp)
eloop_timeout_add_msec(ifp->ctx->eloop, delay, ipv6nd_startrs1, ifp);
return;
}
static struct routeinfo *routeinfo_findalloc(struct ra *rap, const struct in6_addr *prefix, uint8_t prefix_len)
{
struct routeinfo *ri;
char buf[INET6_ADDRSTRLEN];
const char *p;
TAILQ_FOREACH(ri, &rap->rinfos, next) {
if (ri->prefix_len == prefix_len &&
IN6_ARE_ADDR_EQUAL(&ri->prefix, prefix))
return ri;
}
ri = malloc(sizeof(struct routeinfo));
if (ri == NULL)
return NULL;
memcpy(&ri->prefix, prefix, sizeof(ri->prefix));
ri->prefix_len = prefix_len;
p = inet_ntop(AF_INET6, prefix, buf, sizeof(buf));
if (p)
snprintf(ri->sprefix,
sizeof(ri->sprefix),
"%s/%d",
p, prefix_len);
else
ri->sprefix[0] = '\0';
TAILQ_INSERT_TAIL(&rap->rinfos, ri, next);
return ri;
}
static void routeinfohead_free(struct routeinfohead *head)
{
struct routeinfo *ri;
while ((ri = TAILQ_FIRST(head))) {
TAILQ_REMOVE(head, ri, next);
free(ri);
}
}

View File

@ -37,6 +37,20 @@
#include "dhcpcd.h"
#include "ipv6.h"
/* rfc4191 */
struct routeinfo {
TAILQ_ENTRY(routeinfo) next;
struct in6_addr prefix;
uint8_t prefix_len;
uint32_t lifetime;
uint8_t flags;
struct timespec acquired;
char sprefix[INET6_ADDRSTRLEN];
};
TAILQ_HEAD(routeinfohead, routeinfo);
struct ra {
TAILQ_ENTRY(ra) next;
struct interface *iface;
@ -45,13 +59,14 @@ struct ra {
uint8_t *data;
size_t data_len;
struct timespec acquired;
unsigned char flags;
uint8_t flags;
uint32_t lifetime;
uint32_t reachable;
uint32_t retrans;
uint32_t mtu;
uint8_t hoplimit;
struct ipv6_addrhead addrs;
struct routeinfohead rinfos;
bool hasdns;
bool expired;
bool willexpire;
@ -105,7 +120,7 @@ int ipv6nd_open(bool);
int ipv6nd_openif(struct interface *);
#endif
void ipv6nd_recvmsg(struct dhcpcd_ctx *, struct msghdr *);
int ipv6nd_rtpref(struct ra *);
int ipv6nd_rtpref(uint8_t);
void ipv6nd_printoptions(const struct dhcpcd_ctx *,
const struct dhcp_opt *, size_t);
void ipv6nd_startrs(struct interface *);

View File

@ -376,6 +376,8 @@ logsetfd(int fd)
struct logctx *ctx = &_logctx;
ctx->log_fd = fd;
if (fd != -1)
closelog();
#ifndef SMALL
if (fd != -1 && ctx->log_file != NULL) {
fclose(ctx->log_file);

View File

@ -53,6 +53,8 @@
#include "logerr.h"
#include "privsep.h"
/* We expect to have open 3 SEQPACKET and one RAW fd */
static void
ps_bpf_recvbpf(void *arg, unsigned short events)
{
@ -160,6 +162,9 @@ ps_bpf_start_bpf(struct ps_process *psp)
ps_freeprocesses(ctx, psp);
psp->psp_bpf = bpf_open(&psp->psp_ifp, psp->psp_filter, ia);
#ifdef DEBUG_FD
logdebugx("pid %d bpf_fd=%d", getpid(), psp->psp_bpf->bpf_fd);
#endif
if (psp->psp_bpf == NULL)
logerr("%s: bpf_open",__func__);
#ifdef PRIVSEP_RIGHTS

View File

@ -36,6 +36,8 @@
#include "logerr.h"
#include "privsep.h"
/* We expect to have open 2 SEQPACKET, 2 STREAM and 2 file STREAM fds */
static int
ps_ctl_startcb(struct ps_process *psp)
{
@ -217,14 +219,16 @@ ps_ctl_start(struct dhcpcd_ctx *ctx)
.psi_cmd = PS_CTL,
};
struct ps_process *psp;
int data_fd[2], listen_fd[2];
int work_fd[2], listen_fd[2];
pid_t pid;
if (xsocketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, data_fd) == -1 ||
if_closesockets(ctx);
if (xsocketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, work_fd) == -1 ||
xsocketpair(AF_UNIX, SOCK_STREAM | SOCK_CXNB, 0, listen_fd) == -1)
return -1;
#ifdef PRIVSEP_RIGHTS
if (ps_rights_limit_fdpair(data_fd) == -1 ||
if (ps_rights_limit_fdpair(work_fd) == -1 ||
ps_rights_limit_fdpair(listen_fd) == -1)
return -1;
#endif
@ -237,24 +241,25 @@ ps_ctl_start(struct dhcpcd_ctx *ctx)
if (pid == -1)
return -1;
else if (pid != 0) {
psp->psp_work_fd = data_fd[1];
close(data_fd[0]);
psp->psp_work_fd = work_fd[0];
close(work_fd[1]);
close(listen_fd[1]);
ctx->ps_control = control_new(ctx,
listen_fd[1], FD_SENDLEN | FD_LISTEN);
listen_fd[0], FD_SENDLEN | FD_LISTEN);
if (ctx->ps_control == NULL)
return -1;
close(listen_fd[0]);
return pid;
}
psp->psp_work_fd = data_fd[0];
close(data_fd[1]);
close(work_fd[0]);
close(listen_fd[0]);
psp->psp_work_fd = work_fd[1];
if (eloop_event_add(ctx->eloop, psp->psp_work_fd, ELE_READ,
ps_ctl_recv, ctx) == -1)
return -1;
ctx->ps_control = control_new(ctx, listen_fd[0], 0);
close(listen_fd[1]);
ctx->ps_control = control_new(ctx, listen_fd[1], 0);
if (ctx->ps_control == NULL)
return -1;
if (eloop_event_add(ctx->eloop, ctx->ps_control->fd, ELE_READ,

View File

@ -47,6 +47,8 @@
#include "logerr.h"
#include "privsep.h"
/* We expect to have open 2 SEQPACKET, 1 udp, 1 udp6 and 1 raw6 fds */
#ifdef INET
static void
ps_inet_recvbootp(void *arg, unsigned short events)

View File

@ -259,7 +259,7 @@ ps_root_doioctl(unsigned long req, void *data, size_t len)
return -1;
}
s = socket(PF_INET, SOCK_DGRAM, 0);
s = xsocket(PF_INET, SOCK_DGRAM, 0);
if (s != -1)
#ifdef IOCTL_REQUEST_TYPE
{
@ -685,17 +685,6 @@ ps_root_startcb(struct ps_process *psp)
if (if_opensockets(ctx) == -1)
logerr("%s: if_opensockets", __func__);
#ifdef BSD
else {
/* We only want to write to this socket, so set
* a small as possible buffer size. */
socklen_t smallbuf = 1;
if (setsockopt(ctx->link_fd, SOL_SOCKET, SO_RCVBUF,
&smallbuf, (socklen_t)sizeof(smallbuf)) == -1)
logerr("%s: setsockopt(SO_RCVBUF)", __func__);
}
#endif
/* Open network sockets for sending.
* This is a small bit wasteful for non sandboxed OS's
@ -899,7 +888,7 @@ ps_root_start(struct dhcpcd_ctx *ctx)
return -1;
#endif
if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CXNB, 0, datafd) == -1)
if (xsocketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CXNB, 0, datafd) == -1)
return -1;
if (ps_setbuf_fdpair(datafd) == -1)
return -1;
@ -937,6 +926,32 @@ ps_root_start(struct dhcpcd_ctx *ctx)
return pid;
}
void
ps_root_close(struct dhcpcd_ctx *ctx)
{
if_closesockets(ctx);
#ifdef INET
if (ctx->udp_wfd != -1) {
close(ctx->udp_wfd);
ctx->udp_wfd = -1;
}
#endif
#ifdef INET6
if (ctx->nd_fd != -1) {
close(ctx->nd_fd);
ctx->nd_fd = -1;
}
#endif
#ifdef DHCP6
if (ctx->dhcp6_wfd != -1) {
close(ctx->dhcp6_wfd);
ctx->dhcp6_wfd = -1;
}
#endif
}
int
ps_root_stop(struct dhcpcd_ctx *ctx)
{

View File

@ -36,6 +36,7 @@
#endif
pid_t ps_root_start(struct dhcpcd_ctx *ctx);
void ps_root_close(struct dhcpcd_ctx *ctx);
int ps_root_stop(struct dhcpcd_ctx *ctx);
void ps_root_signalcb(int, void *);

View File

@ -408,15 +408,23 @@ ps_startprocess(struct ps_process *psp,
return pid;
}
/* If we are not the root process, close un-needed stuff. */
if (ctx->ps_root != psp) {
ps_root_close(ctx);
#ifdef PLUGIN_DEV
/* If we are not the root process, stop listening to devices. */
if (ctx->ps_root != psp)
dev_stop(ctx);
#endif
}
ctx->options |= DHCPCD_FORKED;
if (ctx->ps_log_fd != -1)
logsetfd(ctx->ps_log_fd);
#ifdef DEBUG_FD
logerrx("pid %d log_fd=%d data_fd=%d psp_fd=%d",
getpid(), ctx->ps_log_fd, ctx->ps_data_fd, psp->psp_fd);
#endif
eloop_clear(ctx->eloop, -1);
eloop_forked(ctx->eloop);
eloop_signal_set_cb(ctx->eloop,
@ -459,18 +467,6 @@ ps_startprocess(struct ps_process *psp,
#endif
}
if (ctx->ps_inet != psp)
ctx->ps_inet = NULL;
if (ctx->ps_ctl != psp)
ctx->ps_ctl = NULL;
#if 0
char buf[1024];
errno = 0;
ssize_t xx = recv(psp->psp_fd, buf, sizeof(buf), MSG_PEEK);
logerr("pid %d test fd %d recv peek %zd", getpid(), psp->psp_fd, xx);
#endif
if (eloop_event_add(ctx->eloop, psp->psp_fd, ELE_READ,
recv_msg, psp) == -1)
{
@ -1215,6 +1211,7 @@ ps_newprocess(struct dhcpcd_ctx *ctx, struct ps_id *psid)
return NULL;
psp->psp_ctx = ctx;
memcpy(&psp->psp_id, psid, sizeof(psp->psp_id));
psp->psp_fd = -1;
psp->psp_work_fd = -1;
#ifdef HAVE_CAPSICUM
psp->psp_pfd = -1;

View File

@ -300,11 +300,39 @@ sa_toprefix(const struct sockaddr *sa)
return prefix;
}
static void
ipbytes_fromprefix(uint8_t *ap, int prefix, int max_prefix)
{
int bytes, bits, i;
bytes = prefix / NBBY;
bits = prefix % NBBY;
for (i = 0; i < bytes; i++)
*ap++ = 0xff;
if (bits) {
uint8_t a;
a = 0xff;
a = (uint8_t)(a << (8 - bits));
*ap++ = a;
}
bytes = (max_prefix - prefix) / NBBY;
for (i = 0; i < bytes; i++)
*ap++ = 0x00;
}
void
in6_addr_fromprefix(struct in6_addr *addr, int prefix)
{
ipbytes_fromprefix((uint8_t *)addr, prefix, 128);
}
int
sa_fromprefix(struct sockaddr *sa, int prefix)
{
uint8_t *ap;
int max_prefix, bytes, bits, i;
int max_prefix;
switch (sa->sa_family) {
#ifdef INET
@ -328,22 +356,8 @@ sa_fromprefix(struct sockaddr *sa, int prefix)
return -1;
}
bytes = prefix / NBBY;
bits = prefix % NBBY;
ap = (uint8_t *)sa + sa_addroffset(sa);
for (i = 0; i < bytes; i++)
*ap++ = 0xff;
if (bits) {
uint8_t a;
a = 0xff;
a = (uint8_t)(a << (8 - bits));
*ap++ = a;
}
bytes = (max_prefix - prefix) / NBBY;
for (i = 0; i < bytes; i++)
*ap++ = 0x00;
ipbytes_fromprefix(ap, prefix, max_prefix);
#ifndef NDEBUG
/* Ensure the calculation is correct */

View File

@ -67,6 +67,7 @@ bool sa_is_loopback(const struct sockaddr *);
void *sa_toaddr(struct sockaddr *);
int sa_toprefix(const struct sockaddr *);
int sa_fromprefix(struct sockaddr *, int);
void in6_addr_fromprefix(struct in6_addr *, int);
const char *sa_addrtop(const struct sockaddr *, char *, socklen_t);
int sa_cmp(const struct sockaddr *, const struct sockaddr *);
void sa_in_init(struct sockaddr *, const struct in_addr *);