Import dhcpcd-8.0.2 with the following changes:
* NetBSD: Can be build without ARP support but listen to kernel DaD * ND6: Removed NA support from SMALL builds * DHCP: Avoid duplicate read of UDP socket when BPF is also open * IP: Avoid adding address if already exists on OS other than Linux * route: Fixed a NULL de-reference error on static routes * DHCP6: Move to REQUEST if any IA has no-binding in REWNEW/REBIND * IP: Accept packets with IP header options
This commit is contained in:
parent
cb0b7d2b9f
commit
b6a3a94eb1
|
@ -1,7 +1,9 @@
|
|||
# Start, reconfigure and stop wpa_supplicant per wireless interface.
|
||||
# This is needed because wpa_supplicant lacks hotplugging of any kind
|
||||
# and the user should not be expected to have to wire it into their system
|
||||
# if the base system doesn't do this itself.
|
||||
#
|
||||
# This is only needed when using wpa_supplicant-2.5 or older, OR
|
||||
# when wpa_supplicant has not been built with CONFIG_MATCH_IFACE, OR
|
||||
# wpa_supplicant was launched without the -M flag to activate
|
||||
# interface matching.
|
||||
|
||||
if [ -z "$wpa_supplicant_conf" ]; then
|
||||
for x in \
|
||||
|
|
|
@ -93,7 +93,7 @@ bpf_frame_header_len(const struct interface *ifp)
|
|||
}
|
||||
}
|
||||
|
||||
static const uint8_t etherbroadcastaddr[] =
|
||||
static const uint8_t etherbcastaddr[] =
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
int
|
||||
|
@ -104,7 +104,7 @@ bpf_frame_bcast(const struct interface *ifp, const char *frame)
|
|||
case ARPHRD_ETHER:
|
||||
return memcmp(frame +
|
||||
offsetof(struct ether_header, ether_dhost),
|
||||
etherbroadcastaddr, sizeof(etherbroadcastaddr));
|
||||
etherbcastaddr, sizeof(etherbcastaddr));
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
@ -552,6 +552,12 @@ 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
|
||||
|
||||
static const struct bpf_insn bpf_bootp_ether[] = {
|
||||
/* Make sure this is an IP packet. */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_ABS,
|
||||
|
@ -561,17 +567,27 @@ static const struct bpf_insn bpf_bootp_ether[] = {
|
|||
|
||||
/* Load frame header length into X. */
|
||||
BPF_STMT(BPF_LDX + BPF_W + BPF_IMM, sizeof(struct ether_header)),
|
||||
/* Copy to M0. */
|
||||
BPF_STMT(BPF_STX, 0),
|
||||
/* Copy frame header length to memory */
|
||||
BPF_STMT(BPF_STX, BPF_M_FHLEN),
|
||||
};
|
||||
#define BPF_BOOTP_ETHER_LEN __arraycount(bpf_bootp_ether)
|
||||
|
||||
static const struct bpf_insn bpf_bootp_filter[] = {
|
||||
/* Make sure it's an optionless IPv4 packet. */
|
||||
/* Make sure it's an IPv4 packet. */
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_IND, 0),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x45, 1, 0),
|
||||
BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0xf0),
|
||||
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),
|
||||
|
@ -582,39 +598,42 @@ static const struct bpf_insn bpf_bootp_filter[] = {
|
|||
BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 0, 1),
|
||||
BPF_STMT(BPF_RET + BPF_K, 0),
|
||||
|
||||
/* Store IP location in M1. */
|
||||
/* Store IP length. */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct ip, ip_len)),
|
||||
BPF_STMT(BPF_ST, 1),
|
||||
|
||||
/* Store IP length in M2. */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct ip, ip_len)),
|
||||
BPF_STMT(BPF_ST, 2),
|
||||
BPF_STMT(BPF_ST, BPF_M_IPLEN),
|
||||
|
||||
/* Advance to the UDP header. */
|
||||
BPF_STMT(BPF_MISC + BPF_TXA, 0),
|
||||
BPF_STMT(BPF_ALU + BPF_ADD + BPF_K, sizeof(struct ip)),
|
||||
BPF_STMT(BPF_LD + BPF_MEM, BPF_M_IPHLEN),
|
||||
BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0),
|
||||
BPF_STMT(BPF_MISC + BPF_TAX, 0),
|
||||
|
||||
/* Store X in M3. */
|
||||
BPF_STMT(BPF_STX, 3),
|
||||
/* 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 in X. */
|
||||
/* 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 in M2 to A. */
|
||||
BPF_STMT(BPF_LD + BPF_MEM, 2),
|
||||
/* Ensure IP length - IP header size == UDP length. */
|
||||
BPF_STMT(BPF_ALU + BPF_SUB + BPF_K, sizeof(struct ip)),
|
||||
/* 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 (UDP X is in M3). */
|
||||
BPF_STMT(BPF_LD + BPF_MEM, 3),
|
||||
/* 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),
|
||||
|
||||
|
@ -695,11 +714,10 @@ bpf_bootp(struct interface *ifp, int fd)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* All passed, return the packet
|
||||
* (Frame length in M0, IP length in M2). */
|
||||
BPF_SET_STMT(bp, BPF_LD + BPF_MEM, 0);
|
||||
/* 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, 2);
|
||||
BPF_SET_STMT(bp, BPF_LDX + BPF_MEM, BPF_M_IPLEN);
|
||||
bp++;
|
||||
BPF_SET_STMT(bp, BPF_ALU + BPF_ADD + BPF_X, 0);
|
||||
bp++;
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#define CONFIG_H
|
||||
|
||||
#define PACKAGE "dhcpcd"
|
||||
#define VERSION "8.0.1"
|
||||
#define VERSION "8.0.2"
|
||||
|
||||
#ifndef CONFIG
|
||||
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"
|
||||
|
|
|
@ -2329,7 +2329,9 @@ dhcp_arp_new(struct interface *ifp, struct in_addr *addr)
|
|||
return astate;
|
||||
}
|
||||
#endif
|
||||
#endif /* ARP */
|
||||
|
||||
#if defined(ARP) || defined(KERNEL_RFC5227)
|
||||
static int
|
||||
dhcp_arp_address(struct interface *ifp)
|
||||
{
|
||||
|
@ -2417,7 +2419,7 @@ dhcp_static(struct interface *ifp)
|
|||
ia ? &ia->addr : &ifo->req_addr,
|
||||
ia ? &ia->mask : &ifo->req_mask);
|
||||
if (state->offer_len)
|
||||
#ifdef ARP
|
||||
#if defined(ARP) || defined(KERNEL_RFC5227)
|
||||
dhcp_arp_bind(ifp);
|
||||
#else
|
||||
dhcp_bind(ifp);
|
||||
|
@ -3210,7 +3212,7 @@ rapidcommit:
|
|||
lease->frominfo = 0;
|
||||
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
|
||||
|
||||
#ifdef ARP
|
||||
#if defined(ARP) || defined(KERNEL_RFC5227)
|
||||
dhcp_arp_bind(ifp);
|
||||
#else
|
||||
dhcp_bind(ifp);
|
||||
|
@ -3218,70 +3220,80 @@ rapidcommit:
|
|||
}
|
||||
|
||||
static void *
|
||||
get_udp_data(void *udp, size_t *len)
|
||||
get_udp_data(void *packet, size_t *len)
|
||||
{
|
||||
struct bootp_pkt *p;
|
||||
const struct ip *ip = packet;
|
||||
size_t ip_hl = (size_t)ip->ip_hl * 4;
|
||||
char *p = packet;
|
||||
|
||||
p = (struct bootp_pkt *)udp;
|
||||
*len = (size_t)ntohs(p->ip.ip_len) - sizeof(p->ip) - sizeof(p->udp);
|
||||
return (char *)udp + offsetof(struct bootp_pkt, bootp);
|
||||
p += ip_hl + sizeof(struct udphdr);
|
||||
*len = (size_t)ntohs(ip->ip_len) - sizeof(struct udphdr) - ip_hl;
|
||||
return p;
|
||||
}
|
||||
|
||||
static int
|
||||
valid_udp_packet(void *data, size_t data_len, struct in_addr *from,
|
||||
int noudpcsum)
|
||||
valid_udp_packet(void *packet, size_t plen, struct in_addr *from,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct bootp_pkt *p;
|
||||
uint16_t bytes;
|
||||
struct ip *ip = packet;
|
||||
char ip_hlv = *(char *)ip;
|
||||
size_t ip_hlen;
|
||||
uint16_t ip_len, uh_sum;
|
||||
struct udphdr *udp;
|
||||
|
||||
if (data_len < sizeof(p->ip)) {
|
||||
if (from)
|
||||
if (plen < sizeof(*ip)) {
|
||||
if (from != NULL)
|
||||
from->s_addr = INADDR_ANY;
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
p = (struct bootp_pkt *)data;
|
||||
if (from)
|
||||
from->s_addr = p->ip.ip_src.s_addr;
|
||||
if (checksum(&p->ip, sizeof(p->ip)) != 0) {
|
||||
|
||||
if (from != NULL)
|
||||
from->s_addr = ip->ip_src.s_addr;
|
||||
|
||||
ip_hlen = (size_t)ip->ip_hl * 4;
|
||||
if (checksum(ip, ip_hlen) != 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bytes = ntohs(p->ip.ip_len);
|
||||
ip_len = ntohs(ip->ip_len);
|
||||
/* Check we have a payload */
|
||||
if (bytes <= sizeof(p->ip) + sizeof(p->udp)) {
|
||||
if (ip_len <= ip_hlen + sizeof(*udp)) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
/* Check we don't go beyond the payload */
|
||||
if (bytes > data_len) {
|
||||
if (ip_len > plen) {
|
||||
errno = ENOBUFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (noudpcsum == 0) {
|
||||
uint16_t udpsum, iplen;
|
||||
if (flags & BPF_PARTIALCSUM)
|
||||
return 0;
|
||||
|
||||
/* This does scribble on the packet, but at this point
|
||||
* we don't care to keep it. */
|
||||
iplen = p->ip.ip_len;
|
||||
udpsum = p->udp.uh_sum;
|
||||
p->udp.uh_sum = 0;
|
||||
p->ip.ip_hl = 0;
|
||||
p->ip.ip_v = 0;
|
||||
p->ip.ip_tos = 0;
|
||||
p->ip.ip_len = p->udp.uh_ulen;
|
||||
p->ip.ip_id = 0;
|
||||
p->ip.ip_off = 0;
|
||||
p->ip.ip_ttl = 0;
|
||||
p->ip.ip_sum = 0;
|
||||
if (udpsum && checksum(p, bytes) != udpsum) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
p->ip.ip_len = iplen;
|
||||
udp = (struct udphdr *)((char *)ip + ip_hlen);
|
||||
if (udp->uh_sum == 0)
|
||||
return 0;
|
||||
uh_sum = udp->uh_sum;
|
||||
|
||||
/* This does scribble on the packet, but at this point
|
||||
* we don't care to keep it. */
|
||||
udp->uh_sum = 0;
|
||||
ip->ip_hl = 0;
|
||||
ip->ip_v = 0;
|
||||
ip->ip_tos = 0;
|
||||
ip->ip_len = udp->uh_ulen;
|
||||
ip->ip_id = 0;
|
||||
ip->ip_off = 0;
|
||||
ip->ip_ttl = 0;
|
||||
ip->ip_sum = 0;
|
||||
if (checksum(packet, ip_len) != uh_sum) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
*(char *)ip = ip_hlv;
|
||||
ip->ip_len = htons(ip_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -3318,9 +3330,7 @@ dhcp_handlepacket(struct interface *ifp, uint8_t *data, size_t len)
|
|||
size_t udp_len;
|
||||
const struct dhcp_state *state = D_CSTATE(ifp);
|
||||
|
||||
if (valid_udp_packet(data, len, &from,
|
||||
state->bpf_flags & RAW_PARTIALCSUM) == -1)
|
||||
{
|
||||
if (valid_udp_packet(data, len, &from, state->bpf_flags) == -1) {
|
||||
if (errno == EINVAL)
|
||||
logerrx("%s: checksum failure from %s",
|
||||
ifp->name, inet_ntoa(from));
|
||||
|
@ -3382,6 +3392,7 @@ dhcp_readpacket(void *arg)
|
|||
static void
|
||||
dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp)
|
||||
{
|
||||
const struct dhcp_state *state;
|
||||
struct sockaddr_in from;
|
||||
unsigned char buf[10 * 1024]; /* Maximum MTU */
|
||||
struct iovec iov = {
|
||||
|
@ -3403,8 +3414,7 @@ dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp)
|
|||
ssize_t bytes;
|
||||
|
||||
if (ifp != NULL) {
|
||||
const struct dhcp_state *state = D_CSTATE(ifp);
|
||||
|
||||
state = D_CSTATE(ifp);
|
||||
s = state->udp_fd;
|
||||
} else
|
||||
s = ctx->udp_fd;
|
||||
|
@ -3424,13 +3434,19 @@ dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp)
|
|||
logerr(__func__);
|
||||
return;
|
||||
}
|
||||
if (D_CSTATE(ifp) == NULL) {
|
||||
state = D_CSTATE(ifp);
|
||||
if (state == NULL) {
|
||||
logdebugx("%s: received BOOTP for inactive interface",
|
||||
ifp->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->bpf_fd != -1) {
|
||||
/* Avoid a duplicate read if BPF is open for the interface. */
|
||||
return;
|
||||
}
|
||||
|
||||
dhcp_handlebootp(ifp, (struct bootp *)(void *)buf, (size_t)bytes,
|
||||
&from.sin_addr);
|
||||
#endif
|
||||
|
|
|
@ -1523,7 +1523,9 @@ dhcp6_dadcallback(void *arg)
|
|||
if (valid)
|
||||
dhcpcd_daemonise(ifp->ctx);
|
||||
}
|
||||
#ifdef ND6_ADVERTISE
|
||||
ipv6nd_advertise(ia);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1936,6 +1938,7 @@ dhcp6_checkstatusok(const struct interface *ifp,
|
|||
if ((opt = f(farg, len, D6_OPTION_STATUS_CODE, &opt_len)) == NULL) {
|
||||
//logdebugx("%s: no status", ifp->name);
|
||||
state->lerror = 0;
|
||||
errno = ESRCH;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1947,7 +1950,8 @@ dhcp6_checkstatusok(const struct interface *ifp,
|
|||
code = ntohs(code);
|
||||
if (code == D6_STATUS_OK) {
|
||||
state->lerror = 0;
|
||||
return 1;
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Anything after the code is a message. */
|
||||
|
@ -1978,7 +1982,8 @@ dhcp6_checkstatusok(const struct interface *ifp,
|
|||
logfunc("%s: DHCPv6 REPLY: %s", ifp->name, status);
|
||||
free(sbuf);
|
||||
state->lerror = code;
|
||||
return -1;
|
||||
errno = 0;
|
||||
return (int)code;
|
||||
}
|
||||
|
||||
const struct ipv6_addr *
|
||||
|
@ -2225,7 +2230,7 @@ dhcp6_findia(struct interface *ifp, struct dhcp6_message *m, size_t l,
|
|||
struct dhcp6_option o;
|
||||
uint8_t *d, *p;
|
||||
struct dhcp6_ia_na ia;
|
||||
int i, e;
|
||||
int i, e, error;
|
||||
size_t j;
|
||||
uint16_t nl;
|
||||
uint8_t iaid[4];
|
||||
|
@ -2314,7 +2319,9 @@ dhcp6_findia(struct interface *ifp, struct dhcp6_message *m, size_t l,
|
|||
}
|
||||
} else
|
||||
ia.t1 = ia.t2 = 0; /* appease gcc */
|
||||
if (dhcp6_checkstatusok(ifp, NULL, p, o.len) == -1) {
|
||||
if ((error = dhcp6_checkstatusok(ifp, NULL, p, o.len)) != 0) {
|
||||
if (error == D6_STATUS_NOBINDING)
|
||||
state->has_no_binding = true;
|
||||
e = 1;
|
||||
continue;
|
||||
}
|
||||
|
@ -2415,7 +2422,7 @@ dhcp6_validatelease(struct interface *ifp,
|
|||
const char *sfrom, const struct timespec *acquired)
|
||||
{
|
||||
struct dhcp6_state *state;
|
||||
int ok, nia;
|
||||
int nia, ok_errno;
|
||||
struct timespec aq;
|
||||
|
||||
if (len <= sizeof(*m)) {
|
||||
|
@ -2424,8 +2431,10 @@ dhcp6_validatelease(struct interface *ifp,
|
|||
}
|
||||
|
||||
state = D6_STATE(ifp);
|
||||
if ((ok = dhcp6_checkstatusok(ifp, m, NULL, len) == -1))
|
||||
errno = 0;
|
||||
if (dhcp6_checkstatusok(ifp, m, NULL, len) != 0)
|
||||
return -1;
|
||||
ok_errno = errno;
|
||||
|
||||
state->renew = state->rebind = state->expire = 0;
|
||||
state->lowpl = ND6_INFINITE_LIFETIME;
|
||||
|
@ -2433,9 +2442,10 @@ dhcp6_validatelease(struct interface *ifp,
|
|||
clock_gettime(CLOCK_MONOTONIC, &aq);
|
||||
acquired = &aq;
|
||||
}
|
||||
state->has_no_binding = false;
|
||||
nia = dhcp6_findia(ifp, m, len, sfrom, acquired);
|
||||
if (nia == 0) {
|
||||
if (state->state != DH6S_CONFIRM && ok != 1) {
|
||||
if (state->state != DH6S_CONFIRM && ok_errno != 0) {
|
||||
logerrx("%s: no useable IA found in lease", ifp->name);
|
||||
return -1;
|
||||
}
|
||||
|
@ -2445,6 +2455,7 @@ dhcp6_validatelease(struct interface *ifp,
|
|||
* IA's must have existed here otherwise we would
|
||||
* have rejected it earlier. */
|
||||
assert(state->new != NULL && state->new_len != 0);
|
||||
state->has_no_binding = false;
|
||||
nia = dhcp6_findia(ifp, state->new, state->new_len,
|
||||
sfrom, acquired);
|
||||
}
|
||||
|
@ -3267,7 +3278,7 @@ dhcp6_recvif(struct interface *ifp, const char *sfrom,
|
|||
case DHCP6_REPLY:
|
||||
switch(state->state) {
|
||||
case DH6S_INFORM:
|
||||
if (dhcp6_checkstatusok(ifp, r, NULL, len) == -1)
|
||||
if (dhcp6_checkstatusok(ifp, r, NULL, len) != 0)
|
||||
return;
|
||||
break;
|
||||
case DH6S_CONFIRM:
|
||||
|
@ -3315,6 +3326,14 @@ dhcp6_recvif(struct interface *ifp, const char *sfrom,
|
|||
dhcp6_startdiscover(ifp);
|
||||
return;
|
||||
}
|
||||
/* RFC8415 18.2.10.1 */
|
||||
if ((state->state == DH6S_RENEW ||
|
||||
state->state == DH6S_REBIND) &&
|
||||
state->has_no_binding)
|
||||
{
|
||||
dhcp6_startrequest(ifp);
|
||||
return;
|
||||
}
|
||||
if (state->state == DH6S_DISCOVER)
|
||||
state->state = DH6S_REQUEST;
|
||||
break;
|
||||
|
@ -3927,16 +3946,20 @@ dhcp6_free(struct interface *ifp)
|
|||
void
|
||||
dhcp6_abort(struct interface *ifp)
|
||||
{
|
||||
#ifdef ND6_ADVERTISE
|
||||
struct dhcp6_state *state;
|
||||
struct ipv6_addr *ia;
|
||||
#endif
|
||||
|
||||
eloop_timeout_delete(ifp->ctx->eloop, dhcp6_start1, ifp);
|
||||
#ifdef ND6_ADVERTISE
|
||||
state = D6_STATE(ifp);
|
||||
if (state == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(ia, &state->addrs, next) {
|
||||
ipv6nd_advertise(ia);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -208,6 +208,7 @@ struct dhcp6_state {
|
|||
char leasefile[sizeof(LEASEFILE6) + IF_NAMESIZE + (IF_SSIDLEN * 4) +3];
|
||||
const char *reason;
|
||||
uint16_t lerror; /* Last error received from DHCPv6 reply. */
|
||||
bool has_no_binding;
|
||||
struct authstate auth;
|
||||
};
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd July 23, 2019
|
||||
.Dd July 25, 2019
|
||||
.Dt DHCPCD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -234,12 +234,11 @@ and need to be copied to
|
|||
.Pa @HOOKDIR@
|
||||
if you intend to use them.
|
||||
For example, you could install
|
||||
.Pa 10-wpa_supplicant
|
||||
.Pa 29-lookup-hostname
|
||||
so that
|
||||
.Nm
|
||||
can ensure that
|
||||
.Xr wpa_supplicant 8
|
||||
is always running on a hot-plugged wireless interface.
|
||||
can lookup the hostname of the IP address in DNS if no hostname
|
||||
is given by the lease and one is not already set.
|
||||
.Ss Fine tuning
|
||||
You can fine-tune the behaviour of
|
||||
.Nm
|
||||
|
@ -404,10 +403,6 @@ is specified then this applies to all interfaces in Master mode.
|
|||
If
|
||||
.Nm
|
||||
is not running, then it starts up as normal.
|
||||
This may also cause
|
||||
.Xr wpa_supplicant 8
|
||||
to reload its configuration for each interface as well if the
|
||||
relevant hook script has been installed.
|
||||
.It Fl N , Fl Fl renew Op Ar interface
|
||||
Notifies
|
||||
.Nm
|
||||
|
|
|
@ -2125,13 +2125,13 @@ exit1:
|
|||
}
|
||||
free(ctx.ifaces);
|
||||
}
|
||||
free_options(&ctx, ifo);
|
||||
#ifdef HAVE_OPEN_MEMSTREAM
|
||||
if (ctx.script_fp)
|
||||
fclose(ctx.script_fp);
|
||||
#endif
|
||||
free(ctx.script_buf);
|
||||
free(ctx.script_env);
|
||||
free_options(&ctx, ifo);
|
||||
rt_dispose(&ctx);
|
||||
free(ctx.duid);
|
||||
if (ctx.link_fd != -1) {
|
||||
|
|
|
@ -51,6 +51,8 @@
|
|||
#include <netinet6/nd6.h>
|
||||
#ifdef __NetBSD__
|
||||
#include <net/if_vlanvar.h> /* Needs netinet/if_ether.h */
|
||||
#elif defined(__DragonFly__)
|
||||
#include <net/vlan/if_vlan_var.h>
|
||||
#else
|
||||
#include <net/if_vlan_var.h>
|
||||
#endif
|
||||
|
@ -541,7 +543,7 @@ if_route(unsigned char cmd, const struct rt *rt)
|
|||
* try to encourage someone to fix that by logging a waring during compile.
|
||||
*/
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
#warning OS does not allow IPv6 address sharing
|
||||
#warning kernel does not allow IPv6 address sharing
|
||||
if (!gateway_unspec || rt->rt_dest.sa_family!=AF_INET6)
|
||||
#endif
|
||||
rtm->rtm_addrs |= RTA_IFP;
|
||||
|
|
|
@ -2611,73 +2611,92 @@ void
|
|||
free_options(struct dhcpcd_ctx *ctx, struct if_options *ifo)
|
||||
{
|
||||
size_t i;
|
||||
#ifdef RT_FREE_ROUTE_TABLE
|
||||
struct interface *ifp;
|
||||
struct rt *rt;
|
||||
#endif
|
||||
struct dhcp_opt *opt;
|
||||
struct vivco *vo;
|
||||
#ifdef AUTH
|
||||
struct token *token;
|
||||
#endif
|
||||
|
||||
if (ifo) {
|
||||
if (ifo->environ) {
|
||||
i = 0;
|
||||
while (ifo->environ[i])
|
||||
free(ifo->environ[i++]);
|
||||
free(ifo->environ);
|
||||
}
|
||||
if (ifo->config) {
|
||||
i = 0;
|
||||
while (ifo->config[i])
|
||||
free(ifo->config[i++]);
|
||||
free(ifo->config);
|
||||
}
|
||||
rt_headclear0(ctx, &ifo->routes, AF_UNSPEC);
|
||||
if (ifo->script != default_script)
|
||||
free(ifo->script);
|
||||
free(ifo->arping);
|
||||
free(ifo->blacklist);
|
||||
free(ifo->fallback);
|
||||
if (ifo == NULL)
|
||||
return;
|
||||
|
||||
for (opt = ifo->dhcp_override;
|
||||
ifo->dhcp_override_len > 0;
|
||||
opt++, ifo->dhcp_override_len--)
|
||||
free_dhcp_opt_embenc(opt);
|
||||
free(ifo->dhcp_override);
|
||||
for (opt = ifo->nd_override;
|
||||
ifo->nd_override_len > 0;
|
||||
opt++, ifo->nd_override_len--)
|
||||
free_dhcp_opt_embenc(opt);
|
||||
free(ifo->nd_override);
|
||||
for (opt = ifo->dhcp6_override;
|
||||
ifo->dhcp6_override_len > 0;
|
||||
opt++, ifo->dhcp6_override_len--)
|
||||
free_dhcp_opt_embenc(opt);
|
||||
free(ifo->dhcp6_override);
|
||||
for (vo = ifo->vivco;
|
||||
ifo->vivco_len > 0;
|
||||
vo++, ifo->vivco_len--)
|
||||
free(vo->data);
|
||||
free(ifo->vivco);
|
||||
for (opt = ifo->vivso_override;
|
||||
ifo->vivso_override_len > 0;
|
||||
opt++, ifo->vivso_override_len--)
|
||||
free_dhcp_opt_embenc(opt);
|
||||
free(ifo->vivso_override);
|
||||
if (ifo->environ) {
|
||||
i = 0;
|
||||
while (ifo->environ[i])
|
||||
free(ifo->environ[i++]);
|
||||
free(ifo->environ);
|
||||
}
|
||||
if (ifo->config) {
|
||||
i = 0;
|
||||
while (ifo->config[i])
|
||||
free(ifo->config[i++]);
|
||||
free(ifo->config);
|
||||
}
|
||||
|
||||
#ifdef RT_FREE_ROUTE_TABLE
|
||||
/* Stupidly, we don't know the interface when creating the options.
|
||||
* As such, make sure each route has one so they can goto the
|
||||
* free list. */
|
||||
ifp = ctx->ifaces != NULL ? TAILQ_FIRST(ctx->ifaces) : NULL;
|
||||
if (ifp != NULL) {
|
||||
RB_TREE_FOREACH(rt, &ifo->routes) {
|
||||
if (rt->rt_ifp == NULL)
|
||||
rt->rt_ifp = ifp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
rt_headclear0(ctx, &ifo->routes, AF_UNSPEC);
|
||||
|
||||
if (ifo->script != default_script)
|
||||
free(ifo->script);
|
||||
free(ifo->arping);
|
||||
free(ifo->blacklist);
|
||||
free(ifo->fallback);
|
||||
|
||||
for (opt = ifo->dhcp_override;
|
||||
ifo->dhcp_override_len > 0;
|
||||
opt++, ifo->dhcp_override_len--)
|
||||
free_dhcp_opt_embenc(opt);
|
||||
free(ifo->dhcp_override);
|
||||
for (opt = ifo->nd_override;
|
||||
ifo->nd_override_len > 0;
|
||||
opt++, ifo->nd_override_len--)
|
||||
free_dhcp_opt_embenc(opt);
|
||||
free(ifo->nd_override);
|
||||
for (opt = ifo->dhcp6_override;
|
||||
ifo->dhcp6_override_len > 0;
|
||||
opt++, ifo->dhcp6_override_len--)
|
||||
free_dhcp_opt_embenc(opt);
|
||||
free(ifo->dhcp6_override);
|
||||
for (vo = ifo->vivco;
|
||||
ifo->vivco_len > 0;
|
||||
vo++, ifo->vivco_len--)
|
||||
free(vo->data);
|
||||
free(ifo->vivco);
|
||||
for (opt = ifo->vivso_override;
|
||||
ifo->vivso_override_len > 0;
|
||||
opt++, ifo->vivso_override_len--)
|
||||
free_dhcp_opt_embenc(opt);
|
||||
free(ifo->vivso_override);
|
||||
|
||||
#if defined(INET6) && !defined(SMALL)
|
||||
for (; ifo->ia_len > 0; ifo->ia_len--)
|
||||
free(ifo->ia[ifo->ia_len - 1].sla);
|
||||
for (; ifo->ia_len > 0; ifo->ia_len--)
|
||||
free(ifo->ia[ifo->ia_len - 1].sla);
|
||||
#endif
|
||||
free(ifo->ia);
|
||||
free(ifo->ia);
|
||||
|
||||
#ifdef AUTH
|
||||
while ((token = TAILQ_FIRST(&ifo->auth.tokens))) {
|
||||
TAILQ_REMOVE(&ifo->auth.tokens, token, next);
|
||||
if (token->realm_len)
|
||||
free(token->realm);
|
||||
free(token->key);
|
||||
free(token);
|
||||
}
|
||||
#endif
|
||||
free(ifo);
|
||||
while ((token = TAILQ_FIRST(&ifo->auth.tokens))) {
|
||||
TAILQ_REMOVE(&ifo->auth.tokens, token, next);
|
||||
if (token->realm_len)
|
||||
free(token->realm);
|
||||
free(token->key);
|
||||
free(token);
|
||||
}
|
||||
#endif
|
||||
free(ifo);
|
||||
}
|
||||
|
|
|
@ -91,9 +91,6 @@
|
|||
((addr & IN_CLASSB_NET) == 0xc0a80000))
|
||||
#endif
|
||||
|
||||
#define RAW_EOF 1 << 0
|
||||
#define RAW_PARTIALCSUM 2 << 0
|
||||
|
||||
#ifndef CLLADDR
|
||||
#ifdef AF_LINK
|
||||
# define CLLADDR(sdl) (const void *)((sdl)->sdl_data + (sdl)->sdl_nlen)
|
||||
|
|
|
@ -659,8 +659,13 @@ ipv4_addaddr(struct interface *ifp, const struct in_addr *addr,
|
|||
|
||||
ia->mask = *mask;
|
||||
ia->brd = *bcast;
|
||||
#ifdef IP_LIFETIME
|
||||
ia->vltime = vltime;
|
||||
ia->pltime = pltime;
|
||||
#else
|
||||
UNUSED(vltime);
|
||||
UNUSED(pltime);
|
||||
#endif
|
||||
snprintf(ia->saddr, sizeof(ia->saddr), "%s/%d",
|
||||
inet_ntoa(*addr), inet_ntocidr(*mask));
|
||||
|
||||
|
@ -746,16 +751,36 @@ ipv4_applyaddr(void *arg)
|
|||
return;
|
||||
}
|
||||
|
||||
#if __linux__
|
||||
/* If the netmask or broadcast is different, re-add the addresss */
|
||||
ia = ipv4_iffindaddr(ifp, &lease->addr, NULL);
|
||||
/* If the netmask or broadcast is different, re-add the addresss.
|
||||
* If IP addresses do not have lifetimes, there is a very real chance
|
||||
* that re-adding them will scrub the subnet route temporarily
|
||||
* which is a bad thing, so avoid it. */
|
||||
if (ia != NULL &&
|
||||
(ia->mask.s_addr != lease->mask.s_addr ||
|
||||
ia->brd.s_addr != lease->brd.s_addr))
|
||||
ipv4_deladdr(ia, 0);
|
||||
ia->mask.s_addr == lease->mask.s_addr &&
|
||||
ia->brd.s_addr == lease->brd.s_addr)
|
||||
{
|
||||
#ifndef IP_LIFETIME
|
||||
logdebugx("%s: IP address %s already exists",
|
||||
ifp->name, ia->saddr);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef __linux__
|
||||
/* Linux does not change netmask/broadcast address
|
||||
* for re-added addresses, so we need to delete the old one
|
||||
* first. */
|
||||
if (ia != NULL)
|
||||
ipv4_deladdr(ia, 0);
|
||||
#endif
|
||||
#ifndef IP_LIFETIME
|
||||
if (ipv4_daddaddr(ifp, lease) == -1 && errno != EEXIST)
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
#ifdef IP_LIFETIME
|
||||
if (ipv4_daddaddr(ifp, lease) == -1 && errno != EEXIST)
|
||||
return;
|
||||
#endif
|
||||
|
||||
ia = ipv4_iffindaddr(ifp, &lease->addr, NULL);
|
||||
if (ia == NULL) {
|
||||
|
|
|
@ -75,6 +75,10 @@
|
|||
#define IN_ARE_ADDR_EQUAL(a, b) ((a)->s_addr == (b)->s_addr)
|
||||
#define IN_IS_ADDR_UNSPECIFIED(a) ((a)->s_addr == INADDR_ANY)
|
||||
|
||||
#ifdef __linux__
|
||||
#define IP_LIFETIME
|
||||
#endif
|
||||
|
||||
struct ipv4_addr {
|
||||
TAILQ_ENTRY(ipv4_addr) next;
|
||||
struct in_addr addr;
|
||||
|
@ -83,8 +87,10 @@ struct ipv4_addr {
|
|||
struct interface *iface;
|
||||
int addr_flags;
|
||||
unsigned int flags;
|
||||
#ifdef IP_LIFETIME
|
||||
uint32_t vltime;
|
||||
uint32_t pltime;
|
||||
#endif
|
||||
char saddr[INET_ADDRSTRLEN + 3];
|
||||
#ifdef ALIAS_ADDR
|
||||
char alias[IF_NAMESIZE];
|
||||
|
|
|
@ -616,8 +616,10 @@ ipv6_deleteaddr(struct ipv6_addr *ia)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef ND6_ADVERTISE
|
||||
/* Advertise the address if it exists on another interface. */
|
||||
ipv6nd_advertise(ia);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -625,11 +627,22 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
|
|||
{
|
||||
struct interface *ifp;
|
||||
uint32_t pltime, vltime;
|
||||
bool vltime_was_zero;
|
||||
__printflike(1, 2) void (*logfunc)(const char *, ...);
|
||||
#ifdef ND6_ADVERTISE
|
||||
bool vltime_was_zero;
|
||||
#endif
|
||||
#ifdef __sun
|
||||
struct ipv6_state *state;
|
||||
struct ipv6_addr *ia2;
|
||||
|
||||
/* If we re-add then address on Solaris then the prefix
|
||||
* route will be scrubbed and re-added. Something might
|
||||
* be using it, so let's avoid it. */
|
||||
if (ia->flags & IPV6_AF_DADCOMPLETED) {
|
||||
logdebugx("%s: IP address %s already exists",
|
||||
ia->iface->name, ia->saddr);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Remember the interface of the address. */
|
||||
|
@ -694,7 +707,9 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
|
|||
" seconds",
|
||||
ifp->name, ia->prefix_pltime, ia->prefix_vltime);
|
||||
|
||||
#ifdef ND6_ADVERTISE
|
||||
vltime_was_zero = ia->prefix_vltime == 0;
|
||||
#endif
|
||||
if (if_address6(RTM_NEWADDR, ia) == -1) {
|
||||
logerr(__func__);
|
||||
/* Restore real pltime and vltime */
|
||||
|
@ -758,9 +773,11 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef ND6_ADVERTISE
|
||||
/* Re-advertise the preferred address to be safe. */
|
||||
if (!vltime_was_zero)
|
||||
ipv6nd_advertise(ia);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1081,9 +1098,11 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
|
|||
case RTM_DELADDR:
|
||||
if (ia != NULL) {
|
||||
TAILQ_REMOVE(&state->addrs, ia, next);
|
||||
#ifdef ND6_ADVERTISE
|
||||
/* Advertise the address if it exists on
|
||||
* another interface. */
|
||||
ipv6nd_advertise(ia);
|
||||
#endif
|
||||
/* We'll free it at the end of the function. */
|
||||
}
|
||||
break;
|
||||
|
@ -1177,6 +1196,8 @@ out:
|
|||
/* Done with the ia now, so free it. */
|
||||
if (cmd == RTM_DELADDR)
|
||||
ipv6_freeaddr(ia);
|
||||
else if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE))
|
||||
ia->flags |= IPV6_AF_DADCOMPLETED;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1455,8 +1476,10 @@ ipv6_newaddr(struct interface *ifp, const struct in6_addr *addr,
|
|||
goto err;
|
||||
|
||||
ia->iface = ifp;
|
||||
ia->flags = IPV6_AF_NEW | flags;
|
||||
ia->addr_flags = addr_flags;
|
||||
ia->flags = IPV6_AF_NEW | flags;
|
||||
if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE))
|
||||
ia->flags |= IPV6_AF_DADCOMPLETED;
|
||||
ia->prefix_len = prefix_len;
|
||||
ia->dhcp6_fd = -1;
|
||||
|
||||
|
|
|
@ -149,6 +149,16 @@
|
|||
# define IN6_IFF_DETACHED 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ND6 Advertising is only used for IP address sharing to prefer
|
||||
* the address on a specific interface.
|
||||
* This just fails to work on OpenBSD and causes erroneous duplicate
|
||||
* address messages on BSD's other then NetBSD.
|
||||
*/
|
||||
#if !defined(SMALL) && (defined(__NetBSD__) || defined(__linux__))
|
||||
# define ND6_ADVERTISE
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
TAILQ_HEAD(ipv6_addrhead, ipv6_addr);
|
||||
struct ipv6_addr {
|
||||
|
|
|
@ -389,6 +389,7 @@ ipv6nd_sendrsprobe(void *arg)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef ND6_ADVERTISE
|
||||
static void
|
||||
ipv6nd_sendadvertisement(void *arg)
|
||||
{
|
||||
|
@ -433,13 +434,7 @@ ipv6nd_sendadvertisement(void *arg)
|
|||
s = ctx->nd_fd;
|
||||
#endif
|
||||
if (sendmsg(s, &msg, 0) == -1)
|
||||
#ifdef __OpenBSD__
|
||||
/* This isn't too critical as they don't support IPv6 address sharing */
|
||||
#warning Cannot send NA messages on OpenBSD
|
||||
logdebug(__func__);
|
||||
#else
|
||||
logerr(__func__);
|
||||
#endif
|
||||
|
||||
if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) {
|
||||
eloop_timeout_add_sec(ctx->eloop,
|
||||
|
@ -526,6 +521,9 @@ ipv6nd_advertise(struct ipv6_addr *ia)
|
|||
eloop_timeout_delete(ctx->eloop, ipv6nd_sendadvertisement, iaf);
|
||||
ipv6nd_sendadvertisement(iaf);
|
||||
}
|
||||
#elif !defined(SMALL)
|
||||
#warning kernel does not support userland sending ND6 advertisements
|
||||
#endif /* ND6_ADVERTISE */
|
||||
|
||||
static void
|
||||
ipv6nd_expire(void *arg)
|
||||
|
@ -908,7 +906,9 @@ try_script:
|
|||
return;
|
||||
}
|
||||
}
|
||||
#ifdef ND6_ADVERTISE
|
||||
ipv6nd_advertise(ia);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -392,8 +392,10 @@ rt_free(struct rt *rt)
|
|||
struct dhcpcd_ctx *ctx;
|
||||
|
||||
assert(rt != NULL);
|
||||
assert(rt->rt_ifp != NULL);
|
||||
assert(rt->rt_ifp->ctx != NULL);
|
||||
if (rt->rt_ifp == NULL) {
|
||||
free(rt);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = rt->rt_ifp->ctx;
|
||||
rb_tree_insert_node(&ctx->froutes, rt);
|
||||
|
|
|
@ -213,10 +213,11 @@ make_env(const struct interface *ifp, const char *reason)
|
|||
if (tmpfd == -1)
|
||||
goto eexit;
|
||||
unlink(tmpfile);
|
||||
fp = fopen(tmpfile, "w+");
|
||||
close(tmpfd);
|
||||
if (fp == NULL)
|
||||
fp = fdopen(tmpfd, "w+");
|
||||
if (fp == NULL) {
|
||||
close(tmpfd);
|
||||
goto eexit;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef INET
|
||||
|
|
Loading…
Reference in New Issue