Module Name: src Committed By: roy Date: Wed Jul 24 09:57:43 UTC 2019
Modified Files: src/external/bsd/dhcpcd/dist/hooks: 20-resolv.conf 50-ntp.conf src/external/bsd/dhcpcd/dist/src: bpf.c dhcp.c dhcp6.c dhcpcd.c if-bsd.c if-options.c ipv6nd.c Log Message: Sync To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/external/bsd/dhcpcd/dist/hooks/20-resolv.conf \ src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf cvs rdiff -u -r1.9 -r1.10 src/external/bsd/dhcpcd/dist/src/bpf.c cvs rdiff -u -r1.19 -r1.20 src/external/bsd/dhcpcd/dist/src/dhcp.c cvs rdiff -u -r1.8 -r1.9 src/external/bsd/dhcpcd/dist/src/dhcp6.c \ src/external/bsd/dhcpcd/dist/src/if-bsd.c cvs rdiff -u -r1.20 -r1.21 src/external/bsd/dhcpcd/dist/src/dhcpcd.c cvs rdiff -u -r1.14 -r1.15 src/external/bsd/dhcpcd/dist/src/if-options.c cvs rdiff -u -r1.7 -r1.8 src/external/bsd/dhcpcd/dist/src/ipv6nd.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/external/bsd/dhcpcd/dist/hooks/20-resolv.conf diff -u src/external/bsd/dhcpcd/dist/hooks/20-resolv.conf:1.2 src/external/bsd/dhcpcd/dist/hooks/20-resolv.conf:1.3 --- src/external/bsd/dhcpcd/dist/hooks/20-resolv.conf:1.2 Sat Sep 22 13:17:46 2018 +++ src/external/bsd/dhcpcd/dist/hooks/20-resolv.conf Wed Jul 24 09:57:43 2019 @@ -19,6 +19,7 @@ build_resolv_conf() interfaces=$(list_interfaces "$resolv_conf_dir") # Build the resolv.conf + header= if [ -n "$interfaces" ]; then # Build the header for x in ${interfaces}; do @@ -69,30 +70,26 @@ build_resolv_conf() } # Extract any ND DNS options from the RA -# For now, we ignore the lifetime of the DNS options unless they -# are absent or zero. -# In this case they are removed from consideration. -# See draft-gont-6man-slaac-dns-config-issues-01 for issues -# regarding DNS option lifetime in ND messages. +# Obey the lifetimes eval_nd_dns() { - eval ltime=\$nd${i}_rdnss${j}_lifetime - if [ -z "$ltime" ] || [ "$ltime" = 0 ]; then - rdnss= - else + + eval rdnsstime=\$nd${i}_rdnss${j}_lifetime + [ -z "$rdnsstime" ] && return 1 + ltime=$(($rdnsstime - $offset)) + if [ "$ltime" -gt 0 ]; then eval rdnss=\$nd${i}_rdnss${j}_servers + [ -n "$rdnss" ] && new_rdnss="$new_rdnss${new_rdnss:+ }$rdnss" fi - eval ltime=\$nd${i}_dnssl${j}_lifetime - if [ -z "$ltime" ] || [ "$ltime" = 0 ]; then - dnssl= - else + + eval dnssltime=\$nd${i}_dnssl${j}_lifetime + [ -z "$dnssltime" ] && return 1 + ltime=$(($dnssltime - $offset)) + if [ "$ltime" -gt 0 ]; then eval dnssl=\$nd${i}_dnssl${j}_search + [ -n "$dnssl" ] && new_dnssl="$new_dnssl${new_dnssl:+ }$dnssl" fi - [ -z "${rdnss}${dnssl}" ] && return 1 - - [ -n "$rdnss" ] && new_rdnss="$new_rdnss${new_rdnss:+ }$rdnss" - [ -n "$dnssl" ] && new_dnssl="$new_dnssl${new_dnssl:+ }$dnssl" j=$(($j + 1)) return 0 } @@ -106,12 +103,16 @@ add_resolv_conf() i=1 j=1 while true; do + eval acquired=\$nd${i}_acquired + [ -z "$acquired" ] && break + eval now=\$nd${i}_now + [ -z "$now" ] && break + offset=$(($now - $acquired)) while true; do eval_nd_dns || break done i=$(($i + 1)) j=1 - eval_nd_dns || break done [ -n "$new_rdnss" ] && \ new_domain_name_servers="$new_domain_name_servers${new_domain_name_servers:+ }$new_rdnss" Index: src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf diff -u src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf:1.2 src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf:1.3 --- src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf:1.2 Sat Sep 22 13:17:46 2018 +++ src/external/bsd/dhcpcd/dist/hooks/50-ntp.conf Wed Jul 24 09:57:43 2019 @@ -62,6 +62,7 @@ build_ntp_conf() # Build a list of interfaces interfaces=$(list_interfaces "$ntp_conf_dir") + header= servers= if [ -n "$interfaces" ]; then # Build the header Index: src/external/bsd/dhcpcd/dist/src/bpf.c diff -u src/external/bsd/dhcpcd/dist/src/bpf.c:1.9 src/external/bsd/dhcpcd/dist/src/bpf.c:1.10 --- src/external/bsd/dhcpcd/dist/src/bpf.c:1.9 Sat May 4 09:42:15 2019 +++ src/external/bsd/dhcpcd/dist/src/bpf.c Wed Jul 24 09:57:43 2019 @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ /* * dhcpcd: BPF arp and bootp filtering * Copyright (c) 2006-2019 Roy Marples <r...@marples.name> @@ -84,7 +85,7 @@ size_t bpf_frame_header_len(const struct interface *ifp) { - switch(ifp->family) { + switch (ifp->family) { case ARPHRD_ETHER: return sizeof(struct ether_header); default: @@ -92,6 +93,23 @@ bpf_frame_header_len(const struct interf } } +static const uint8_t etherbroadcastaddr[] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +int +bpf_frame_bcast(const struct interface *ifp, const char *frame) +{ + + switch (ifp->family) { + case ARPHRD_ETHER: + return memcmp(frame + + offsetof(struct ether_header, ether_dhost), + etherbroadcastaddr, sizeof(etherbroadcastaddr)); + default: + return -1; + } +} + #ifndef __linux__ /* Linux is a special snowflake for opening, attaching and reading BPF. * See if-linux.c for the Linux specific BPF functions. */ @@ -227,8 +245,12 @@ bpf_read(struct interface *ifp, int fd, if (state->buffer_pos + packet.bh_caplen + packet.bh_hdrlen > state->buffer_len) goto next; /* Packet beyond buffer, drop. */ - payload = state->buffer + state->buffer_pos + - packet.bh_hdrlen + fl; + payload = state->buffer + state->buffer_pos + packet.bh_hdrlen; + if (bpf_frame_bcast(ifp, payload) == 0) + *flags |= BPF_BCAST; + else + *flags &= ~BPF_BCAST; + payload += fl; bytes = (ssize_t)packet.bh_caplen - fl; if ((size_t)bytes > len) bytes = (ssize_t)len; Index: src/external/bsd/dhcpcd/dist/src/dhcp.c diff -u src/external/bsd/dhcpcd/dist/src/dhcp.c:1.19 src/external/bsd/dhcpcd/dist/src/dhcp.c:1.20 --- src/external/bsd/dhcpcd/dist/src/dhcp.c:1.19 Sat May 4 09:42:15 2019 +++ src/external/bsd/dhcpcd/dist/src/dhcp.c Wed Jul 24 09:57:43 2019 @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ /* * dhcpcd - DHCP client daemon * Copyright (c) 2006-2019 Roy Marples <r...@marples.name> @@ -47,6 +48,7 @@ #include <inttypes.h> #include <stdbool.h> #include <stddef.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -124,8 +126,9 @@ static const char * const dhcp_params[] }; static int dhcp_openbpf(struct interface *); +static void dhcp_start1(void *); #ifdef ARP -static void dhcp_arp_conflicted(struct arp_state *, const struct arp_msg *); +static void dhcp_arp_found(struct arp_state *, const struct arp_msg *); #endif static void dhcp_handledhcp(struct interface *, struct bootp *, size_t, const struct in_addr *); @@ -339,23 +342,25 @@ get_option_uint8(struct dhcpcd_ctx *ctx, } ssize_t -decode_rfc3442(char *out, size_t len, const uint8_t *p, size_t pl) +print_rfc3442(FILE *fp, const uint8_t *data, size_t data_len) { - const uint8_t *e; - size_t bytes = 0, ocets; - int b; + const uint8_t *p = data, *e; + size_t ocets; uint8_t cidr; struct in_addr addr; - char *o = out; /* Minimum is 5 -first is CIDR and a router length of 4 */ - if (pl < 5) { + if (data_len < 5) { errno = EINVAL; return -1; } - e = p + pl; + e = p + data_len; while (p < e) { + if (p != data) { + if (fputc(' ', fp) == EOF) + return -1; + } cidr = *p++; if (cidr > 32) { errno = EINVAL; @@ -366,45 +371,29 @@ decode_rfc3442(char *out, size_t len, co errno = ERANGE; return -1; } - if (!out) { - p += 4 + ocets; - bytes += ((4 * 4) * 2) + 4; - continue; - } - if ((((4 * 4) * 2) + 4) > len) { - errno = ENOBUFS; - return -1; - } - if (o != out) { - *o++ = ' '; - len--; - } /* If we have ocets then we have a destination and netmask */ + addr.s_addr = 0; if (ocets > 0) { - addr.s_addr = 0; memcpy(&addr.s_addr, p, ocets); - b = snprintf(o, len, "%s/%d", inet_ntoa(addr), cidr); p += ocets; - } else - b = snprintf(o, len, "0.0.0.0/0"); - o += b; - len -= (size_t)b; + } + if (fprintf(fp, "%s/%d", inet_ntoa(addr), cidr) == -1) + return -1; /* Finally, snag the router */ memcpy(&addr.s_addr, p, 4); p += 4; - b = snprintf(o, len, " %s", inet_ntoa(addr)); - o += b; - len -= (size_t)b; + if (fprintf(fp, " %s", inet_ntoa(addr)) == -1) + return -1; } - if (out) - return o - out; - return (ssize_t)bytes; + if (fputc('\0', fp) == EOF) + return -1; + return 1; } static int -decode_rfc3442_rt(struct rt_head *routes, struct interface *ifp, +decode_rfc3442_rt(rb_tree_t *routes, struct interface *ifp, const uint8_t *data, size_t dl, const struct bootp *bootp) { const uint8_t *p = data; @@ -467,22 +456,18 @@ decode_rfc3442_rt(struct rt_head *routes sa_in_init(&rt->rt_dest, &dest); sa_in_init(&rt->rt_netmask, &netmask); sa_in_init(&rt->rt_gateway, &gateway); - - TAILQ_INSERT_TAIL(routes, rt, rt_next); - n++; + if (rt_proto_add(routes, rt)) + n = 1; } return n; } -char * -decode_rfc3361(const uint8_t *data, size_t dl) +ssize_t +print_rfc3361(FILE *fp, const uint8_t *data, size_t dl) { uint8_t enc; - size_t l; - ssize_t r; - char *sip = NULL; + char sip[NS_MAXDNAME]; struct in_addr addr; - char *p; if (dl < 2) { errno = EINVAL; @@ -493,13 +478,10 @@ decode_rfc3361(const uint8_t *data, size dl--; switch (enc) { case 0: - if ((r = decode_rfc1035(NULL, 0, data, dl)) > 0) { - l = (size_t)r + 1; - sip = malloc(l); - if (sip == NULL) - return 0; - decode_rfc1035(sip, l, data, dl); - } + if (decode_rfc1035(sip, sizeof(sip), data, dl) == -1) + return -1; + if (efprintf(fp, "%s", sip) == -1) + return -1; break; case 1: if (dl == 0 || dl % 4 != 0) { @@ -507,25 +489,27 @@ decode_rfc3361(const uint8_t *data, size break; } addr.s_addr = INADDR_BROADCAST; - l = ((dl / sizeof(addr.s_addr)) * ((4 * 4) + 1)) + 1; - sip = p = malloc(l); - if (sip == NULL) - return 0; - while (dl != 0) { + for (; + dl != 0; + data += sizeof(addr.s_addr), dl -= sizeof(addr.s_addr)) + { memcpy(&addr.s_addr, data, sizeof(addr.s_addr)); - data += sizeof(addr.s_addr); - p += snprintf(p, l - (size_t)(p - sip), - "%s ", inet_ntoa(addr)); - dl -= sizeof(addr.s_addr); + if (fprintf(fp, "%s", inet_ntoa(addr)) == -1) + return -1; + if (dl != 0) { + if (fputc(' ', fp) == EOF) + return -1; + } } - *--p = '\0'; + if (fputc('\0', fp) == EOF) + return -1; break; default: errno = EINVAL; return 0; } - return sip; + return 1; } static char * @@ -581,7 +565,7 @@ route_netmask(uint32_t ip_in) * If we have a CSR then we only use that. * Otherwise we add static routes and then routers. */ static int -get_option_routes(struct rt_head *routes, struct interface *ifp, +get_option_routes(rb_tree_t *routes, struct interface *ifp, const struct bootp *bootp, size_t bootp_len) { struct if_options *ifo = ifp->options; @@ -656,9 +640,8 @@ get_option_routes(struct rt_head *routes sa_in_init(&rt->rt_dest, &dest); sa_in_init(&rt->rt_netmask, &netmask); sa_in_init(&rt->rt_gateway, &gateway); - - TAILQ_INSERT_TAIL(routes, rt, rt_next); - n++; + if (rt_proto_add(routes, rt)) + n++; } } @@ -667,7 +650,7 @@ get_option_routes(struct rt_head *routes p = get_option(ifp->ctx, bootp, bootp_len, DHO_ROUTER, &len); else p = NULL; - if (p) { + if (p && len % 4 == 0) { e = p + len; dest.s_addr = INADDR_ANY; netmask.s_addr = INADDR_ANY; @@ -679,8 +662,8 @@ get_option_routes(struct rt_head *routes sa_in_init(&rt->rt_dest, &dest); sa_in_init(&rt->rt_netmask, &netmask); sa_in_init(&rt->rt_gateway, &gateway); - TAILQ_INSERT_TAIL(routes, rt, rt_next); - n++; + if (rt_proto_add(routes, rt)) + n++; } } @@ -707,7 +690,7 @@ dhcp_get_mtu(const struct interface *ifp /* Grab our routers from the DHCP message and apply any MTU value * the message contains */ int -dhcp_get_routes(struct rt_head *routes, struct interface *ifp) +dhcp_get_routes(rb_tree_t *routes, struct interface *ifp) { const struct dhcp_state *state; @@ -1299,9 +1282,8 @@ dhcp_getoption(struct dhcpcd_ctx *ctx, } ssize_t -dhcp_env(char **env, const char *prefix, - const struct bootp *bootp, size_t bootp_len, - const struct interface *ifp) +dhcp_env(FILE *fenv, const char *prefix, const struct interface *ifp, + const struct bootp *bootp, size_t bootp_len) { const struct if_options *ifo; const uint8_t *p; @@ -1309,109 +1291,73 @@ dhcp_env(char **env, const char *prefix, struct in_addr net; struct in_addr brd; struct dhcp_opt *opt, *vo; - size_t e, i, pl; - char **ep; - char cidr[4], safe[(BOOTP_FILE_LEN * 4) + 1]; + size_t i, pl; + char safe[(BOOTP_FILE_LEN * 4) + 1]; uint8_t overl = 0; uint32_t en; - e = 0; ifo = ifp->options; if (get_option_uint8(ifp->ctx, &overl, bootp, bootp_len, DHO_OPTSOVERLOADED) == -1) overl = 0; - if (env == NULL) { - if (bootp->yiaddr || bootp->ciaddr) - e += 5; - if (*bootp->file && !(overl & 1)) - e++; - if (*bootp->sname && !(overl & 2)) - e++; - for (i = 0, opt = ifp->ctx->dhcp_opts; - i < ifp->ctx->dhcp_opts_len; - i++, opt++) - { - if (has_option_mask(ifo->nomask, opt->option)) - continue; - if (dhcp_getoverride(ifo, opt->option)) - continue; - p = get_option(ifp->ctx, bootp, bootp_len, - opt->option, &pl); - if (!p) - continue; - e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name, - opt, dhcp_getoption, p, pl); - } - for (i = 0, opt = ifo->dhcp_override; - i < ifo->dhcp_override_len; - i++, opt++) - { - if (has_option_mask(ifo->nomask, opt->option)) - continue; - p = get_option(ifp->ctx, bootp, bootp_len, - opt->option, &pl); - if (!p) - continue; - e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name, - opt, dhcp_getoption, p, pl); - } - return (ssize_t)e; - } - - ep = env; if (bootp->yiaddr || bootp->ciaddr) { /* Set some useful variables that we derive from the DHCP * message but are not necessarily in the options */ addr.s_addr = bootp->yiaddr ? bootp->yiaddr : bootp->ciaddr; - addvar(&ep, prefix, "ip_address", inet_ntoa(addr)); + if (efprintf(fenv, "%s_ip_address=%s", + prefix, inet_ntoa(addr)) == -1) + return -1; if (get_option_addr(ifp->ctx, &net, - bootp, bootp_len, DHO_SUBNETMASK) == -1) - { + bootp, bootp_len, DHO_SUBNETMASK) == -1) { net.s_addr = ipv4_getnetmask(addr.s_addr); - addvar(&ep, prefix, - "subnet_mask", inet_ntoa(net)); + if (efprintf(fenv, "%s_subnet_mask=%s", + prefix, inet_ntoa(net)) == -1) + return -1; } - snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net)); - addvar(&ep, prefix, "subnet_cidr", cidr); + if (efprintf(fenv, "%s_subnet_cidr=%d", + prefix, inet_ntocidr(net))== -1) + return -1; if (get_option_addr(ifp->ctx, &brd, bootp, bootp_len, DHO_BROADCAST) == -1) { brd.s_addr = addr.s_addr | ~net.s_addr; - addvar(&ep, prefix, - "broadcast_address", inet_ntoa(brd)); + if (efprintf(fenv, "%s_broadcast_address=%s", + prefix, inet_ntoa(brd)) == -1) + return -1; } addr.s_addr = bootp->yiaddr & net.s_addr; - addvar(&ep, prefix, - "network_number", inet_ntoa(addr)); + if (efprintf(fenv, "%s_network_number=%s", + prefix, inet_ntoa(addr)) == -1) + return -1; } if (*bootp->file && !(overl & 1)) { print_string(safe, sizeof(safe), OT_STRING, bootp->file, sizeof(bootp->file)); - addvar(&ep, prefix, "filename", safe); + if (efprintf(fenv, "%s_filename=%s", prefix, safe) == -1) + return -1; } if (*bootp->sname && !(overl & 2)) { print_string(safe, sizeof(safe), OT_STRING | OT_DOMAIN, bootp->sname, sizeof(bootp->sname)); - addvar(&ep, prefix, "server_name", safe); + if (efprintf(fenv, "%s_server_name=%s", prefix, safe) == -1) + return -1; } /* Zero our indexes */ - if (env) { - for (i = 0, opt = ifp->ctx->dhcp_opts; - i < ifp->ctx->dhcp_opts_len; - i++, opt++) - dhcp_zero_index(opt); - for (i = 0, opt = ifp->options->dhcp_override; - i < ifp->options->dhcp_override_len; - i++, opt++) - dhcp_zero_index(opt); - for (i = 0, opt = ifp->ctx->vivso; - i < ifp->ctx->vivso_len; - i++, opt++) - dhcp_zero_index(opt); - } + for (i = 0, opt = ifp->ctx->dhcp_opts; + i < ifp->ctx->dhcp_opts_len; + i++, opt++) + dhcp_zero_index(opt); + for (i = 0, opt = ifp->options->dhcp_override; + i < ifp->options->dhcp_override_len; + i++, opt++) + dhcp_zero_index(opt); + for (i = 0, opt = ifp->ctx->vivso; + i < ifp->ctx->vivso_len; + i++, opt++) + dhcp_zero_index(opt); for (i = 0, opt = ifp->ctx->dhcp_opts; i < ifp->ctx->dhcp_opts_len; @@ -1424,7 +1370,7 @@ dhcp_env(char **env, const char *prefix, p = get_option(ifp->ctx, bootp, bootp_len, opt->option, &pl); if (p == NULL) continue; - ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name, + dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name, opt, dhcp_getoption, p, pl); if (opt->option != DHO_VIVSO || pl <= (int)sizeof(uint32_t)) @@ -1437,7 +1383,7 @@ dhcp_env(char **env, const char *prefix, /* Skip over en + total size */ p += sizeof(en) + 1; pl -= sizeof(en) + 1; - ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name, + dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name, vo, dhcp_getoption, p, pl); } @@ -1450,11 +1396,11 @@ dhcp_env(char **env, const char *prefix, p = get_option(ifp->ctx, bootp, bootp_len, opt->option, &pl); if (p == NULL) continue; - ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name, + dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name, opt, dhcp_getoption, p, pl); } - return ep - env; + return 1; } static void @@ -1497,7 +1443,7 @@ get_lease(struct interface *ifp, } if (get_option_uint32(ctx, &lease->leasetime, bootp, len, DHO_LEASETIME) != 0) - lease->leasetime = ~0U; /* Default to infinite lease */ + lease->leasetime = DHCP_INFINITE_LIFETIME; if (get_option_uint32(ctx, &lease->renewaltime, bootp, len, DHO_RENEWALTIME) != 0) lease->renewaltime = 0; @@ -1923,35 +1869,6 @@ dhcp_request(void *arg) send_request(ifp); } -static int -dhcp_leaseextend(struct interface *ifp) -{ - -#ifdef ARP - if (ifp->options->options & DHCPCD_ARP) { - const struct dhcp_state *state; - struct arp_state *astate; - - state = D_CSTATE(ifp); - if ((astate = arp_new(ifp, &state->lease.addr)) == NULL) - return -1; - astate->conflicted_cb = dhcp_arp_conflicted; - -#ifndef KERNEL_RFC5227 - if (arp_open(ifp) == -1) - return -1; -#endif - - logwarnx("%s: extending lease until DaD failure or DHCP", - ifp->name); - return 0; - } -#endif - - logwarnx("%s: extending lease", ifp->name); - return 0; -} - static void dhcp_expire1(struct interface *ifp) { @@ -1970,12 +1887,12 @@ dhcp_expire(void *arg) { struct interface *ifp = arg; - logerrx("%s: DHCP lease expired", ifp->name); if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND) { - if (dhcp_leaseextend(ifp) == 0) - return; - logerr(__func__); + logwarnx("%s: DHCP lease expired, extending lease", ifp->name); + return; } + + logerrx("%s: DHCP lease expired", ifp->name); dhcp_expire1(ifp); } @@ -2041,41 +1958,18 @@ dhcp_rebind(void *arg) send_rebind(ifp); } -#ifdef ARP static void -dhcp_arp_probed(struct arp_state *astate) +dhcp_finish_dad(struct interface *ifp, struct in_addr *ia) { - struct interface *ifp; - struct dhcp_state *state; - struct if_options *ifo; + struct dhcp_state *state = D_STATE(ifp); - ifp = astate->iface; - state = D_STATE(ifp); - ifo = ifp->options; -#ifdef ARPING - if (ifo->arping_len && state->arping_index < ifo->arping_len) { - /* We didn't find a profile for this - * address or hwaddr, so move to the next - * arping profile */ - if (++state->arping_index < ifo->arping_len) { - astate->addr.s_addr = - ifo->arping[state->arping_index]; - arp_probe(astate); - return; - } - arp_free(astate); - dhcpcd_startinterface(ifp); + if (state->state != DHS_PROBE) return; - } -#endif - - /* Already bound so DAD has worked */ - if (state->state == DHS_BOUND) + if (state->offer == NULL || state->offer->yiaddr != ia->s_addr) return; - logdebugx("%s: DAD completed for %s", - ifp->name, inet_ntoa(astate->addr)); - if (!(ifo->options & DHCPCD_INFORM)) + logdebugx("%s: DAD completed for %s", ifp->name, inet_ntoa(*ia)); + if (!(ifp->options->options & DHCPCD_INFORM)) dhcp_bind(ifp); #ifndef IN_IFF_DUPLICATED else { @@ -2087,7 +1981,7 @@ dhcp_arp_probed(struct arp_state *astate state->new = state->offer; state->new_len = state->offer_len; get_lease(ifp, &state->lease, state->new, state->new_len); - ipv4_applyaddr(astate->iface); + ipv4_applyaddr(ifp); state->new = bootp; state->new_len = len; } @@ -2102,23 +1996,80 @@ dhcp_arp_probed(struct arp_state *astate ipv4ll_drop(ifp); #endif - if (ifo->options & DHCPCD_INFORM) + if (ifp->options->options & DHCPCD_INFORM) dhcp_inform(ifp); } + +static void +dhcp_addr_duplicated(struct interface *ifp, struct in_addr *ia) +{ + struct dhcp_state *state = D_STATE(ifp); +#ifdef IN_IFF_DUPLICATED + struct ipv4_addr *iap; +#endif + + if ((state->offer == NULL || state->offer->yiaddr != ia->s_addr) && + !IN_ARE_ADDR_EQUAL(ia, &state->lease.addr)) + return; + + /* RFC 2131 3.1.5, Client-server interaction */ + logerrx("%s: DAD detected %s", ifp->name, inet_ntoa(*ia)); + unlink(state->leasefile); + if (!(ifp->options->options & DHCPCD_STATIC) && !state->lease.frominfo) + dhcp_decline(ifp); +#ifdef IN_IFF_DUPLICATED + if ((iap = ipv4_iffindaddr(ifp, ia, NULL)) != NULL) + ipv4_deladdr(iap, 0); +#endif + eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); + eloop_timeout_add_sec(ifp->ctx->eloop, + DHCP_RAND_MAX, dhcp_discover, ifp); +} + +#ifdef ARP static void -dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg) +dhcp_arp_not_found(struct arp_state *astate) { struct interface *ifp; struct dhcp_state *state; -#ifdef ARPING struct if_options *ifo; -#endif ifp = astate->iface; state = D_STATE(ifp); + ifo = ifp->options; +#ifdef ARPING + if (ifo->arping_len && state->arping_index < ifo->arping_len) { + /* We didn't find a profile for this + * address or hwaddr, so move to the next + * arping profile */ + if (++state->arping_index < ifo->arping_len) { + astate->addr.s_addr = + ifo->arping[state->arping_index]; + arp_probe(astate); + return; + } + arp_free(astate); + dhcpcd_startinterface(ifp); + return; + } +#endif + dhcp_finish_dad(ifp, &astate->addr); +} + +static void +dhcp_arp_found(struct arp_state *astate, const struct arp_msg *amsg) +{ + struct in_addr addr; #ifdef ARPING + struct interface *ifp; + struct dhcp_state *state; + struct if_options *ifo; + + ifp = astate->iface; + state = D_STATE(ifp); + ifo = ifp->options; if (state->arping_index != -1 && state->arping_index < ifo->arping_len && @@ -2127,17 +2078,14 @@ dhcp_arp_conflicted(struct arp_state *as { char buf[HWADDR_LEN * 3]; - astate->failed.s_addr = ifo->arping[state->arping_index]; - arp_report_conflicted(astate, amsg); hwaddr_ntoa(amsg->sha, ifp->hwlen, buf, sizeof(buf)); if (dhcpcd_selectprofile(ifp, buf) == -1 && - dhcpcd_selectprofile(ifp, - inet_ntoa(astate->failed)) == -1) + dhcpcd_selectprofile(ifp, inet_ntoa(amsg->sip)) == -1) { /* We didn't find a profile for this * address or hwaddr, so move to the next * arping profile */ - dhcp_arp_probed(astate); + dhcp_arp_not_found(astate); return; } arp_free(astate); @@ -2147,65 +2095,20 @@ dhcp_arp_conflicted(struct arp_state *as } #endif - /* RFC 2131 3.1.5, Client-server interaction - * NULL amsg means IN_IFF_DUPLICATED */ - if (amsg == NULL || (state->offer && - (amsg->sip.s_addr == state->offer->yiaddr || - (amsg->sip.s_addr == 0 && - amsg->tip.s_addr == state->offer->yiaddr)))) - { -#ifdef IN_IFF_DUPLICATED - struct ipv4_addr *ia; -#endif - - if (amsg) - astate->failed.s_addr = state->offer->yiaddr; - else - astate->failed = astate->addr; - arp_report_conflicted(astate, amsg); - unlink(state->leasefile); -#ifdef ARP - if (!(ifp->options->options & DHCPCD_STATIC) && - !state->lease.frominfo) - dhcp_decline(ifp); -#endif -#ifdef IN_IFF_DUPLICATED - if ((ia = ipv4_iffindaddr(ifp, &astate->addr, NULL)) != NULL) - ipv4_deladdr(ia, 1); -#endif - arp_free(astate); - eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); - eloop_timeout_add_sec(ifp->ctx->eloop, - DHCP_RAND_MAX, dhcp_discover, ifp); - return; - } - - /* Bound address */ - if (amsg && state->addr && - amsg->sip.s_addr == state->addr->addr.s_addr) - { - astate->failed = state->addr->addr; - arp_report_conflicted(astate, amsg); - if (state->state == DHS_BOUND) { - /* For now, just report the duplicated address */ - } else { - arp_free(astate); - dhcp_expire1(ifp); - } - return; - } + addr = astate->addr; + arp_free(astate); + dhcp_addr_duplicated(ifp, &addr); } +#ifdef KERNEL_RFC5227 static void dhcp_arp_announced(struct arp_state *state) { -// TODO: DHCP addresses handle ACD? -//#ifdef KERNEL_RFC5227 arp_free(state); -//#endif } -#endif +#endif /* KERNEL_RFC5227 */ +#endif /* ARP */ void dhcp_bind(struct interface *ifp) @@ -2232,17 +2135,17 @@ dhcp_bind(struct interface *ifp) loginfox("%s: using static address %s/%d", ifp->name, inet_ntoa(lease->addr), inet_ntocidr(lease->mask)); - lease->leasetime = ~0U; + lease->leasetime = DHCP_INFINITE_LIFETIME; state->reason = "STATIC"; } else if (ifo->options & DHCPCD_INFORM) { loginfox("%s: received approval for %s", ifp->name, inet_ntoa(lease->addr)); - lease->leasetime = ~0U; + lease->leasetime = DHCP_INFINITE_LIFETIME; state->reason = "INFORM"; } else { if (lease->frominfo) state->reason = "TIMEOUT"; - if (lease->leasetime == ~0U) { + if (lease->leasetime == DHCP_INFINITE_LIFETIME) { lease->renewaltime = lease->rebindtime = lease->leasetime; @@ -2305,7 +2208,7 @@ dhcp_bind(struct interface *ifp) else state->reason = "BOUND"; } - if (lease->leasetime == ~0U) + if (lease->leasetime == DHCP_INFINITE_LIFETIME) lease->renewaltime = lease->rebindtime = lease->leasetime; else { eloop_timeout_add_sec(ctx->eloop, @@ -2359,12 +2262,6 @@ dhcp_lastlease(void *arg) if (ifp->ctx->options & DHCPCD_FORKED) return; state->interval = 0; - if (ifp->options->options & DHCPCD_LASTLEASE_EXTEND && - dhcp_leaseextend(ifp) == -1) - { - logerr("%s: %s", ifp->name, __func__); - dhcp_expire(ifp); - } dhcp_discover(ifp); } @@ -2397,17 +2294,32 @@ dhcp_message_new(struct bootp **bootp, } #ifdef ARP +#ifndef KERNEL_RFC5227 +static void +dhcp_arp_defend_failed(struct arp_state *astate) +{ + + dhcp_drop(astate->iface, "EXPIRED"); + dhcp_start1(astate->iface); +} +#endif + static struct arp_state * dhcp_arp_new(struct interface *ifp, struct in_addr *addr) { struct arp_state *astate; + astate = arp_new(ifp, addr); if (astate == NULL) return NULL; - astate->probed_cb = dhcp_arp_probed; - astate->conflicted_cb = dhcp_arp_conflicted; + astate->found_cb = dhcp_arp_found; + astate->not_found_cb = dhcp_arp_not_found; +#ifdef KERNEL_RFC5227 astate->announced_cb = dhcp_arp_announced; +#else + astate->defend_failed_cb = dhcp_arp_defend_failed; +#endif return astate; } @@ -2417,7 +2329,6 @@ dhcp_arp_address(struct interface *ifp) struct dhcp_state *state; struct in_addr addr; struct ipv4_addr *ia; - struct arp_state *astate; eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); @@ -2427,10 +2338,6 @@ dhcp_arp_address(struct interface *ifp) /* If the interface already has the address configured * then we can't ARP for duplicate detection. */ ia = ipv4_iffindaddr(ifp, &addr, NULL); - astate = dhcp_arp_new(ifp, &addr); - if (astate == NULL) - return -1; - #ifdef IN_IFF_NOTUSEABLE if (ia == NULL || ia->addr_flags & IN_IFF_NOTUSEABLE) { state->state = DHS_PROBE; @@ -2439,7 +2346,8 @@ dhcp_arp_address(struct interface *ifp) get_lease(ifp, &l, state->offer, state->offer_len); /* Add the address now, let the kernel handle DAD. */ - ipv4_addaddr(ifp, &l.addr, &l.mask, &l.brd); + ipv4_addaddr(ifp, &l.addr, &l.mask, &l.brd, + l.leasetime, l.rebindtime); } else loginfox("%s: waiting for DAD on %s", ifp->name, inet_ntoa(addr)); @@ -2447,8 +2355,13 @@ dhcp_arp_address(struct interface *ifp) } #else if (ifp->options->options & DHCPCD_ARP && ia == NULL) { + struct arp_state *astate; struct dhcp_lease l; + astate = dhcp_arp_new(ifp, &addr); + if (astate == NULL) + return -1; + state->state = DHS_PROBE; get_lease(ifp, &l, state->offer, state->offer_len); loginfox("%s: probing address %s/%d", @@ -2705,9 +2618,14 @@ dhcp_drop(struct interface *ifp, const c return; } +#ifdef ARP + if (state->addr != NULL) + arp_freeaddr(ifp, &state->addr->addr); +#endif #ifdef ARPING state->arping_index = -1; #endif + if (ifp->options->options & DHCPCD_RELEASE && !(ifp->options->options & DHCPCD_INFORM)) { @@ -3653,15 +3571,9 @@ dhcp_init(struct interface *ifp) const struct if_options *ifo; uint8_t len; char buf[(sizeof(ifo->clientid) - 1) * 3]; - int r; - r = dhcp_initstate(ifp); - if (r == -1) + if (dhcp_initstate(ifp) == -1) return -1; - else if (r == 1) { - /* Now is a good time to find IPv4 routes */ - if_initrt(ifp->ctx, AF_INET); - } state = D_STATE(ifp); state->state = DHS_INIT; @@ -3771,7 +3683,7 @@ dhcp_start1(void *arg) astate = dhcp_arp_new(ifp, NULL); if (astate) - dhcp_arp_probed(astate); + dhcp_arp_not_found(astate); return; } #endif @@ -3848,7 +3760,7 @@ dhcp_start1(void *arg) state->offer = NULL; state->offer_len = 0; } else if (!(ifo->options & DHCPCD_LASTLEASE_EXTEND) && - state->lease.leasetime != ~0U && + state->lease.leasetime != DHCP_INFINITE_LIFETIME && stat(state->leasefile, &st) == 0) { time_t now; @@ -4023,8 +3935,10 @@ dhcp_handleifa(int cmd, struct ipv4_addr return; #ifdef IN_IFF_NOTUSEABLE - if (ia->addr_flags & IN_IFF_NOTUSEABLE) - return; + if (!(ia->addr_flags & IN_IFF_NOTUSEABLE)) + dhcp_finish_dad(ifp, &ia->addr); + else if (ia->addr_flags & IN_IFF_DUPLICATED) + dhcp_addr_duplicated(ifp, &ia->addr); #endif ifo = ifp->options; Index: src/external/bsd/dhcpcd/dist/src/dhcp6.c diff -u src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.8 src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.9 --- src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.8 Wed Jun 26 17:47:47 2019 +++ src/external/bsd/dhcpcd/dist/src/dhcp6.c Wed Jul 24 09:57:43 2019 @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ /* * dhcpcd - DHCP client daemon * Copyright (c) 2006-2019 Roy Marples <r...@marples.name> @@ -582,10 +583,14 @@ dhcp6_delegateaddr(struct in6_addr *addr #define BIT(n) (1UL << (n)) #define BIT_MASK(len) (BIT(len) - 1) - if (ia->sla_max == 0) + if (ia->sla_max == 0) { /* Work out the real sla_max from our bits used */ - ia->sla_max = (uint32_t)BIT_MASK(asla.prefix_len - - prefix->prefix_len); + bits = asla.prefix_len - prefix->prefix_len; + /* Make static analysis happy. + * Bits cannot be bigger than 32 thanks to fls32. */ + assert(bits <= 32); + ia->sla_max = (uint32_t)BIT_MASK(bits); + } } if (ipv6_userprefix(&prefix->prefix, prefix->prefix_len, @@ -2845,26 +2850,11 @@ dhcp6_delegate_prefix(struct interface * struct dhcp6_state *s = D6_STATE(ifd); ipv6_addaddrs(&s->addrs); - - /* - * Can't add routes here because that will trigger - * interface sorting which may break the current - * enumeration. - * This doesn't really matter thanks to DaD because - * calling the script will be delayed and routes - * will get re-built if needed first. - * This only cause minor confusion when dhcpcd is - * restarted and confirms a lease where prior delegation - * has already been assigned, because it will log it - * added routes after the script has run. - * The routes should still be there and fine though. - */ dhcp6_script_try_run(ifd, 1); } } /* Now all addresses have been added, rebuild the routing table. */ - if_initrt(ifp->ctx, AF_INET6); rt_build(ifp->ctx, AF_INET6); } @@ -2929,7 +2919,6 @@ dhcp6_find_delegates(struct interface *i state = D6_STATE(ifp); state->state = DH6S_DELEGATED; ipv6_addaddrs(&state->addrs); - if_initrt(ifp->ctx, AF_INET6); rt_build(ifp->ctx, AF_INET6); dhcp6_script_try_run(ifp, 1); } @@ -3167,7 +3156,6 @@ dhcp6_bind(struct interface *ifp, const else lognewinfo("%s: expire in %"PRIu32" seconds", ifp->name, state->expire); - if_initrt(ifp->ctx, AF_INET6); rt_build(ifp->ctx, AF_INET6); if (!timed_out) dhcp6_writelease(ifp); @@ -3971,24 +3959,22 @@ dhcp6_handleifa(int cmd, struct ipv6_add } ssize_t -dhcp6_env(char **env, const char *prefix, const struct interface *ifp, +dhcp6_env(FILE *fp, const char *prefix, const struct interface *ifp, const struct dhcp6_message *m, size_t len) { const struct if_options *ifo; struct dhcp_opt *opt, *vo; const uint8_t *p; struct dhcp6_option o; - size_t i, n; + size_t i; char *pfx; uint32_t en; const struct dhcpcd_ctx *ctx; #ifndef SMALL const struct dhcp6_state *state; const struct ipv6_addr *ap; - char *v, *val; #endif - n = 0; if (m == NULL) goto delegated; @@ -4003,28 +3989,20 @@ dhcp6_env(char **env, const char *prefix ctx = ifp->ctx; /* Zero our indexes */ - if (env) { - for (i = 0, opt = ctx->dhcp6_opts; - i < ctx->dhcp6_opts_len; - i++, opt++) - dhcp_zero_index(opt); - for (i = 0, opt = ifp->options->dhcp6_override; - i < ifp->options->dhcp6_override_len; - i++, opt++) - dhcp_zero_index(opt); - for (i = 0, opt = ctx->vivso; - i < ctx->vivso_len; - i++, opt++) - dhcp_zero_index(opt); - i = strlen(prefix) + strlen("_dhcp6") + 1; - pfx = malloc(i); - if (pfx == NULL) { - logerr(__func__); - return -1; - } - snprintf(pfx, i, "%s_dhcp6", prefix); - } else - pfx = NULL; + for (i = 0, opt = ctx->dhcp6_opts; + i < ctx->dhcp6_opts_len; + i++, opt++) + dhcp_zero_index(opt); + for (i = 0, opt = ifp->options->dhcp6_override; + i < ifp->options->dhcp6_override_len; + i++, opt++) + dhcp_zero_index(opt); + for (i = 0, opt = ctx->vivso; + i < ctx->vivso_len; + i++, opt++) + dhcp_zero_index(opt); + if (asprintf(&pfx, "%s_dhcp6", prefix) == -1) + return -1; /* Unlike DHCP, DHCPv6 options *may* occur more than once. * There is also no provision for option concatenation unlike DHCP. */ @@ -4070,15 +4048,13 @@ dhcp6_env(char **env, const char *prefix opt = NULL; } if (opt) { - n += dhcp_envoption(ifp->ctx, - env == NULL ? NULL : &env[n], - pfx, ifp->name, + dhcp_envoption(ifp->ctx, + fp, pfx, ifp->name, opt, dhcp6_getoption, p, o.len); } if (vo) { - n += dhcp_envoption(ifp->ctx, - env == NULL ? NULL : &env[n], - pfx, ifp->name, + dhcp_envoption(ifp->ctx, + fp, pfx, ifp->name, vo, dhcp6_getoption, p + sizeof(en), o.len - sizeof(en)); @@ -4090,38 +4066,29 @@ delegated: #ifndef SMALL /* Needed for Delegated Prefixes */ state = D6_CSTATE(ifp); - i = 0; TAILQ_FOREACH(ap, &state->addrs, next) { - if (ap->delegating_prefix) { - i += strlen(ap->saddr) + 1; - } + if (ap->delegating_prefix) + break; } - if (env && i) { - i += strlen(prefix) + strlen("_delegated_dhcp6_prefix="); - v = val = env[n] = malloc(i); - if (v == NULL) { - logerr(__func__); - return -1; - } - v += snprintf(val, i, "%s_delegated_dhcp6_prefix=", prefix); - TAILQ_FOREACH(ap, &state->addrs, next) { - if (ap->delegating_prefix) { - /* Can't use stpcpy(3) due to "security" */ - const char *sap = ap->saddr; - - do - *v++ = *sap; - while (*++sap != '\0'); - *v++ = ' '; - } + if (ap == NULL) + return 1; + if (fprintf(fp, "%s_delegated_dhcp6_prefix=", prefix) == -1) + return -1; + TAILQ_FOREACH(ap, &state->addrs, next) { + if (ap->delegating_prefix == NULL) + continue; + if (ap != TAILQ_FIRST(&state->addrs)) { + if (fputc(' ', fp) == EOF) + return -1; } - *--v = '\0'; + if (fprintf(fp, "%s", ap->saddr) == -1) + return -1; } - if (i) - n++; + if (fputc('\0', fp) == EOF) + return -1; #endif - return (ssize_t)n; + return 1; } int Index: src/external/bsd/dhcpcd/dist/src/if-bsd.c diff -u src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.8 src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.9 --- src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.8 Wed Jun 26 17:47:47 2019 +++ src/external/bsd/dhcpcd/dist/src/if-bsd.c Wed Jul 24 09:57:43 2019 @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ /* * BSD interface driver for dhcpcd * Copyright (c) 2006-2019 Roy Marples <r...@marples.name> @@ -496,6 +497,8 @@ if_route(unsigned char cmd, const struct bool gateway_unspec; assert(rt != NULL); + assert(rt->rt_ifp != NULL); + assert(rt->rt_ifp->ctx != NULL); ctx = rt->rt_ifp->ctx; #define ADDSA(sa) do { \ @@ -695,15 +698,13 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct } int -if_initrt(struct dhcpcd_ctx *ctx, int af) +if_initrt(struct dhcpcd_ctx *ctx, rb_tree_t *kroutes, int af) { struct rt_msghdr *rtm; int mib[6]; size_t needed; char *buf, *p, *end; - struct rt rt; - - rt_headclear(&ctx->kroutes, af); + struct rt rt, *rtn; mib[0] = CTL_NET; mib[1] = PF_ROUTE; @@ -730,10 +731,15 @@ if_initrt(struct dhcpcd_ctx *ctx, int af errno = EINVAL; break; } - if (if_copyrt(ctx, &rt, rtm) == 0) { - rt.rt_dflags |= RTDF_INIT; - rt_recvrt(RTM_ADD, &rt, rtm->rtm_pid); + if (if_copyrt(ctx, &rt, rtm) != 0) + continue; + if ((rtn = rt_new(rt.rt_ifp)) == NULL) { + logerr(__func__); + break; } + memcpy(rtn, &rt, sizeof(*rtn)); + if (rb_tree_insert_node(kroutes, rtn) != rtn) + rt_free(rtn); } free(buf); return p == end ? 0 : -1; @@ -1063,7 +1069,7 @@ if_rtm(struct dhcpcd_ctx *ctx, const str return 0; if (if_copyrt(ctx, &rt, rtm) == -1) - return errno == ENOTSUP ? 0 : -1; + return -1; #ifdef INET6 /* @@ -1306,7 +1312,6 @@ if_dispatch(struct dhcpcd_ctx *ctx, cons #ifdef RTM_DESYNC case RTM_DESYNC: dhcpcd_linkoverflow(ctx); - return 0; #endif } @@ -1326,12 +1331,13 @@ if_handlelink(struct dhcpcd_ctx *ctx) return -1; if (len == 0) return 0; - if ((size_t)len < offsetof(struct rt_msghdr, rtm_index) || - len < rtm.hdr.rtm_msglen) - { + if (len < rtm.hdr.rtm_msglen) { errno = EINVAL; return -1; } + /* We generally treat rtm.hdr has an array so we can easily + * access the following data. */ + /* coverity[callee_ptr_arith] */ return if_dispatch(ctx, &rtm.hdr); } Index: src/external/bsd/dhcpcd/dist/src/dhcpcd.c diff -u src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.20 src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.21 --- src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.20 Wed Jun 26 17:47:47 2019 +++ src/external/bsd/dhcpcd/dist/src/dhcpcd.c Wed Jul 24 09:57:43 2019 @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ /* * dhcpcd - DHCP client daemon * Copyright (c) 2006-2019 Roy Marples <r...@marples.name> @@ -738,9 +739,6 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx * #ifdef INET dhcp_abort(ifp); #endif -#ifdef INET6 - ipv6nd_expire(ifp, 0); -#endif #ifdef DHCP6 dhcp6_abort(ifp); #endif @@ -785,7 +783,7 @@ dhcpcd_handlecarrier(struct dhcpcd_ctx * /* Set any IPv6 Routers we remembered to expire * faster than they would normally as we * maybe on a new network. */ - ipv6nd_expire(ifp, RTR_CARRIER_EXPIRE); + ipv6nd_startexpire(ifp); #endif /* RFC4941 Section 3.5 */ ipv6_gentempifid(ifp); @@ -1003,6 +1001,7 @@ dhcpcd_handleinterface(void *arg, int ac struct if_head *ifs; struct interface *ifp, *iff; const char * const argv[] = { ifname }; + int e; ctx = arg; if (action == -1) { @@ -1026,13 +1025,17 @@ dhcpcd_handleinterface(void *arg, int ac logerr(__func__); return -1; } + ifp = if_find(ifs, ifname); if (ifp == NULL) { /* This can happen if an interface is quickly added * and then removed. */ errno = ENOENT; - return -1; + e = -1; + goto out; } + e = 1; + /* Check if we already have the interface */ iff = if_find(ctx->ifaces, ifp->name); @@ -1061,6 +1064,7 @@ dhcpcd_handleinterface(void *arg, int ac dhcpcd_prestartinterface(iff); } +out: /* Free our discovered list */ while ((ifp = TAILQ_FIRST(ifs))) { TAILQ_REMOVE(ifs, ifp, next); @@ -1068,7 +1072,7 @@ dhcpcd_handleinterface(void *arg, int ac } free(ifs); - return 1; + return e; } static void @@ -1081,7 +1085,8 @@ dhcpcd_handlelink(void *arg) dhcpcd_linkoverflow(ctx); return; } - logerr(__func__); + if (errno != ENOTSUP) + logerr(__func__); } } @@ -1093,6 +1098,22 @@ dhcpcd_checkcarrier(void *arg) dhcpcd_handlecarrier(ifp->ctx, LINK_UNKNOWN, ifp->flags, ifp->name); } +#ifndef SMALL +static void +dhcpcd_setlinkrcvbuf(struct dhcpcd_ctx *ctx) +{ + socklen_t socklen; + + if (ctx->link_rcvbuf == 0) + return; + + socklen = sizeof(ctx->link_rcvbuf); + if (setsockopt(ctx->link_fd, SOL_SOCKET, + SO_RCVBUF, &ctx->link_rcvbuf, socklen) == -1) + logerr(__func__); +} +#endif + void dhcpcd_linkoverflow(struct dhcpcd_ctx *ctx) { @@ -1113,10 +1134,17 @@ dhcpcd_linkoverflow(struct dhcpcd_ctx *c eloop_exit(ctx->eloop, EXIT_FAILURE); return; } +#ifndef SMALL + dhcpcd_setlinkrcvbuf(ctx); +#endif eloop_event_add(ctx->eloop, ctx->link_fd, dhcpcd_handlelink, ctx); /* Work out the current interfaces. */ ifaces = if_discover(ctx, &ifaddrs, ctx->ifc, ctx->ifv); + if (ifaces == NULL) { + logerr(__func__); + return; + } /* Punt departed interfaces */ TAILQ_FOREACH_SAFE(ifp, ctx->ifaces, next, ifn) { @@ -1126,21 +1154,23 @@ dhcpcd_linkoverflow(struct dhcpcd_ctx *c } /* Add new interfaces */ - TAILQ_FOREACH_SAFE(ifp, ifaces, next, ifn) { + while ((ifp = TAILQ_FIRST(ifaces)) != NULL ) { + TAILQ_REMOVE(ifaces, ifp, next); ifp1 = if_find(ctx->ifaces, ifp->name); if (ifp1 != NULL) { /* If the interface already exists, * check carrier state. */ eloop_timeout_add_sec(ctx->eloop, 0, dhcpcd_checkcarrier, ifp1); + if_free(ifp); continue; } - TAILQ_REMOVE(ifaces, ifp, next); TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next); if (ifp->active) eloop_timeout_add_sec(ctx->eloop, 0, dhcpcd_prestartinterface, ifp); } + free(ifaces); /* Update address state. */ if_markaddrsstale(ctx->ifaces); @@ -1958,6 +1988,9 @@ printpidfile: logerr("%s: if_opensockets", __func__); goto exit_failure; } +#ifndef SMALL + dhcpcd_setlinkrcvbuf(&ctx); +#endif /* When running dhcpcd against a single interface, we need to retain * the old behaviour of waiting for an IP address */ @@ -2057,7 +2090,6 @@ printpidfile: free_options(&ctx, ifo); ifo = NULL; - if_sortinterfaces(&ctx); TAILQ_FOREACH(ifp, ctx.ifaces, next) { if (ifp->active) eloop_timeout_add_sec(ctx.eloop, 0, @@ -2114,5 +2146,11 @@ exit1: if (ctx.options & DHCPCD_FORKED) _exit(i); /* so atexit won't remove our pidfile */ #endif +#ifdef HAVE_OPEN_MEMSTREAM + if (ctx.script_fp) + fclose(ctx.script_fp); +#endif + free(ctx.script_buf); + free(ctx.script_env); return i; } Index: src/external/bsd/dhcpcd/dist/src/if-options.c diff -u src/external/bsd/dhcpcd/dist/src/if-options.c:1.14 src/external/bsd/dhcpcd/dist/src/if-options.c:1.15 --- src/external/bsd/dhcpcd/dist/src/if-options.c:1.14 Sat May 4 09:42:15 2019 +++ src/external/bsd/dhcpcd/dist/src/if-options.c Wed Jul 24 09:57:43 2019 @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ /* * dhcpcd - DHCP client daemon * Copyright (c) 2006-2019 Roy Marples <r...@marples.name> @@ -64,7 +65,7 @@ #define O_IPV6RS O_BASE + 4 #define O_NOIPV6RS O_BASE + 5 #define O_IPV6RA_FORK O_BASE + 6 -// unused O_BASE + 7 +#define O_LINK_RCVBUF O_BASE + 7 // unused O_BASE + 8 #define O_NOALIAS O_BASE + 9 #define O_IA_NA O_BASE + 10 @@ -204,6 +205,7 @@ const struct option cf_options[] = { {"lastleaseextend", no_argument, NULL, O_LASTLEASE_EXTEND}, {"inactive", no_argument, NULL, O_INACTIVE}, {"mudurl", required_argument, NULL, O_MUDURL}, + {"link_rcvbuf", required_argument, NULL, O_LINK_RCVBUF}, {NULL, 0, NULL, '\0'} }; @@ -724,8 +726,9 @@ parse_option(struct dhcpcd_ctx *ctx, con logerr(__func__); return -1; } - parse_str(ifo->script, dl, arg, PARSE_STRING_NULL); - if (ifo->script[0] == '\0' || + s = parse_str(ifo->script, dl, arg, PARSE_STRING_NULL); + if (s == -1 || + ifo->script[0] == '\0' || strcmp(ifo->script, "/dev/null") == 0) { free(ifo->script); @@ -1122,16 +1125,14 @@ parse_option(struct dhcpcd_ctx *ctx, con *fp = ' '; return -1; } - if ((rt = rt_new0(ctx)) == NULL) { - *fp = ' '; + *fp = ' '; + if ((rt = rt_new0(ctx)) == NULL) return -1; - } sa_in_init(&rt->rt_dest, &addr); sa_in_init(&rt->rt_netmask, &addr2); sa_in_init(&rt->rt_gateway, &addr3); - TAILQ_INSERT_TAIL(&ifo->routes, rt, rt_next); - *fp = ' '; - add_environ(&ifo->config, arg, 0); + if (rt_proto_add_ctx(&ifo->routes, rt, ctx)) + add_environ(&ifo->config, arg, 0); } else if (strncmp(arg, "routers=", strlen("routers=")) == 0) { if (parse_addr(&addr, NULL, p) == -1) return -1; @@ -1141,8 +1142,8 @@ parse_option(struct dhcpcd_ctx *ctx, con sa_in_init(&rt->rt_dest, &addr2); sa_in_init(&rt->rt_netmask, &addr2); sa_in_init(&rt->rt_gateway, &addr); - TAILQ_INSERT_TAIL(&ifo->routes, rt, rt_next); - add_environ(&ifo->config, arg, 0); + if (rt_proto_add_ctx(&ifo->routes, rt, ctx)) + add_environ(&ifo->config, arg, 0); } else if (strncmp(arg, "interface_mtu=", strlen("interface_mtu=")) == 0 || strncmp(arg, "mtu=", strlen("mtu=")) == 0) @@ -1868,6 +1869,7 @@ err_sla: ifo->vivco_len + 1, sizeof(*ifo->vivco)); if (vivco == NULL) { logerr( __func__); + free(np); return -1; } ifo->vivco = vivco; @@ -2160,6 +2162,16 @@ err_sla: } *ifo->mudurl = (uint8_t)s; break; + case O_LINK_RCVBUF: +#ifndef SMALL + ARG_REQUIRED; + ctx->link_rcvbuf = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e); + if (e) { + logerrx("failed to convert link_rcvbuf %s", arg); + return -1; + } +#endif + break; default: return 0; } @@ -2269,7 +2281,7 @@ default_config(struct dhcpcd_ctx *ctx) ifo->script = UNCONST(default_script); ifo->metric = -1; ifo->auth.options |= DHCPCD_AUTH_REQUIRE; - TAILQ_INIT(&ifo->routes); + rb_tree_init(&ifo->routes, &rt_compare_proto_ops); #ifdef AUTH TAILQ_INIT(&ifo->auth.tokens); #endif @@ -2327,6 +2339,9 @@ read_config(struct dhcpcd_ctx *ctx, buf = NULL; buflen = 0; + /* Reset route order */ + ctx->rt_order = 0; + /* Parse our embedded options file */ if (ifname == NULL && !(ctx->options & DHCPCD_PRINT_PIDFILE)) { /* Space for initial estimates */ Index: src/external/bsd/dhcpcd/dist/src/ipv6nd.c diff -u src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.7 src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.8 --- src/external/bsd/dhcpcd/dist/src/ipv6nd.c:1.7 Wed Jun 26 17:47:47 2019 +++ src/external/bsd/dhcpcd/dist/src/ipv6nd.c Wed Jul 24 09:57:43 2019 @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ /* * dhcpcd - IPv6 ND handling * Copyright (c) 2006-2019 Roy Marples <r...@marples.name> @@ -105,6 +106,9 @@ __CTASSERT(sizeof(struct nd_opt_rdnss) = #define RTPREF_RESERVED (-2) #define RTPREF_INVALID (-3) /* internal */ +#define EXPIRED_MAX 5 /* Remember 5 expired routers to avoid + logspam. */ + #define MIN_RANDOM_FACTOR 500 /* millisecs */ #define MAX_RANDOM_FACTOR 1500 /* millisecs */ #define MIN_RANDOM_FACTOR_U MIN_RANDOM_FACTOR * 1000 /* usecs */ @@ -462,7 +466,6 @@ ipv6nd_advertise(struct ipv6_addr *ia) return; ctx = ia->iface->ctx; - if_sortinterfaces(ctx); /* Find the most preferred address to advertise. */ iaf = NULL; TAILQ_FOREACH(ifp, ctx->ifaces, next) { @@ -483,7 +486,8 @@ ipv6nd_advertise(struct ipv6_addr *ia) iap->addr_flags & IN6_IFF_NOTUSEABLE) continue; - if (iaf == NULL) + if (iaf == NULL || + iaf->iface->metric > iap->iface->metric) iaf = iap; } } @@ -523,46 +527,34 @@ ipv6nd_advertise(struct ipv6_addr *ia) ipv6nd_sendadvertisement(iaf); } -void -ipv6nd_expire(struct interface *ifp, uint32_t seconds) +static void +ipv6nd_expire(void *arg) { + struct interface *ifp = arg; struct ra *rap; - struct timespec now; - uint32_t vltime = seconds; - uint32_t pltime = seconds / 2; + struct ipv6_addr *ia; + struct timespec now = { .tv_sec = 1 }; if (ifp->ctx->ra_routers == NULL) return; - clock_gettime(CLOCK_MONOTONIC, &now); - TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) { - if (rap->iface == ifp) { - rap->acquired = now; - rap->expired = seconds ? 0 : 1; - if (seconds) { - struct ipv6_addr *ia; - - rap->lifetime = seconds; - TAILQ_FOREACH(ia, &rap->addrs, next) { - if (ia->prefix_pltime > pltime || - ia->prefix_vltime > vltime) - { - ia->acquired = now; - if (ia->prefix_pltime != 0) - ia->prefix_pltime = - pltime; - ia->prefix_vltime = vltime; - } - } - ipv6_addaddrs(&rap->addrs); - } + if (rap->iface == ifp) + continue; + rap->acquired = now; + TAILQ_FOREACH(ia, &rap->addrs, next) { + ia->acquired = now; } } - if (seconds) - ipv6nd_expirera(ifp); - else - rt_build(ifp->ctx, AF_INET6); + ipv6nd_expirera(ifp); +} + +void +ipv6nd_startexpire(struct interface *ifp) +{ + + eloop_timeout_add_sec(ifp->ctx->eloop, RTR_CARRIER_EXPIRE, + ipv6nd_expire, ifp); } static void @@ -1228,6 +1220,10 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, break; case ND_OPT_MTU: + if (len < sizeof(mtu)) { + logerrx("%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) { @@ -1239,6 +1235,10 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, break; case ND_OPT_RDNSS: + if (len < sizeof(rdnss)) { + logerrx("%s: short RDNSS option", ifp->name); + break; + } memcpy(&rdnss, p, sizeof(rdnss)); if (rdnss.nd_opt_rdnss_lifetime && rdnss.nd_opt_rdnss_len > 1) @@ -1278,11 +1278,6 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, ipv6_addtempaddrs(ifp, &rap->acquired); #endif - /* Find any freshly added routes, such as the subnet route. - * We do this because we cannot rely on recieving the kernel - * notification right now via our link socket. */ - if_initrt(ifp->ctx, AF_INET6); - rt_build(ifp->ctx, AF_INET6); if (ipv6nd_scriptrun(rap)) return; @@ -1390,11 +1385,11 @@ ipv6nd_getoption(struct dhcpcd_ctx *ctx, } ssize_t -ipv6nd_env(char **env, const char *prefix, const struct interface *ifp) +ipv6nd_env(FILE *fp, const struct interface *ifp) { size_t i, j, n, len, olen; struct ra *rap; - char ndprefix[32], abuf[24]; + char ndprefix[32]; struct dhcp_opt *opt; uint8_t *p; struct nd_opt_hdr ndo; @@ -1407,34 +1402,25 @@ ipv6nd_env(char **env, const char *prefi if (rap->iface != ifp) continue; i++; - if (prefix != NULL) - snprintf(ndprefix, sizeof(ndprefix), - "%s_nd%zu", prefix, i); - else - snprintf(ndprefix, sizeof(ndprefix), - "nd%zu", i); - if (env) - setvar(&env[n], ndprefix, "from", rap->sfrom); - n++; - if (env) - setvard(&env[n], ndprefix, "acquired", - (size_t)rap->acquired.tv_sec); - n++; - if (env) - setvard(&env[n], ndprefix, "now", (size_t)now.tv_sec); - n++; + snprintf(ndprefix, sizeof(ndprefix), "nd%zu", i); + if (efprintf(fp, "%s_from=%s", ndprefix, rap->sfrom) == -1) + return -1; + if (efprintf(fp, "%s_acquired=%lld", ndprefix, + (long long)rap->acquired.tv_sec) == -1) + return -1; + if (efprintf(fp, "%s_now=%lld", ndprefix, + (long long)now.tv_sec) == -1) + return -1; /* Zero our indexes */ - if (env) { - for (j = 0, opt = rap->iface->ctx->nd_opts; - j < rap->iface->ctx->nd_opts_len; - j++, opt++) - dhcp_zero_index(opt); - for (j = 0, opt = rap->iface->options->nd_override; - j < rap->iface->options->nd_override_len; - j++, opt++) - dhcp_zero_index(opt); - } + for (j = 0, opt = rap->iface->ctx->nd_opts; + j < rap->iface->ctx->nd_opts_len; + j++, opt++) + dhcp_zero_index(opt); + for (j = 0, opt = rap->iface->options->nd_override; + j < rap->iface->options->nd_override_len; + j++, opt++) + dhcp_zero_index(opt); /* Unlike DHCP, ND6 options *may* occur more than once. * There is also no provision for option concatenation @@ -1467,34 +1453,31 @@ ipv6nd_env(char **env, const char *prefi if (j == rap->iface->ctx->nd_opts_len) opt = NULL; } - if (opt) { - n += dhcp_envoption(rap->iface->ctx, - env == NULL ? NULL : &env[n], - ndprefix, rap->iface->name, - opt, ipv6nd_getoption, - p + sizeof(ndo), olen - sizeof(ndo)); - } + if (opt == NULL) + continue; + dhcp_envoption(rap->iface->ctx, fp, + ndprefix, rap->iface->name, + opt, ipv6nd_getoption, + p + sizeof(ndo), olen - sizeof(ndo)); } /* We need to output the addresses we actually made * from the prefix information options as well. */ j = 0; TAILQ_FOREACH(ia, &rap->addrs, next) { - if (!(ia->flags & IPV6_AF_AUTOCONF) + if (!(ia->flags & IPV6_AF_AUTOCONF) || #ifdef IPV6_AF_TEMPORARY - || ia->flags & IPV6_AF_TEMPORARY + ia->flags & IPV6_AF_TEMPORARY || #endif - ) + !(ia->flags & IPV6_AF_ADDED) || + ia->prefix_vltime == 0) continue; - j++; - if (env) { - snprintf(abuf, sizeof(abuf), "addr%zu", j); - setvar(&env[n], ndprefix, abuf, ia->saddr); - } - n++; + if (efprintf(fp, "%s_addr%zu=%s", + ndprefix, j++, ia->saddr) == -1) + return -1; } } - return (ssize_t)n; + return 1; } void @@ -1522,6 +1505,16 @@ ipv6nd_expirera(void *arg) struct timespec now, lt, expire, next; bool expired, valid, validone; struct ipv6_addr *ia; + size_t len, olen; + uint8_t *p; + struct nd_opt_hdr ndo; +#if 0 + struct nd_opt_prefix_info pi; +#endif + struct nd_opt_dnssl dnssl; + struct nd_opt_rdnss rdnss; + uint32_t ltime; + size_t nexpired = 0; ifp = arg; clock_gettime(CLOCK_MONOTONIC, &now); @@ -1536,8 +1529,7 @@ ipv6nd_expirera(void *arg) lt.tv_sec = (time_t)rap->lifetime; lt.tv_nsec = 0; timespecadd(&rap->acquired, <, &expire); - if (rap->lifetime == 0 || timespeccmp(&now, &expire, >)) - { + if (timespeccmp(&now, &expire, >)) { if (!rap->expired) { logwarnx("%s: %s: router expired", ifp->name, rap->sfrom); @@ -1588,14 +1580,79 @@ ipv6nd_expirera(void *arg) } } - /* XXX FixMe! - * We need to extract the lifetime from each option and check - * if that has expired or not. - * If it has, zero the option out in the returned data. */ - - /* No valid lifetimes are left on the RA, so we might - * as well punt it. */ - if (!valid && !validone) + /* Work out expiry for ND options */ + len = rap->data_len - sizeof(struct nd_router_advert); + for (p = rap->data + sizeof(struct nd_router_advert); + len >= sizeof(ndo); + p += olen, len -= olen) + { + memcpy(&ndo, p, sizeof(ndo)); + olen = (size_t)(ndo.nd_opt_len * 8); + if (olen > len) { + errno = EINVAL; + break; + } + + if (has_option_mask(rap->iface->options->nomasknd, + ndo.nd_opt_type)) + continue; + + switch (ndo.nd_opt_type) { + /* Prefix info is already checked in the above loop. */ +#if 0 + case ND_OPT_PREFIX_INFORMATION: + if (len < sizeof(pi)) + break; + memcpy(&pi, p, sizeof(pi)); + ltime = pi.nd_opt_pi_valid_time; + break; +#endif + case ND_OPT_DNSSL: + if (len < sizeof(dnssl)) + continue; + memcpy(&dnssl, p, sizeof(dnssl)); + ltime = dnssl.nd_opt_dnssl_lifetime; + break; + case ND_OPT_RDNSS: + if (len < sizeof(rdnss)) + continue; + memcpy(&rdnss, p, sizeof(rdnss)); + ltime = rdnss.nd_opt_rdnss_lifetime; + break; + default: + continue; + } + + if (ltime == 0) + continue; + if (ltime == ND6_INFINITE_LIFETIME) { + validone = true; + continue; + } + + lt.tv_sec = (time_t)ntohl(ltime); + lt.tv_nsec = 0; + timespecadd(&rap->acquired, <, &expire); + if (timespeccmp(&now, &expire, >)) { + expired = true; + continue; + } + + timespecsub(&expire, &now, <); + if (!timespecisset(&next) || + timespeccmp(&next, <, >)) + { + next = lt; + validone = true; + } + } + + if (valid || validone) + continue; + + /* Router has expired. Let's not keep a lot of them. + * We should work out if all the options have expired .... */ + if (++nexpired > EXPIRED_MAX) ipv6nd_free_ra(rap); } @@ -1603,6 +1660,7 @@ ipv6nd_expirera(void *arg) eloop_timeout_add_tv(ifp->ctx->eloop, &next, ipv6nd_expirera, ifp); if (expired) { + logwarnx("%s: part of Router Advertisement expired", ifp->name); rt_build(ifp->ctx, AF_INET6); script_runreason(ifp, "ROUTERADVERT"); }