Module Name: src Committed By: roy Date: Fri Oct 11 11:03:59 UTC 2019
Modified Files: src/external/bsd/dhcpcd/dist/src: bpf.c dhcp.c dhcp6.c dhcpcd.8.in dhcpcd.c if-bsd.c if-options.c Log Message: Sync To generate a diff of this commit: cvs rdiff -u -r1.12 -r1.13 src/external/bsd/dhcpcd/dist/src/bpf.c \ src/external/bsd/dhcpcd/dist/src/dhcp6.c cvs rdiff -u -r1.27 -r1.28 src/external/bsd/dhcpcd/dist/src/dhcp.c cvs rdiff -u -r1.3 -r1.4 src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in cvs rdiff -u -r1.26 -r1.27 src/external/bsd/dhcpcd/dist/src/dhcpcd.c cvs rdiff -u -r1.13 -r1.14 src/external/bsd/dhcpcd/dist/src/if-bsd.c cvs rdiff -u -r1.17 -r1.18 src/external/bsd/dhcpcd/dist/src/if-options.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/src/bpf.c diff -u src/external/bsd/dhcpcd/dist/src/bpf.c:1.12 src/external/bsd/dhcpcd/dist/src/bpf.c:1.13 --- src/external/bsd/dhcpcd/dist/src/bpf.c:1.12 Wed Aug 21 17:12:19 2019 +++ src/external/bsd/dhcpcd/dist/src/bpf.c Fri Oct 11 11:03:59 2019 @@ -410,13 +410,7 @@ bpf_cmp_hwaddr(struct bpf_insn *bpf, siz #endif #ifdef ARP - static const struct bpf_insn bpf_arp_ether [] = { - /* Ensure packet is at least correct size. */ - BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), - BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), - BPF_STMT(BPF_RET + BPF_K, 0), - /* Check this is an ARP packet. */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_header, ether_type)), @@ -552,17 +546,8 @@ bpf_arp(struct interface *ifp, int fd) } #endif -#define BPF_M_FHLEN 0 -#define BPF_M_IPHLEN 1 -#define BPF_M_IPLEN 2 -#define BPF_M_UDP 3 -#define BPF_M_UDPLEN 4 - #ifdef ARPHRD_NONE static const struct bpf_insn bpf_bootp_none[] = { - /* Set the frame header length to zero. */ - BPF_STMT(BPF_LD + BPF_IMM, 0), - BPF_STMT(BPF_ST, BPF_M_FHLEN), }; #define BPF_BOOTP_NONE_LEN __arraycount(bpf_bootp_none) #endif @@ -574,13 +559,14 @@ static const struct bpf_insn bpf_bootp_e BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), BPF_STMT(BPF_RET + BPF_K, 0), - /* Load frame header length into X. */ - BPF_STMT(BPF_LDX + BPF_W + BPF_IMM, sizeof(struct ether_header)), - /* Copy frame header length to memory */ - BPF_STMT(BPF_STX, BPF_M_FHLEN), + /* Advance to the IP header. */ + BPF_STMT(BPF_LDX + BPF_K, sizeof(struct ether_header)), }; #define BPF_BOOTP_ETHER_LEN __arraycount(bpf_bootp_ether) +#define BOOTP_MIN_SIZE sizeof(struct ip) + sizeof(struct udphdr) + \ + sizeof(struct bootp) + static const struct bpf_insn bpf_bootp_filter[] = { /* Make sure it's an IPv4 packet. */ BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0), @@ -588,15 +574,6 @@ static const struct bpf_insn bpf_bootp_f BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x40, 1, 0), BPF_STMT(BPF_RET + BPF_K, 0), - /* Ensure IP header length is big enough and - * store the IP header length in memory. */ - BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0), - BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x0f), - BPF_STMT(BPF_ALU + BPF_MUL + BPF_K, 4), - BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ip), 1, 0), - BPF_STMT(BPF_RET + BPF_K, 0), - BPF_STMT(BPF_ST, BPF_M_IPHLEN), - /* Make sure it's a UDP packet. */ BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct ip, ip_p)), BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0), @@ -607,49 +584,17 @@ static const struct bpf_insn bpf_bootp_f BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 0, 1), BPF_STMT(BPF_RET + BPF_K, 0), - /* Store IP length. */ - BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct ip, ip_len)), - BPF_STMT(BPF_ST, BPF_M_IPLEN), - /* Advance to the UDP header. */ - BPF_STMT(BPF_LD + BPF_MEM, BPF_M_IPHLEN), + BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0), + BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x0f), + BPF_STMT(BPF_ALU + BPF_MUL + BPF_K, 4), BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0), BPF_STMT(BPF_MISC + BPF_TAX, 0), - /* Store UDP location */ - BPF_STMT(BPF_STX, BPF_M_UDP), - /* Make sure it's from and to the right port. */ BPF_STMT(BPF_LD + BPF_W + BPF_IND, 0), BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (BOOTPS << 16) + BOOTPC, 1, 0), BPF_STMT(BPF_RET + BPF_K, 0), - - /* Store UDP length. */ - BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct udphdr, uh_ulen)), - BPF_STMT(BPF_ST, BPF_M_UDPLEN), - - /* Ensure that UDP length + IP header length == IP length */ - /* Copy IP header length to X. */ - BPF_STMT(BPF_LDX + BPF_MEM, BPF_M_IPHLEN), - /* Add UDP length (A) to IP header length (X). */ - BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0), - /* Store result in X. */ - BPF_STMT(BPF_MISC + BPF_TAX, 0), - /* Copy IP length to A. */ - BPF_STMT(BPF_LD + BPF_MEM, BPF_M_IPLEN), - /* Ensure X == A. */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), - BPF_STMT(BPF_RET + BPF_K, 0), - - /* Advance to the BOOTP packet. */ - BPF_STMT(BPF_LD + BPF_MEM, BPF_M_UDP), - BPF_STMT(BPF_ALU + BPF_ADD + BPF_K, sizeof(struct udphdr)), - BPF_STMT(BPF_MISC + BPF_TAX, 0), - - /* Make sure it's BOOTREPLY. */ - BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct bootp, op)), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTREPLY, 1, 0), - BPF_STMT(BPF_RET + BPF_K, 0), }; #define BPF_BOOTP_FILTER_LEN __arraycount(bpf_bootp_filter) @@ -729,14 +674,8 @@ bpf_bootp(struct interface *ifp, int fd) } #endif - /* All passed, return the packet - frame length + ip length */ - BPF_SET_STMT(bp, BPF_LD + BPF_MEM, BPF_M_FHLEN); - bp++; - BPF_SET_STMT(bp, BPF_LDX + BPF_MEM, BPF_M_IPLEN); - bp++; - BPF_SET_STMT(bp, BPF_ALU + BPF_ADD + BPF_X, 0); - bp++; - BPF_SET_STMT(bp, BPF_RET + BPF_A, 0); + /* All passed, return the packet. */ + BPF_SET_STMT(bp, BPF_RET + BPF_K, BPF_WHOLEPACKET); bp++; return bpf_attach(fd, bpf, (unsigned int)(bp - bpf)); Index: src/external/bsd/dhcpcd/dist/src/dhcp6.c diff -u src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.12 src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.13 --- src/external/bsd/dhcpcd/dist/src/dhcp6.c:1.12 Wed Sep 4 13:28:56 2019 +++ src/external/bsd/dhcpcd/dist/src/dhcp6.c Fri Oct 11 11:03:59 2019 @@ -532,13 +532,6 @@ dhcp6_delegateaddr(struct in6_addr *addr asla.prefix_len = 0; asla.sla_set = 0; sla = &asla; - } else if (sla->sla == 0 && sla->prefix_len == 0) { - /* An SLA of 0 was set with no prefix length specified. - * This means we delegate the whole prefix. */ - asla.sla = sla->sla; - asla.prefix_len = prefix->prefix_len; - asla.sla_set = 0; - sla = &asla; } else if (sla->prefix_len == 0) { /* An SLA was given, but prefix length was not. * We need to work out a suitable prefix length for @@ -680,27 +673,21 @@ dhcp6_makemessage(struct interface *ifp) break; } if (n < ifo->dhcp6_override_len) - continue; - if (!(opt->type & OT_NOREQ) && - (opt->type & OT_REQUEST || - has_option_mask(ifo->requestmask6, opt->option))) - { - n_options++; - len += sizeof(o.len); - } + continue; + if (!DHC_REQOPT(opt, ifo->requestmask6, ifo->nomask6)) + continue; + n_options++; + len += sizeof(o.len); } #ifndef SMALL for (l = 0, opt = ifo->dhcp6_override; l < ifo->dhcp6_override_len; l++, opt++) { - if (!(opt->type & OT_NOREQ) && - (opt->type & OT_REQUEST || - has_option_mask(ifo->requestmask6, opt->option))) - { - n_options++; - len += sizeof(o.len); - } + if (!DHC_REQOPT(opt, ifo->requestmask6, ifo->nomask6)) + continue; + n_options++; + len += sizeof(o.len); } if (dhcp6_findselfsla(ifp)) { n_options++; @@ -1037,7 +1024,8 @@ dhcp6_makemessage(struct interface *ifp) #ifdef AUTH if ((ifo->auth.options & DHCPCD_AUTH_SENDREQUIRE) != - DHCPCD_AUTH_SENDREQUIRE) + DHCPCD_AUTH_SENDREQUIRE && + !has_option_mask(ifo->nomask6, D6_OPTION_RECONF_ACCEPT)) COPYIN1(D6_OPTION_RECONF_ACCEPT, 0); #endif @@ -1060,34 +1048,26 @@ dhcp6_makemessage(struct interface *ifp) if (n < ifo->dhcp6_override_len) continue; #endif - if (!(opt->type & OT_NOREQ) && - (opt->type & OT_REQUEST || - has_option_mask(ifo->requestmask6, - opt->option))) - { - o.code = htons((uint16_t)opt->option); - memcpy(p, &o.code, sizeof(o.code)); - p += sizeof(o.code); - o.len = (uint16_t) - (o.len + sizeof(o.code)); - } + if (!DHC_REQOPT(opt, ifo->requestmask6, + ifo->nomask6)) + continue; + o.code = htons((uint16_t)opt->option); + memcpy(p, &o.code, sizeof(o.code)); + p += sizeof(o.code); + o.len = (uint16_t)(o.len + sizeof(o.code)); } #ifndef SMALL for (l = 0, opt = ifo->dhcp6_override; l < ifo->dhcp6_override_len; l++, opt++) { - if (!(opt->type & OT_NOREQ) && - (opt->type & OT_REQUEST || - has_option_mask(ifo->requestmask6, - opt->option))) - { - o.code = htons((uint16_t)opt->option); - memcpy(p, &o.code, sizeof(o.code)); - p += sizeof(o.code); - o.len = (uint16_t) - (o.len + sizeof(o.code)); - } + if (!DHC_REQOPT(opt, ifo->requestmask6, + ifo->nomask6)) + continue; + o.code = htons((uint16_t)opt->option); + memcpy(p, &o.code, sizeof(o.code)); + p += sizeof(o.code); + o.len = (uint16_t)(o.len + sizeof(o.code)); } if (dhcp6_findselfsla(ifp)) { o.code = htons(D6_OPTION_PD_EXCLUDE); @@ -3008,7 +2988,9 @@ dhcp6_bind(struct interface *ifp, const TAILQ_FOREACH(ia, &state->addrs, next) { if (ia->flags & IPV6_AF_STALE) continue; - if (ia->prefix_vltime <= state->renew) + if (!(state->renew == ND6_INFINITE_LIFETIME && + ia->prefix_vltime == ND6_INFINITE_LIFETIME) + && ia->prefix_vltime <= state->renew) logwarnx( "%s: %s will expire before renewal", ifp->name, ia->saddr); @@ -3152,6 +3134,8 @@ dhcp6_bind(struct interface *ifp, const if (state->state == DH6S_INFORMED) lognewinfo("%s: refresh in %"PRIu32" seconds", ifp->name, state->renew); + else if (state->renew == ND6_INFINITE_LIFETIME) + lognewinfo("%s: leased for infinity", ifp->name); else if (state->renew || state->rebind) lognewinfo("%s: renew in %"PRIu32", " "rebind in %"PRIu32", " Index: src/external/bsd/dhcpcd/dist/src/dhcp.c diff -u src/external/bsd/dhcpcd/dist/src/dhcp.c:1.27 src/external/bsd/dhcpcd/dist/src/dhcp.c:1.28 --- src/external/bsd/dhcpcd/dist/src/dhcp.c:1.27 Fri Sep 13 11:54:03 2019 +++ src/external/bsd/dhcpcd/dist/src/dhcp.c Fri Oct 11 11:03:59 2019 @@ -988,7 +988,8 @@ make_message(struct bootp **bootpm, cons #ifdef AUTH if ((ifo->auth.options & DHCPCD_AUTH_SENDREQUIRE) != - DHCPCD_AUTH_SENDREQUIRE) + DHCPCD_AUTH_SENDREQUIRE && + !has_option_mask(ifo->nomask, DHO_FORCERENEW_NONCE)) { /* We support HMAC-MD5 */ AREA_CHECK(1); @@ -1032,10 +1033,7 @@ make_message(struct bootp **bootpm, cons i < ifp->ctx->dhcp_opts_len; i++, opt++) { - if (!(opt->type & OT_REQUEST || - has_option_mask(ifo->requestmask, opt->option))) - continue; - if (opt->type & OT_NOREQ) + if (!DHC_REQOPT(opt, ifo->requestmask, ifo->nomask)) continue; if (type == DHCP_INFORM && (opt->option == DHO_RENEWALTIME || @@ -1054,10 +1052,7 @@ make_message(struct bootp **bootpm, cons break; if (lp < p) continue; - if (!(opt->type & OT_REQUEST || - has_option_mask(ifo->requestmask, opt->option))) - continue; - if (opt->type & OT_NOREQ) + if (!DHC_REQOPT(opt, ifo->requestmask, ifo->nomask)) continue; if (type == DHCP_INFORM && (opt->option == DHO_RENEWALTIME || @@ -1738,15 +1733,32 @@ send_message(struct interface *ifp, uint if (r == -1) goto fail; len = (size_t)r; - from.s_addr = bootp->ciaddr; - if (from.s_addr != INADDR_ANY) + + if (ipv4_iffindaddr(ifp, &state->lease.addr, NULL) != NULL) + from.s_addr = state->lease.addr.s_addr; + else + from.s_addr = INADDR_ANY; + if (from.s_addr != INADDR_ANY && + state->lease.server.s_addr != INADDR_ANY) to.s_addr = state->lease.server.s_addr; else - to.s_addr = INADDR_ANY; + to.s_addr = INADDR_BROADCAST; - /* If unicasting, try and avoid sending by BPF so we don't - * use a L2 broadcast. */ - if (to.s_addr != INADDR_ANY && to.s_addr != INADDR_BROADCAST) { + /* + * If not listening on the unspecified address we can + * only receive broadcast messages via BPF. + * Sockets bound to an address cannot receive broadcast messages + * even if they are setup to send them. + * Broadcasting from UDP is only an optimisation for rebinding + * and on BSD, at least, is reliant on the subnet route being + * correctly configured to recieve the unicast reply. + * As such, we always broadcast and receive the reply to it via BPF. + * This also guarantees we have a DHCP server attached to the + * interface we want to configure because we can't dictate the + * interface via IP_PKTINFO unlike for IPv6. + */ + if (to.s_addr != INADDR_BROADCAST) + { if (dhcp_sendudp(ifp, &to, bootp, len) != -1) goto out; logerr("%s: dhcp_sendudp", ifp->name); @@ -2001,30 +2013,44 @@ dhcp_finish_dad(struct interface *ifp, s } -static void +static bool dhcp_addr_duplicated(struct interface *ifp, struct in_addr *ia) { struct dhcp_state *state = D_STATE(ifp); + unsigned long long opts = ifp->options->options; + struct dhcpcd_ctx *ctx = ifp->ctx; + bool deleted = false; #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; + return deleted; /* 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) + if (!(opts & DHCPCD_STATIC) && !state->lease.frominfo) dhcp_decline(ifp); #ifdef IN_IFF_DUPLICATED - if ((iap = ipv4_iffindaddr(ifp, ia, NULL)) != NULL) + if ((iap = ipv4_iffindaddr(ifp, ia, NULL)) != NULL) { ipv4_deladdr(iap, 0); + deleted = true; + } #endif - eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); + eloop_timeout_delete(ctx->eloop, NULL, ifp); + if (opts & (DHCPCD_STATIC | DHCPCD_INFORM)) { + state->reason = "EXPIRE"; + script_runreason(ifp, state->reason); +#define NOT_ONLY_SELF (DHCPCD_MASTER | DHCPCD_IPV6RS | DHCPCD_DHCP6) + if (!(ctx->options & NOT_ONLY_SELF)) + eloop_exit(ifp->ctx->eloop, EXIT_FAILURE); + return deleted; + } eloop_timeout_add_sec(ifp->ctx->eloop, DHCP_RAND_MAX, dhcp_discover, ifp); + return deleted; } #endif @@ -2362,7 +2388,9 @@ dhcp_arp_address(struct interface *ifp) /* Add the address now, let the kernel handle DAD. */ ipv4_addaddr(ifp, &l.addr, &l.mask, &l.brd, l.leasetime, l.rebindtime); - } else + } else if (ia->addr_flags & IN_IFF_DUPLICATED) + dhcp_addr_duplicated(ifp, &ia->addr); + else loginfox("%s: waiting for DAD on %s", ifp->name, inet_ntoa(addr)); return 0; @@ -2841,14 +2869,18 @@ dhcp_handledhcp(struct interface *ifp, s #define LOGDHCP(l, m) \ log_dhcp((l), (m), ifp, bootp, bootp_len, from, 1) +#define IS_STATE_ACTIVE(s) ((s)-state != DHS_NONE && \ + (s)->state != DHS_INIT && (s)->state != DHS_BOUND) + if (bootp->op != BOOTREPLY) { - logdebugx("%s: op (%d) is not BOOTREPLY", - ifp->name, bootp->op); + if (IS_STATE_ACTIVE(state)) + logdebugx("%s: op (%d) is not BOOTREPLY", + ifp->name, bootp->op); return; } if (state->xid != ntohl(bootp->xid)) { - if (state->state != DHS_BOUND && state->state != DHS_NONE) + if (IS_STATE_ACTIVE(state)) logdebugx("%s: wrong xid 0x%x (expecting 0x%x) from %s", ifp->name, ntohl(bootp->xid), state->xid, inet_ntoa(*from)); @@ -2859,12 +2891,14 @@ dhcp_handledhcp(struct interface *ifp, s if (ifp->hwlen <= sizeof(bootp->chaddr) && memcmp(bootp->chaddr, ifp->hwaddr, ifp->hwlen)) { - char buf[sizeof(bootp->chaddr) * 3]; + if (IS_STATE_ACTIVE(state)) { + char buf[sizeof(bootp->chaddr) * 3]; - logdebugx("%s: xid 0x%x is for hwaddr %s", - ifp->name, ntohl(bootp->xid), - hwaddr_ntoa(bootp->chaddr, sizeof(bootp->chaddr), - buf, sizeof(buf))); + logdebugx("%s: xid 0x%x is for hwaddr %s", + ifp->name, ntohl(bootp->xid), + hwaddr_ntoa(bootp->chaddr, sizeof(bootp->chaddr), + buf, sizeof(buf))); + } dhcp_redirect_dhcp(ifp, bootp, bootp_len, from); return; } @@ -2959,10 +2993,7 @@ dhcp_handledhcp(struct interface *ifp, s } if (state->state == DHS_BOUND) { - /* Before we supported FORCERENEW we closed off the raw - * port so we effectively ignored all messages. - * As such we'll not log by default here. */ - //LOGDHCP(logdebugx, "bound, ignoring"); + LOGDHCP(logdebugx, "bound, ignoring"); return; } @@ -3239,9 +3270,40 @@ get_udp_data(void *packet, size_t *len) return p; } -static int -valid_udp_packet(void *packet, size_t plen, struct in_addr *from, - unsigned int flags) +static bool +is_packet_udp_bootp(void *packet, size_t plen) +{ + struct ip *ip = packet; + size_t ip_hlen; + struct udphdr *udp; + + if (sizeof(*ip) > plen) + return false; + + if (ip->ip_v != IPVERSION || ip->ip_p != IPPROTO_UDP) + return false; + + /* Sanity. */ + if (ntohs(ip->ip_len) != plen) + return false; + + ip_hlen = (size_t)ip->ip_hl * 4; + /* Check we have a UDP header and BOOTP. */ + if (ip_hlen + sizeof(*udp) + offsetof(struct bootp, vend) > plen) + return false; + + /* Check it's to and from the right ports. */ + udp = (struct udphdr *)(void *)((char *)ip + ip_hlen); + if (udp->uh_dport != htons(BOOTPC) || udp->uh_sport != htons(BOOTPS)) + return false; + + return true; +} + +/* Lengths have already been checked. */ +static bool +checksums_valid(void *packet, + struct in_addr *from, unsigned int flags) { struct ip *ip = packet; struct ip pseudo_ip = { @@ -3250,69 +3312,34 @@ valid_udp_packet(void *packet, size_t pl .ip_dst = ip->ip_dst }; size_t ip_hlen; - uint16_t ip_len, udp_len, uh_sum; + uint16_t udp_len, uh_sum; struct udphdr *udp; uint32_t csum; - if (plen < sizeof(*ip)) { - if (from != NULL) - from->s_addr = INADDR_ANY; - errno = ERANGE; - return -1; - } - if (from != NULL) from->s_addr = ip->ip_src.s_addr; - /* Check we have the IP header */ ip_hlen = (size_t)ip->ip_hl * 4; - if (ip_hlen > plen) { - errno = ENOBUFS; - return -1; - } + if (in_cksum(ip, ip_hlen, NULL) != 0) + return false; - if (in_cksum(ip, ip_hlen, NULL) != 0) { - errno = EINVAL; - return -1; - } - - /* Check we have a payload */ - ip_len = ntohs(ip->ip_len); - if (ip_len <= ip_hlen + sizeof(*udp)) { - errno = ERANGE; - return -1; - } - /* Check IP doesn't go beyond the payload */ - if (ip_len > plen) { - errno = ENOBUFS; - return -1; - } + if (flags & BPF_PARTIALCSUM) + return 0; - /* Check UDP doesn't go beyond the payload */ udp = (struct udphdr *)(void *)((char *)ip + ip_hlen); - udp_len = ntohs(udp->uh_ulen); - if (udp_len > plen - ip_hlen) { - errno = ENOBUFS; - return -1; - } - - if (udp->uh_sum == 0 || flags & BPF_PARTIALCSUM) + if (udp->uh_sum == 0) return 0; /* UDP checksum is based on a pseudo IP header alongside * the UDP header and payload. */ + udp_len = ntohs(udp->uh_ulen); uh_sum = udp->uh_sum; udp->uh_sum = 0; pseudo_ip.ip_len = udp->uh_ulen; csum = 0; in_cksum(&pseudo_ip, sizeof(pseudo_ip), &csum); csum = in_cksum(udp, udp_len, &csum); - if (csum != uh_sum) { - errno = EINVAL; - return -1; - } - - return 0; + return csum == uh_sum; } static void @@ -3321,13 +3348,12 @@ dhcp_handlebootp(struct interface *ifp, { size_t v; - /* udp_len must be correct because the values are checked in - * valid_udp_packet(). */ if (len < offsetof(struct bootp, vend)) { logerrx("%s: truncated packet (%zu) from %s", ifp->name, len, inet_ntoa(*from)); return; } + /* To make our IS_DHCP macro easy, ensure the vendor * area has at least 4 octets. */ v = len - offsetof(struct bootp, vend); @@ -3340,21 +3366,24 @@ dhcp_handlebootp(struct interface *ifp, } static void -dhcp_handlepacket(struct interface *ifp, uint8_t *data, size_t len) +dhcp_handlebpf(struct interface *ifp, uint8_t *data, size_t len) { struct bootp *bootp; struct in_addr from; size_t udp_len; const struct dhcp_state *state = D_CSTATE(ifp); - if (valid_udp_packet(data, len, &from, state->bpf_flags) == -1) { - const char *errstr; + /* Validate filter. */ + if (!is_packet_udp_bootp(data, len)) { +#ifdef BPF_DEBUG + logerrx("%s: DHCP BPF validation failure", ifp->name); +#endif + return; + } - if (errno == EINVAL) - errstr = "checksum failure"; - else - errstr = "invalid UDP packet"; - logerrx("%s: %s from %s", errstr, ifp->name, inet_ntoa(from)); + if (!checksums_valid(data, &from, state->bpf_flags)) { + logerrx("%s: checksum failure from %s", + ifp->name, inet_ntoa(from)); return; } @@ -3370,7 +3399,7 @@ dhcp_handlepacket(struct interface *ifp, } static void -dhcp_readpacket(void *arg) +dhcp_readbpf(void *arg) { struct interface *ifp = arg; uint8_t buf[MTU_MAX]; @@ -3392,7 +3421,7 @@ dhcp_readpacket(void *arg) } break; } - dhcp_handlepacket(ifp, buf, (size_t)bytes); + dhcp_handlebpf(ifp, buf, (size_t)bytes); /* Check we still have a state after processing. */ if ((state = D_STATE(ifp)) == NULL) break; @@ -3505,7 +3534,7 @@ dhcp_openbpf(struct interface *ifp) } eloop_event_add(ifp->ctx->eloop, - state->bpf_fd, dhcp_readpacket, ifp); + state->bpf_fd, dhcp_readbpf, ifp); return 0; } @@ -3937,7 +3966,7 @@ dhcp_abort(struct interface *ifp) } } -void +struct ipv4_addr * dhcp_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid) { struct interface *ifp; @@ -3948,7 +3977,7 @@ dhcp_handleifa(int cmd, struct ipv4_addr ifp = ia->iface; state = D_STATE(ifp); if (state == NULL || state->state == DHS_NONE) - return; + return ia; if (cmd == RTM_DELADDR) { if (state->addr == ia) { @@ -3959,37 +3988,37 @@ dhcp_handleifa(int cmd, struct ipv4_addr * to drop the lease. */ dhcp_drop(ifp, "EXPIRE"); dhcp_start1(ifp); + return NULL; } - return; } if (cmd != RTM_NEWADDR) - return; + return ia; #ifdef IN_IFF_NOTUSEABLE 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); + return dhcp_addr_duplicated(ifp, &ia->addr) ? NULL : ia; #endif ifo = ifp->options; if (ifo->options & DHCPCD_INFORM) { if (state->state != DHS_INFORM) dhcp_inform(ifp); - return; + return ia; } if (!(ifo->options & DHCPCD_STATIC)) - return; + return ia; if (ifo->req_addr.s_addr != INADDR_ANY) - return; + return ia; free(state->old); state->old = state->new; state->new_len = dhcp_message_new(&state->new, &ia->addr, &ia->mask); if (state->new == NULL) - return; + return ia; if (ifp->flags & IFF_POINTOPOINT) { for (i = 1; i < 255; i++) if (i != DHO_ROUTER && has_option_mask(ifo->dstmask,i)) @@ -4005,4 +4034,6 @@ dhcp_handleifa(int cmd, struct ipv4_addr state->addr = ia; dhcp_inform(ifp); } + + return ia; } Index: src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in diff -u src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in:1.3 src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in:1.4 --- src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in:1.3 Wed Sep 4 13:28:56 2019 +++ src/external/bsd/dhcpcd/dist/src/dhcpcd.8.in Fri Oct 11 11:03:59 2019 @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 28, 2019 +.Dd October 9, 2019 .Dt DHCPCD 8 .Os .Sh NAME @@ -203,6 +203,15 @@ changes the routes to use the interface metric. See options below for controlling which interfaces we allow and deny through the use of patterns. +.Pp +Non-ethernet interfaces and some virtual ethernet interfaces +such as TAP and bridge are ignored by default, +as is the FireWire interface. +To work with these devices they either need to be specified on the command line, +be listed in +.Fl Fl allowinterfaces +or have an interface directive in +.Pa @SYSCONFDIR@/dhcpcd.conf . .Ss Hooking into events .Nm runs Index: src/external/bsd/dhcpcd/dist/src/dhcpcd.c diff -u src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.26 src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.27 --- src/external/bsd/dhcpcd/dist/src/dhcpcd.c:1.26 Fri Sep 13 11:01:50 2019 +++ src/external/bsd/dhcpcd/dist/src/dhcpcd.c Fri Oct 11 11:03:59 2019 @@ -1094,8 +1094,13 @@ static void dhcpcd_checkcarrier(void *arg) { struct interface *ifp = arg; + int carrier; - dhcpcd_handlecarrier(ifp->ctx, LINK_UNKNOWN, ifp->flags, ifp->name); + /* Check carrier here rather than setting LINK_UNKNOWN. + * This is because we force LINK_UNKNOWN as down for wireless which + * we do not want when dealing with a route socket overflow. */ + carrier = if_carrier(ifp); + dhcpcd_handlecarrier(ifp->ctx, carrier, ifp->flags, ifp->name); } #ifndef SMALL Index: src/external/bsd/dhcpcd/dist/src/if-bsd.c diff -u src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.13 src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.14 --- src/external/bsd/dhcpcd/dist/src/if-bsd.c:1.13 Fri Sep 13 11:01:50 2019 +++ src/external/bsd/dhcpcd/dist/src/if-bsd.c Fri Oct 11 11:03:59 2019 @@ -101,6 +101,14 @@ #define RT_ADVANCE(x, n) (x += RT_ROUNDUP((n)->sa_len)) #endif +/* Ignore these interface names which look like ethernet but are virtual. */ +static const char * const ifnames_ignore[] = { + "bridge", + "fwe", /* Firewire */ + "tap", + NULL +}; + #ifdef INET6 static void ifa_setscope(struct sockaddr_in6 *, unsigned int); static unsigned int ifa_getscope(const struct sockaddr_in6 *); @@ -208,6 +216,61 @@ if_closesockets_os(struct dhcpcd_ctx *ct close(priv->pf_inet6_fd); } +static bool +if_ignore1(const char *drvname) +{ + const char * const *p; + + for (p = ifnames_ignore; *p; p++) { + if (strcmp(*p, drvname) == 0) + return true; + } + return false; +} + +bool +if_ignore(struct dhcpcd_ctx *ctx, const char *ifname) +{ + struct if_spec spec; + + if (if_nametospec(ifname, &spec) != 0) + return false; + + if (if_ignore1(spec.drvname)) + return true; + +#ifdef SIOCGIFGROUP + struct ifgroupreq ifgr = { .ifgr_len = 0 }; + struct ifg_req *ifg; + size_t ifg_len; + + /* Sadly it is possible to remove the device name + * from the interface groups, but hopefully this + * will be very unlikely.... */ + + strlcpy(ifgr.ifgr_name, ifname, sizeof(ifgr.ifgr_name)); + if (ioctl(ctx->pf_inet_fd, SIOCGIFGROUP, &ifgr) == -1 || + (ifgr.ifgr_groups = malloc(ifgr.ifgr_len)) == NULL || + ioctl(ctx->pf_inet_fd, SIOCGIFGROUP, &ifgr) == -1) + { + logerr(__func__); + return false; + } + + for (ifg = ifgr.ifgr_groups, ifg_len = ifgr.ifgr_len; + ifg && ifg_len >= sizeof(*ifg); + ifg++, ifg_len -= sizeof(*ifg)) + { + if (if_ignore1(ifg->ifgrq_group)) + return true; + } +#else + UNUSED(ctx); +#endif + + return false; +} + int if_carrier(struct interface *ifp) { Index: src/external/bsd/dhcpcd/dist/src/if-options.c diff -u src/external/bsd/dhcpcd/dist/src/if-options.c:1.17 src/external/bsd/dhcpcd/dist/src/if-options.c:1.18 --- src/external/bsd/dhcpcd/dist/src/if-options.c:1.17 Wed Aug 21 17:12:19 2019 +++ src/external/bsd/dhcpcd/dist/src/if-options.c Fri Oct 11 11:03:59 2019 @@ -520,7 +520,7 @@ parse_addr(__unused struct in_addr *addr } #endif -static const char * +static void set_option_space(struct dhcpcd_ctx *ctx, const char *arg, const struct dhcp_opt **d, size_t *dl, @@ -543,7 +543,7 @@ set_option_space(struct dhcpcd_ctx *ctx, *require = ifo->requiremasknd; *no = ifo->nomasknd; *reject = ifo->rejectmasknd; - return arg + strlen("nd_"); + return; } #ifdef DHCP6 @@ -556,7 +556,7 @@ set_option_space(struct dhcpcd_ctx *ctx, *require = ifo->requiremask6; *no = ifo->nomask6; *reject = ifo->rejectmask6; - return arg + strlen("dhcp6_"); + return; } #endif #endif @@ -576,7 +576,6 @@ set_option_space(struct dhcpcd_ctx *ctx, *require = ifo->requiremask; *no = ifo->nomask; *reject = ifo->rejectmask; - return arg; } void @@ -806,7 +805,7 @@ parse_option(struct dhcpcd_ctx *ctx, con break; case 'o': ARG_REQUIRED; - arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, + set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, &request, &require, &no, &reject); if (make_option_mask(d, dl, od, odl, request, arg, 1) != 0 || make_option_mask(d, dl, od, odl, no, arg, -1) != 0 || @@ -818,7 +817,7 @@ parse_option(struct dhcpcd_ctx *ctx, con break; case O_REJECT: ARG_REQUIRED; - arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, + set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, &request, &require, &no, &reject); if (make_option_mask(d, dl, od, odl, reject, arg, 1) != 0 || make_option_mask(d, dl, od, odl, request, arg, -1) != 0 || @@ -1053,7 +1052,7 @@ parse_option(struct dhcpcd_ctx *ctx, con break; case 'O': ARG_REQUIRED; - arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, + set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, &request, &require, &no, &reject); if (make_option_mask(d, dl, od, odl, request, arg, -1) != 0 || make_option_mask(d, dl, od, odl, require, arg, -1) != 0 || @@ -1065,7 +1064,7 @@ parse_option(struct dhcpcd_ctx *ctx, con break; case 'Q': ARG_REQUIRED; - arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, + set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, &request, &require, &no, &reject); if (make_option_mask(d, dl, od, odl, require, arg, 1) != 0 || make_option_mask(d, dl, od, odl, request, arg, 1) != 0 || @@ -1253,7 +1252,7 @@ parse_option(struct dhcpcd_ctx *ctx, con break; case O_DESTINATION: ARG_REQUIRED; - arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, + set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo, &request, &require, &no, &reject); if (make_option_mask(d, dl, od, odl, ifo->dstmask, arg, 2) != 0)