Sync with dhcpcd-10.0.7

This commit is contained in:
roy 2024-05-24 11:30:29 +00:00
parent 4dcbd9d51d
commit 31430cea00
10 changed files with 367 additions and 83 deletions

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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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;