Import dhcpcd-7.2.0 with the following changes:

*  BSD: PF_LINK sockets now closed when no longer needed
  *  BSD: Fix detecting interface for scoped routes
  *  script: Allow "" to mean /dev/null
  *  script: Add static routers and routes to env
  *  DHCP: outbound interface is no longer dictated with IP_PKTINFO
  *  DHCP: BPF sockets now closed when no longer needed
  *  DHCPv6: Allow nooption dhcp6_unicast to work
  *  DHCPv6: Don't spam syslog if we always get the same error
  *  route: Log pid which deleted routes of interest

This release fixes PR bin/53705.
This commit is contained in:
roy 2019-04-17 23:33:08 +00:00
parent a5e54c894f
commit dbd4cee32e
24 changed files with 667 additions and 565 deletions

View File

@ -175,17 +175,18 @@ arp_packet(struct interface *ifp, uint8_t *data, size_t len)
} }
} }
void static void
arp_close(struct interface *ifp) arp_close(struct interface *ifp)
{ {
struct iarp_state *state; struct iarp_state *state;
if ((state = ARP_STATE(ifp)) != NULL && state->bpf_fd != -1) { if ((state = ARP_STATE(ifp)) == NULL || state->bpf_fd == -1)
eloop_event_delete(ifp->ctx->eloop, state->bpf_fd); return;
bpf_close(ifp, state->bpf_fd);
state->bpf_fd = -1; eloop_event_delete(ifp->ctx->eloop, state->bpf_fd);
state->bpf_flags |= BPF_EOF; bpf_close(ifp, state->bpf_fd);
} state->bpf_fd = -1;
state->bpf_flags |= BPF_EOF;
} }
static void static void

View File

@ -90,7 +90,6 @@ struct iarp_state {
int arp_open(struct interface *); int arp_open(struct interface *);
ssize_t arp_request(const struct interface *, in_addr_t, in_addr_t); ssize_t arp_request(const struct interface *, in_addr_t, in_addr_t);
void arp_probe(struct arp_state *); void arp_probe(struct arp_state *);
void arp_close(struct interface *);
void arp_report_conflicted(const struct arp_state *, const struct arp_msg *); void arp_report_conflicted(const struct arp_state *, const struct arp_msg *);
struct arp_state *arp_new(struct interface *, const struct in_addr *); struct arp_state *arp_new(struct interface *, const struct in_addr *);
struct arp_state *arp_find(struct interface *, const struct in_addr *); struct arp_state *arp_find(struct interface *, const struct in_addr *);

View File

@ -200,51 +200,3 @@ read_hwaddr_aton(uint8_t **data, const char *path)
fclose(fp); fclose(fp);
return len; return len;
} }
ssize_t
recvmsg_realloc(int fd, struct msghdr *msg, int flags)
{
struct iovec *iov;
ssize_t slen;
size_t len;
void *n;
assert(msg != NULL);
assert(msg->msg_iov != NULL && msg->msg_iovlen > 0);
assert((flags & (MSG_PEEK | MSG_TRUNC)) == 0);
/* Assume we are reallocing the last iovec. */
iov = &msg->msg_iov[msg->msg_iovlen - 1];
for (;;) {
/* Passing MSG_TRUNC should return the actual size needed. */
slen = recvmsg(fd, msg, flags | MSG_PEEK | MSG_TRUNC);
if (slen == -1)
return -1;
if (!(msg->msg_flags & MSG_TRUNC))
break;
len = (size_t)slen;
/* Some kernels return the size of the receive buffer
* on truncation, not the actual size needed.
* So grow the buffer and try again. */
if (iov->iov_len == len)
len++;
else if (iov->iov_len > len)
break;
len = roundup(len, IOVEC_BUFSIZ);
if ((n = realloc(iov->iov_base, len)) == NULL)
return -1;
iov->iov_base = n;
iov->iov_len = len;
}
slen = recvmsg(fd, msg, flags);
if (slen != -1 && msg->msg_flags & MSG_TRUNC) {
/* This should not be possible ... */
errno = ENOBUFS;
return -1;
}
return slen;
}

View File

@ -181,6 +181,4 @@ ssize_t addvard(char ***, const char *, const char *, size_t);
const char *hwaddr_ntoa(const void *, size_t, char *, size_t); const char *hwaddr_ntoa(const void *, size_t, char *, size_t);
size_t hwaddr_aton(uint8_t *, const char *); size_t hwaddr_aton(uint8_t *, const char *);
size_t read_hwaddr_aton(uint8_t **, const char *); size_t read_hwaddr_aton(uint8_t **, const char *);
ssize_t recvmsg_realloc(int, struct msghdr *, int);
#endif #endif

View File

@ -28,7 +28,7 @@
#define CONFIG_H #define CONFIG_H
#define PACKAGE "dhcpcd" #define PACKAGE "dhcpcd"
#define VERSION "7.1.1" #define VERSION "7.2.0"
#ifndef CONFIG #ifndef CONFIG
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf" # define CONFIG SYSCONFDIR "/" PACKAGE ".conf"

View File

@ -86,9 +86,9 @@
#define IPDEFTTL 64 /* RFC1340 */ #define IPDEFTTL 64 /* RFC1340 */
#endif #endif
/* NetBSD-7 has an incomplete IP_PKTINFO implementation. */ /* Support older systems with different defines */
#if defined(__NetBSD_Version__) && __NetBSD_Version__ < 800000000 #if !defined(IP_RECVPKTINFO) && defined(IP_PKTINFO)
#undef IP_PKTINFO #define IP_RECVPKTINFO IP_PKTINFO
#endif #endif
/* Assert the correct structure size for on wire */ /* Assert the correct structure size for on wire */
@ -129,6 +129,9 @@ static void dhcp_arp_conflicted(struct arp_state *, const struct arp_msg *);
#endif #endif
static void dhcp_handledhcp(struct interface *, struct bootp *, size_t, static void dhcp_handledhcp(struct interface *, struct bootp *, size_t,
const struct in_addr *); const struct in_addr *);
#ifdef IP_PKTINFO
static void dhcp_handleifudp(void *);
#endif
static int dhcp_initstate(struct interface *); static int dhcp_initstate(struct interface *);
void void
@ -447,7 +450,7 @@ decode_rfc3442_rt(struct rt_head *routes, struct interface *ifp,
memcpy(&gateway.s_addr, p, 4); memcpy(&gateway.s_addr, p, 4);
p += 4; p += 4;
/* A host route is normally set by having the /* An on-link host route is normally set by having the
* gateway match the destination or assigned address */ * gateway match the destination or assigned address */
if (gateway.s_addr == dest.s_addr || if (gateway.s_addr == dest.s_addr ||
(gateway.s_addr == bootp->yiaddr || (gateway.s_addr == bootp->yiaddr ||
@ -455,17 +458,14 @@ decode_rfc3442_rt(struct rt_head *routes, struct interface *ifp,
{ {
gateway.s_addr = INADDR_ANY; gateway.s_addr = INADDR_ANY;
netmask.s_addr = INADDR_BROADCAST; netmask.s_addr = INADDR_BROADCAST;
rt->rt_flags = RTF_HOST;
} }
if (netmask.s_addr == INADDR_BROADCAST)
rt->rt_flags = RTF_HOST;
sa_in_init(&rt->rt_dest, &dest); sa_in_init(&rt->rt_dest, &dest);
sa_in_init(&rt->rt_netmask, &netmask); sa_in_init(&rt->rt_netmask, &netmask);
sa_in_init(&rt->rt_gateway, &gateway); sa_in_init(&rt->rt_gateway, &gateway);
/* If CIDR is 32 then it's a host route. */
if (cidr == 32)
rt->rt_flags = RTF_HOST;
TAILQ_INSERT_TAIL(routes, rt, rt_next); TAILQ_INSERT_TAIL(routes, rt, rt_next);
n++; n++;
} }
@ -638,7 +638,7 @@ get_option_routes(struct rt_head *routes, struct interface *ifp,
if ((rt = rt_new(ifp)) == NULL) if ((rt = rt_new(ifp)) == NULL)
return -1; return -1;
/* A host route is normally set by having the /* A on-link host route is normally set by having the
* gateway match the destination or assigned address */ * gateway match the destination or assigned address */
if (gateway.s_addr == dest.s_addr || if (gateway.s_addr == dest.s_addr ||
(gateway.s_addr == bootp->yiaddr || (gateway.s_addr == bootp->yiaddr ||
@ -646,12 +646,15 @@ get_option_routes(struct rt_head *routes, struct interface *ifp,
{ {
gateway.s_addr = INADDR_ANY; gateway.s_addr = INADDR_ANY;
netmask.s_addr = INADDR_BROADCAST; netmask.s_addr = INADDR_BROADCAST;
rt->rt_flags = RTF_HOST;
} else } else
netmask.s_addr = route_netmask(dest.s_addr); netmask.s_addr = route_netmask(dest.s_addr);
if (netmask.s_addr == INADDR_BROADCAST)
rt->rt_flags = RTF_HOST;
sa_in_init(&rt->rt_dest, &dest); sa_in_init(&rt->rt_dest, &dest);
sa_in_init(&rt->rt_netmask, &netmask); sa_in_init(&rt->rt_netmask, &netmask);
sa_in_init(&rt->rt_gateway, &gateway); sa_in_init(&rt->rt_gateway, &gateway);
TAILQ_INSERT_TAIL(routes, rt, rt_next); TAILQ_INSERT_TAIL(routes, rt, rt_next);
n++; n++;
} }
@ -1587,6 +1590,11 @@ dhcp_close(struct interface *ifp)
state->bpf_fd = -1; state->bpf_fd = -1;
state->bpf_flags |= BPF_EOF; state->bpf_flags |= BPF_EOF;
} }
if (state->udp_fd != -1) {
eloop_event_delete(ifp->ctx->eloop, state->udp_fd);
close(state->udp_fd);
state->udp_fd = -1;
}
state->interval = 0; state->interval = 0;
} }
@ -1604,11 +1612,15 @@ dhcp_openudp(struct interface *ifp)
n = 1; n = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1)
goto eexit; goto eexit;
#ifdef IP_RECVPKTINFO
if (setsockopt(s, IPPROTO_IP, IP_RECVPKTINFO, &n, sizeof(n)) == -1)
goto eexit;
#endif
memset(&sin, 0, sizeof(sin)); memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET; sin.sin_family = AF_INET;
sin.sin_port = htons(BOOTPC); sin.sin_port = htons(BOOTPC);
if (ifp) { if (ifp) {
struct dhcp_state *state = D_STATE(ifp); const struct dhcp_state *state = D_CSTATE(ifp);
if (state->addr) if (state->addr)
sin.sin_addr.s_addr = state->addr->addr.s_addr; sin.sin_addr.s_addr = state->addr->addr.s_addr;
@ -1699,12 +1711,8 @@ dhcp_sendudp(struct interface *ifp, struct in_addr *to, void *data, size_t len)
struct msghdr msg; struct msghdr msg;
struct sockaddr_in sin; struct sockaddr_in sin;
struct iovec iov[1]; struct iovec iov[1];
struct dhcp_state *state = D_STATE(ifp);
ssize_t r; ssize_t r;
#ifdef IP_PKTINFO
uint8_t cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
struct cmsghdr *cm;
struct in_pktinfo ipi;
#endif
iov[0].iov_base = data; iov[0].iov_base = data;
iov[0].iov_len = len; iov[0].iov_len = len;
@ -1723,29 +1731,15 @@ dhcp_sendudp(struct interface *ifp, struct in_addr *to, void *data, size_t len)
msg.msg_iov = iov; msg.msg_iov = iov;
msg.msg_iovlen = 1; msg.msg_iovlen = 1;
#ifdef IP_PKTINFO s = state->udp_fd;
/* Set the outbound interface */ if (s == -1) {
msg.msg_control = cmsg; s = dhcp_openudp(ifp);
msg.msg_controllen = sizeof(cmsg); if (s == -1)
return -1;
memset(&ipi, 0, sizeof(ipi));
ipi.ipi_ifindex = ifp->index;
cm = CMSG_FIRSTHDR(&msg);
if (cm == NULL) {
errno = ESRCH;
return -1;
} }
cm->cmsg_level = IPPROTO_IP;
cm->cmsg_type = IP_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(ipi));
memcpy(CMSG_DATA(cm), &ipi, sizeof(ipi));
#endif
s = dhcp_openudp(ifp);
if (s == -1)
return -1;
r = sendmsg(s, &msg, 0); r = sendmsg(s, &msg, 0);
close(s); if (state->udp_fd == -1)
close(s);
return r; return r;
} }
@ -1803,7 +1797,7 @@ send_message(struct interface *ifp, uint8_t type,
else else
to.s_addr = INADDR_ANY; to.s_addr = INADDR_ANY;
/* If unicasting, try and void sending by BPF so we don't /* If unicasting, try and avoid sending by BPF so we don't
* use a L2 broadcast. */ * use a L2 broadcast. */
if (to.s_addr != INADDR_ANY && to.s_addr != INADDR_BROADCAST) { if (to.s_addr != INADDR_ANY && to.s_addr != INADDR_BROADCAST) {
if (dhcp_sendudp(ifp, &to, bootp, len) != -1) if (dhcp_sendudp(ifp, &to, bootp, len) != -1)
@ -2068,11 +2062,6 @@ dhcp_arp_probed(struct arp_state *astate)
return; return;
} }
arp_free(astate); arp_free(astate);
#ifdef KERNEL_RFC5227
/* As arping is finished, close the ARP socket.
* The kernel will handle ACD from here. */
arp_close(ifp);
#endif
dhcpcd_startinterface(ifp); dhcpcd_startinterface(ifp);
return; return;
} }
@ -2150,11 +2139,6 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
return; return;
} }
arp_free(astate); arp_free(astate);
#ifdef KERNEL_RFC5227
/* As arping is finished, close the ARP socket.
* The kernel will handle ACD from here. */
arp_close(ifp);
#endif
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
dhcpcd_startinterface(ifp); dhcpcd_startinterface(ifp);
return; return;
@ -2209,11 +2193,22 @@ dhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
return; return;
} }
} }
static void
dhcp_arp_announced(struct arp_state *state)
{
// TODO: DHCP addresses handle ACD?
//#ifdef KERNEL_RFC5227
arp_free(state);
//#endif
}
#endif #endif
void void
dhcp_bind(struct interface *ifp) dhcp_bind(struct interface *ifp)
{ {
struct dhcpcd_ctx *ctx = ifp->ctx;
struct dhcp_state *state = D_STATE(ifp); struct dhcp_state *state = D_STATE(ifp);
struct if_options *ifo = ifp->options; struct if_options *ifo = ifp->options;
struct dhcp_lease *lease = &state->lease; struct dhcp_lease *lease = &state->lease;
@ -2289,10 +2284,10 @@ dhcp_bind(struct interface *ifp)
lease->leasetime); lease->leasetime);
} }
} }
if (ifp->ctx->options & DHCPCD_TEST) { if (ctx->options & DHCPCD_TEST) {
state->reason = "TEST"; state->reason = "TEST";
script_runreason(ifp, state->reason); script_runreason(ifp, state->reason);
eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS); eloop_exit(ctx->eloop, EXIT_SUCCESS);
return; return;
} }
if (state->reason == NULL) { if (state->reason == NULL) {
@ -2311,26 +2306,42 @@ dhcp_bind(struct interface *ifp)
if (lease->leasetime == ~0U) if (lease->leasetime == ~0U)
lease->renewaltime = lease->rebindtime = lease->leasetime; lease->renewaltime = lease->rebindtime = lease->leasetime;
else { else {
eloop_timeout_add_sec(ifp->ctx->eloop, eloop_timeout_add_sec(ctx->eloop,
(time_t)lease->renewaltime, dhcp_startrenew, ifp); (time_t)lease->renewaltime, dhcp_startrenew, ifp);
eloop_timeout_add_sec(ifp->ctx->eloop, eloop_timeout_add_sec(ctx->eloop,
(time_t)lease->rebindtime, dhcp_rebind, ifp); (time_t)lease->rebindtime, dhcp_rebind, ifp);
eloop_timeout_add_sec(ifp->ctx->eloop, eloop_timeout_add_sec(ctx->eloop,
(time_t)lease->leasetime, dhcp_expire, ifp); (time_t)lease->leasetime, dhcp_expire, ifp);
logdebugx("%s: renew in %"PRIu32" seconds, rebind in %"PRIu32 logdebugx("%s: renew in %"PRIu32" seconds, rebind in %"PRIu32
" seconds", " seconds",
ifp->name, lease->renewaltime, lease->rebindtime); ifp->name, lease->renewaltime, lease->rebindtime);
} }
state->state = DHS_BOUND; state->state = DHS_BOUND;
/* Re-apply the filter because we need to accept any XID anymore. */
if (bpf_bootp(ifp, state->bpf_fd) == -1)
logerr(__func__); /* try to continue */
if (!state->lease.frominfo && if (!state->lease.frominfo &&
!(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))) !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
if (write_lease(ifp, state->new, state->new_len) == -1) if (write_lease(ifp, state->new, state->new_len) == -1)
logerr(__func__); logerr(__func__);
ipv4_applyaddr(ifp); ipv4_applyaddr(ifp);
#ifdef IP_PKTINFO
/* Close the BPF filter as we can now receive the DHCP renew messages
* on a UDP socket. */
if (state->udp_fd == -1 ||
(state->old != NULL && state->old->yiaddr != state->new->yiaddr))
{
dhcp_close(ifp);
/* If not in master mode, open an address specific socket. */
if (ctx->udp_fd == -1) {
state->udp_fd = dhcp_openudp(ifp);
if (state->udp_fd == -1)
logerr(__func__);
else
eloop_event_add(ctx->eloop,
state->udp_fd, dhcp_handleifudp, ifp);
}
}
#endif
} }
static void static void
@ -2384,6 +2395,20 @@ dhcp_message_new(struct bootp **bootp,
} }
#ifdef ARP #ifdef ARP
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->announced_cb = dhcp_arp_announced;
return astate;
}
static int static int
dhcp_arp_address(struct interface *ifp) dhcp_arp_address(struct interface *ifp)
{ {
@ -2400,10 +2425,9 @@ dhcp_arp_address(struct interface *ifp)
/* If the interface already has the address configured /* If the interface already has the address configured
* then we can't ARP for duplicate detection. */ * then we can't ARP for duplicate detection. */
ia = ipv4_iffindaddr(ifp, &addr, NULL); ia = ipv4_iffindaddr(ifp, &addr, NULL);
if ((astate = arp_new(ifp, &addr)) == NULL) astate = dhcp_arp_new(ifp, &addr);
if (astate == NULL)
return -1; return -1;
astate->probed_cb = dhcp_arp_probed;
astate->conflicted_cb = dhcp_arp_conflicted;
#ifdef IN_IFF_TENTATIVE #ifdef IN_IFF_TENTATIVE
if (ia == NULL || ia->addr_flags & IN_IFF_NOTUSEABLE) { if (ia == NULL || ia->addr_flags & IN_IFF_NOTUSEABLE) {
@ -2440,7 +2464,8 @@ static void
dhcp_arp_bind(struct interface *ifp) dhcp_arp_bind(struct interface *ifp)
{ {
if (dhcp_arp_address(ifp) == 1) if (ifp->ctx->options & DHCPCD_TEST ||
dhcp_arp_address(ifp) == 1)
dhcp_bind(ifp); dhcp_bind(ifp);
} }
#endif #endif
@ -2879,14 +2904,11 @@ dhcp_handledhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len,
#define LOGDHCP(l, m) \ #define LOGDHCP(l, m) \
log_dhcp((l), (m), ifp, bootp, bootp_len, from, 1) log_dhcp((l), (m), ifp, bootp, bootp_len, from, 1)
/* Handled in our BPF filter. */
#if 0
if (bootp->op != BOOTREPLY) { if (bootp->op != BOOTREPLY) {
logdebugx("%s: op (%d) is not BOOTREPLY", logdebugx("%s: op (%d) is not BOOTREPLY",
ifp->name, bootp->op); ifp->name, bootp->op);
return; return;
} }
#endif
if (state->xid != ntohl(bootp->xid)) { if (state->xid != ntohl(bootp->xid)) {
if (state->state != DHS_BOUND && state->state != DHS_NONE) if (state->state != DHS_BOUND && state->state != DHS_NONE)
@ -3190,6 +3212,7 @@ dhcp_handledhcp(struct interface *ifp, struct bootp *bootp, size_t bootp_len,
state->reason = "TEST"; state->reason = "TEST";
script_runreason(ifp, state->reason); script_runreason(ifp, state->reason);
eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS); eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
state->bpf_flags |= BPF_EOF;
return; return;
} }
eloop_timeout_delete(ifp->ctx->eloop, send_discover, ifp); eloop_timeout_delete(ifp->ctx->eloop, send_discover, ifp);
@ -3336,6 +3359,30 @@ valid_udp_packet(void *data, size_t data_len, struct in_addr *from,
return 0; return 0;
} }
static void
dhcp_handlebootp(struct interface *ifp, struct bootp *bootp, size_t len,
struct in_addr *from)
{
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);
while (v < 4) {
bootp->vend[v++] = '\0';
len++;
}
dhcp_handledhcp(ifp, bootp, len, from);
}
static void static void
dhcp_handlepacket(struct interface *ifp, uint8_t *data, size_t len) dhcp_handlepacket(struct interface *ifp, uint8_t *data, size_t len)
{ {
@ -3370,22 +3417,7 @@ dhcp_handlepacket(struct interface *ifp, uint8_t *data, size_t len)
* dhcpcd can work fine without the vendor area being sent. * dhcpcd can work fine without the vendor area being sent.
*/ */
bootp = get_udp_data(data, &udp_len); bootp = get_udp_data(data, &udp_len);
/* udp_len must be correct because the values are checked in dhcp_handlebootp(ifp, bootp, udp_len, &from);
* valid_udp_packet(). */
if (udp_len < offsetof(struct bootp, vend)) {
logerrx("%s: truncated packet (%zu) from %s",
ifp->name, udp_len, inet_ntoa(from));
return;
}
/* To make our IS_DHCP macro easy, ensure the vendor
* area has at least 4 octets. */
len = udp_len - offsetof(struct bootp, vend);
while (len < 4) {
bootp->vend[len++] = '\0';
udp_len++;
}
dhcp_handledhcp(ifp, bootp, udp_len, &from);
} }
static void static void
@ -3420,24 +3452,77 @@ dhcp_readpacket(void *arg)
state->bpf_flags &= ~BPF_READING; state->bpf_flags &= ~BPF_READING;
} }
static void
dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp)
{
struct sockaddr_in from;
unsigned char buf[10 * 1024]; /* Maximum MTU */
struct iovec iov = {
.iov_base = buf,
.iov_len = sizeof(buf),
};
#ifdef IP_PKTINFO
unsigned char ctl[CMSG_SPACE(sizeof(struct in_pktinfo))] = { 0 };
char sfrom[INET_ADDRSTRLEN];
#endif
struct msghdr msg = {
.msg_name = &from, .msg_namelen = sizeof(from),
.msg_iov = &iov, .msg_iovlen = 1,
#ifdef IP_PKTINFO
.msg_control = ctl, .msg_controllen = sizeof(ctl),
#endif
};
int s;
ssize_t bytes;
if (ifp != NULL) {
const struct dhcp_state *state = D_CSTATE(ifp);
s = state->udp_fd;
} else
s = ctx->udp_fd;
bytes = recvmsg(s, &msg, 0);
if (bytes == -1) {
logerr(__func__);
return;
}
#ifdef IP_PKTINFO
inet_ntop(AF_INET, &from.sin_addr, sfrom, sizeof(sfrom));
if (ifp == NULL) {
ifp = if_findifpfromcmsg(ctx, &msg, NULL);
if (ifp == NULL) {
logerr(__func__);
return;
}
}
dhcp_handlebootp(ifp, (struct bootp *)buf, (size_t)bytes,
&from.sin_addr);
#endif
}
static void static void
dhcp_handleudp(void *arg) dhcp_handleudp(void *arg)
{ {
struct dhcpcd_ctx *ctx; struct dhcpcd_ctx *ctx = arg;
uint8_t buffer[MTU_MAX];
ctx = arg; dhcp_readudp(ctx, NULL);
/* Just read what's in the UDP fd and discard it as we always read
* from the raw fd */
if (read(ctx->udp_fd, buffer, sizeof(buffer)) == -1) {
logerr(__func__);
eloop_event_delete(ctx->eloop, ctx->udp_fd);
close(ctx->udp_fd);
ctx->udp_fd = -1;
}
} }
#ifdef IP_PKTINFO
static void
dhcp_handleifudp(void *arg)
{
struct interface *ifp = arg;
dhcp_readudp(ifp->ctx, ifp);
}
#endif
static int static int
dhcp_openbpf(struct interface *ifp) dhcp_openbpf(struct interface *ifp)
{ {
@ -3547,6 +3632,7 @@ dhcp_initstate(struct interface *ifp)
state->state = DHS_NONE; state->state = DHS_NONE;
/* 0 is a valid fd, so init to -1 */ /* 0 is a valid fd, so init to -1 */
state->bpf_fd = -1; state->bpf_fd = -1;
state->udp_fd = -1;
#ifdef ARPING #ifdef ARPING
state->arping_index = -1; state->arping_index = -1;
#endif #endif
@ -3676,12 +3762,9 @@ dhcp_start1(void *arg)
if (ifo->arping_len && state->arping_index < ifo->arping_len) { if (ifo->arping_len && state->arping_index < ifo->arping_len) {
struct arp_state *astate; struct arp_state *astate;
astate = arp_new(ifp, NULL); astate = dhcp_arp_new(ifp, NULL);
if (astate) { if (astate)
astate->probed_cb = dhcp_arp_probed;
astate->conflicted_cb = dhcp_arp_conflicted;
dhcp_arp_probed(astate); dhcp_arp_probed(astate);
}
return; return;
} }
#endif #endif
@ -3691,13 +3774,11 @@ dhcp_start1(void *arg)
return; return;
} }
if (ifo->options & DHCPCD_DHCP && dhcp_openbpf(ifp) == -1)
return;
if (ifo->options & DHCPCD_INFORM) { if (ifo->options & DHCPCD_INFORM) {
dhcp_inform(ifp); dhcp_inform(ifp);
return; return;
} }
if (ifp->hwlen == 0 && ifo->clientid[0] == '\0') { if (ifp->hwlen == 0 && ifo->clientid[0] == '\0') {
logwarnx("%s: needs a clientid to configure", ifp->name); logwarnx("%s: needs a clientid to configure", ifp->name);
dhcp_drop(ifp, "FAIL"); dhcp_drop(ifp, "FAIL");

View File

@ -216,6 +216,7 @@ struct dhcp_state {
int bpf_fd; int bpf_fd;
unsigned int bpf_flags; unsigned int bpf_flags;
int udp_fd;
struct ipv4_addr *addr; struct ipv4_addr *addr;
uint8_t added; uint8_t added;

View File

@ -168,7 +168,7 @@ static const char * const dhcp6_statuses[] = {
"No Prefix Available" "No Prefix Available"
}; };
static void dhcp6_bind(struct interface *, const char *); static void dhcp6_bind(struct interface *, const char *, const char *);
static void dhcp6_failinform(void *); static void dhcp6_failinform(void *);
static int dhcp6_listen(struct dhcpcd_ctx *, struct ipv6_addr *); static int dhcp6_listen(struct dhcpcd_ctx *, struct ipv6_addr *);
static void dhcp6_recvaddr(void *); static void dhcp6_recvaddr(void *);
@ -797,8 +797,7 @@ dhcp6_makemessage(struct interface *ifp)
m = state->new; m = state->new;
ml = state->new_len; ml = state->new_len;
} }
unicast = NULL;
/* Depending on state, get the unicast address */
switch(state->state) { switch(state->state) {
case DH6S_INIT: /* FALLTHROUGH */ case DH6S_INIT: /* FALLTHROUGH */
case DH6S_DISCOVER: case DH6S_DISCOVER:
@ -806,7 +805,6 @@ dhcp6_makemessage(struct interface *ifp)
break; break;
case DH6S_REQUEST: case DH6S_REQUEST:
type = DHCP6_REQUEST; type = DHCP6_REQUEST;
unicast = dhcp6_findmoption(m, ml, D6_OPTION_UNICAST, &uni_len);
break; break;
case DH6S_CONFIRM: case DH6S_CONFIRM:
type = DHCP6_CONFIRM; type = DHCP6_CONFIRM;
@ -816,20 +814,33 @@ dhcp6_makemessage(struct interface *ifp)
break; break;
case DH6S_RENEW: case DH6S_RENEW:
type = DHCP6_RENEW; type = DHCP6_RENEW;
unicast = dhcp6_findmoption(m, ml, D6_OPTION_UNICAST, &uni_len);
break; break;
case DH6S_INFORM: case DH6S_INFORM:
type = DHCP6_INFORMATION_REQ; type = DHCP6_INFORMATION_REQ;
break; break;
case DH6S_RELEASE: case DH6S_RELEASE:
type = DHCP6_RELEASE; type = DHCP6_RELEASE;
unicast = dhcp6_findmoption(m, ml, D6_OPTION_UNICAST, &uni_len);
break; break;
default: default:
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
switch(state->state) {
case DH6S_REQUEST: /* FALLTHROUGH */
case DH6S_RENEW: /* FALLTHROUGH */
case DH6S_RELEASE:
if (has_option_mask(ifo->nomask6, D6_OPTION_UNICAST)) {
unicast = NULL;
break;
}
unicast = dhcp6_findmoption(m, ml, D6_OPTION_UNICAST, &uni_len);
break;
default:
unicast = NULL;
break;
}
/* In non master mode we listen and send from fixed addresses. /* In non master mode we listen and send from fixed addresses.
* We should try and match an address we have to unicast to, * We should try and match an address we have to unicast to,
* but for now this is the safest policy. */ * but for now this is the safest policy. */
@ -1157,9 +1168,12 @@ dhcp6_update_auth(struct interface *ifp, struct dhcp6_message *m, size_t len)
static int static int
dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *)) dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
{ {
struct dhcp6_state *state; struct dhcp6_state *state = D6_STATE(ifp);
struct dhcpcd_ctx *ctx; struct dhcpcd_ctx *ctx = ifp->ctx;
struct sockaddr_in6 dst; struct sockaddr_in6 dst = {
.sin6_family = AF_INET6,
.sin6_port = htons(DHCP6_SERVER_PORT),
};
struct timespec RTprev; struct timespec RTprev;
double rnd; double rnd;
time_t ms; time_t ms;
@ -1168,18 +1182,22 @@ dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *))
const struct in6_addr alldhcp = IN6ADDR_LINKLOCAL_ALLDHCP_INIT; const struct in6_addr alldhcp = IN6ADDR_LINKLOCAL_ALLDHCP_INIT;
struct ipv6_addr *lla; struct ipv6_addr *lla;
int s; int s;
struct iovec iov = {
.iov_base = state->send, .iov_len = state->send_len,
};
unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
struct msghdr msg = {
.msg_name = &dst, .msg_namelen = sizeof(dst),
.msg_iov = &iov, .msg_iovlen = 1,
};
if (!callback && ifp->carrier <= LINK_DOWN) if (!callback && ifp->carrier <= LINK_DOWN)
return 0; return 0;
memset(&dst, 0, sizeof(dst));
dst.sin6_family = AF_INET6;
dst.sin6_port = htons(DHCP6_SERVER_PORT);
#ifdef HAVE_SA_LEN #ifdef HAVE_SA_LEN
dst.sin6_len = sizeof(dst); dst.sin6_len = sizeof(dst);
#endif #endif
state = D6_STATE(ifp);
lla = ipv6_linklocal(ifp); lla = ipv6_linklocal(ifp);
/* We need to ensure we have sufficient scope to unicast the address */ /* We need to ensure we have sufficient scope to unicast the address */
/* XXX FIXME: We should check any added addresses we have like from /* XXX FIXME: We should check any added addresses we have like from
@ -1280,7 +1298,7 @@ logsend:
/* Wait the initial delay */ /* Wait the initial delay */
if (state->IMD != 0) { if (state->IMD != 0) {
state->IMD = 0; state->IMD = 0;
eloop_timeout_add_tv(ifp->ctx->eloop, eloop_timeout_add_tv(ctx->eloop,
&state->RT, callback, ifp); &state->RT, callback, ifp);
return 0; return 0;
} }
@ -1301,31 +1319,21 @@ logsend:
} }
#endif #endif
ctx = ifp->ctx;
ctx->sndhdr.msg_name = (void *)&dst;
ctx->sndhdr.msg_iov[0].iov_base = state->send;
ctx->sndhdr.msg_iov[0].iov_len = state->send_len;
/* Set the outbound interface */ /* Set the outbound interface */
if (IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &alldhcp)) { if (IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &alldhcp)) {
struct cmsghdr *cm; struct cmsghdr *cm;
struct in6_pktinfo pi; struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
dst.sin6_scope_id = ifp->index; dst.sin6_scope_id = ifp->index;
cm = CMSG_FIRSTHDR(&ctx->sndhdr); msg.msg_control = ctl;
msg.msg_controllen = sizeof(ctl);
cm = CMSG_FIRSTHDR(&msg);
if (cm == NULL) /* unlikely */ if (cm == NULL) /* unlikely */
return -1; return -1;
cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_PKTINFO; cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(pi)); cm->cmsg_len = CMSG_LEN(sizeof(pi));
memset(&pi, 0, sizeof(pi));
pi.ipi6_ifindex = ifp->index;
memcpy(CMSG_DATA(cm), &pi, sizeof(pi)); memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
} else {
/* Remove the control buffer as we're not dictating
* which interface to use for outgoing messages. */
ctx->sndhdr.msg_control = NULL;
ctx->sndhdr.msg_controllen = 0;
} }
if (ctx->dhcp6_fd != -1) if (ctx->dhcp6_fd != -1)
@ -1337,7 +1345,7 @@ logsend:
return -1; return -1;
} }
if (sendmsg(s, &ctx->sndhdr, 0) == -1) { if (sendmsg(s, &msg, 0) == -1) {
logerr("%s: %s: sendmsg", __func__, ifp->name); logerr("%s: %s: sendmsg", __func__, ifp->name);
/* Allow DHCPv6 to continue .... the errors /* Allow DHCPv6 to continue .... the errors
* would be rate limited by the protocol. * would be rate limited by the protocol.
@ -1345,19 +1353,13 @@ logsend:
* associate with an access point. */ * associate with an access point. */
} }
/* Restore the control buffer assignment. */
if (!IN6_ARE_ADDR_EQUAL(&dst.sin6_addr, &alldhcp)) {
ctx->sndhdr.msg_control = ctx->sndbuf;
ctx->sndhdr.msg_controllen = sizeof(ctx->sndbuf);
}
state->RTC++; state->RTC++;
if (callback) { if (callback) {
if (state->MRC == 0 || state->RTC < state->MRC) if (state->MRC == 0 || state->RTC < state->MRC)
eloop_timeout_add_tv(ifp->ctx->eloop, eloop_timeout_add_tv(ctx->eloop,
&state->RT, callback, ifp); &state->RT, callback, ifp);
else if (state->MRC != 0 && state->MRCcallback) else if (state->MRC != 0 && state->MRCcallback)
eloop_timeout_add_tv(ifp->ctx->eloop, eloop_timeout_add_tv(ctx->eloop,
&state->RT, state->MRCcallback, ifp); &state->RT, state->MRCcallback, ifp);
else else
logwarnx("%s: sent %d times with no reply", logwarnx("%s: sent %d times with no reply",
@ -1650,7 +1652,7 @@ dhcp6_fail(struct interface *ifp)
break; break;
} }
dhcp6_bind(ifp, NULL); dhcp6_bind(ifp, NULL, NULL);
switch (state->state) { switch (state->state) {
case DH6S_BOUND: case DH6S_BOUND:
@ -1911,13 +1913,16 @@ static int
dhcp6_checkstatusok(const struct interface *ifp, dhcp6_checkstatusok(const struct interface *ifp,
struct dhcp6_message *m, uint8_t *p, size_t len) struct dhcp6_message *m, uint8_t *p, size_t len)
{ {
struct dhcp6_state *state;
uint8_t *opt; uint8_t *opt;
uint16_t opt_len, code; uint16_t opt_len, code;
size_t mlen; size_t mlen;
void * (*f)(void *, size_t, uint16_t, uint16_t *), *farg; void * (*f)(void *, size_t, uint16_t, uint16_t *), *farg;
char buf[32], *sbuf; char buf[32], *sbuf;
const char *status; const char *status;
logfunc_t *logfunc;
state = D6_STATE(ifp);
f = p ? dhcp6_findoption : dhcp6_findmoption; f = p ? dhcp6_findoption : dhcp6_findmoption;
if (p) if (p)
farg = p; farg = p;
@ -1925,6 +1930,7 @@ dhcp6_checkstatusok(const struct interface *ifp,
farg = m; farg = m;
if ((opt = f(farg, len, D6_OPTION_STATUS_CODE, &opt_len)) == NULL) { if ((opt = f(farg, len, D6_OPTION_STATUS_CODE, &opt_len)) == NULL) {
//logdebugx("%s: no status", ifp->name); //logdebugx("%s: no status", ifp->name);
state->lerror = 0;
return 0; return 0;
} }
@ -1934,8 +1940,10 @@ dhcp6_checkstatusok(const struct interface *ifp,
} }
memcpy(&code, opt, sizeof(code)); memcpy(&code, opt, sizeof(code));
code = ntohs(code); code = ntohs(code);
if (code == D6_STATUS_OK) if (code == D6_STATUS_OK) {
state->lerror = 0;
return 1; return 1;
}
/* Anything after the code is a message. */ /* Anything after the code is a message. */
opt += sizeof(code); opt += sizeof(code);
@ -1958,8 +1966,13 @@ dhcp6_checkstatusok(const struct interface *ifp,
status = sbuf; status = sbuf;
} }
logerrx("%s: DHCPv6 REPLY: %s", ifp->name, status); if (state->lerror == code || state->state == DH6S_INIT)
logfunc = logdebugx;
else
logfunc = logerrx;
logfunc("%s: DHCPv6 REPLY: %s", ifp->name, status);
free(sbuf); free(sbuf);
state->lerror = code;
return -1; return -1;
} }
@ -2927,7 +2940,7 @@ dhcp6_find_delegates(struct interface *ifp)
#endif #endif
static void static void
dhcp6_bind(struct interface *ifp, const char *op) dhcp6_bind(struct interface *ifp, const char *op, const char *sfrom)
{ {
struct dhcp6_state *state = D6_STATE(ifp); struct dhcp6_state *state = D6_STATE(ifp);
bool has_new = false; bool has_new = false;
@ -2943,8 +2956,7 @@ dhcp6_bind(struct interface *ifp, const char *op)
} }
lognewinfo = has_new ? loginfox : logdebugx; lognewinfo = has_new ? loginfox : logdebugx;
if (op != NULL) if (op != NULL)
lognewinfo("%s: %s received from %s", lognewinfo("%s: %s received from %s", ifp->name, op, sfrom);
ifp->name, op, ifp->ctx->sfrom);
state->reason = NULL; state->reason = NULL;
if (state->state != DH6S_ITIMEDOUT) if (state->state != DH6S_ITIMEDOUT)
@ -3176,7 +3188,8 @@ dhcp6_bind(struct interface *ifp, const char *op)
} }
static void static void
dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len) dhcp6_recvif(struct interface *ifp, const char *sfrom,
struct dhcp6_message *r, size_t len)
{ {
struct dhcpcd_ctx *ctx; struct dhcpcd_ctx *ctx;
size_t i; size_t i;
@ -3211,8 +3224,7 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len)
} }
if (dhcp6_findmoption(r, len, D6_OPTION_SERVERID, NULL) == NULL) { if (dhcp6_findmoption(r, len, D6_OPTION_SERVERID, NULL) == NULL) {
logdebugx("%s: no DHCPv6 server ID from %s", logdebugx("%s: no DHCPv6 server ID from %s", ifp->name, sfrom);
ifp->name, ctx->sfrom);
return; return;
} }
@ -3225,14 +3237,14 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len)
!dhcp6_findmoption(r, len, (uint16_t)opt->option, NULL)) !dhcp6_findmoption(r, len, (uint16_t)opt->option, NULL))
{ {
logwarnx("%s: reject DHCPv6 (no option %s) from %s", logwarnx("%s: reject DHCPv6 (no option %s) from %s",
ifp->name, opt->var, ctx->sfrom); ifp->name, opt->var, sfrom);
return; return;
} }
if (has_option_mask(ifo->rejectmask6, opt->option) && if (has_option_mask(ifo->rejectmask6, opt->option) &&
dhcp6_findmoption(r, len, (uint16_t)opt->option, NULL)) dhcp6_findmoption(r, len, (uint16_t)opt->option, NULL))
{ {
logwarnx("%s: reject DHCPv6 (option %s) from %s", logwarnx("%s: reject DHCPv6 (option %s) from %s",
ifp->name, opt->var, ctx->sfrom); ifp->name, opt->var, sfrom);
return; return;
} }
} }
@ -3245,7 +3257,7 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len)
(uint8_t *)r, len, 6, r->type, auth, auth_len) == NULL) (uint8_t *)r, len, 6, r->type, auth, auth_len) == NULL)
{ {
logerr("%s: authentication failed from %s", logerr("%s: authentication failed from %s",
ifp->name, ctx->sfrom); ifp->name, sfrom);
return; return;
} }
if (state->auth.token) if (state->auth.token)
@ -3256,11 +3268,10 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len)
} else if (ifo->auth.options & DHCPCD_AUTH_SEND) { } else if (ifo->auth.options & DHCPCD_AUTH_SEND) {
if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) { if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) {
logerr("%s: no authentication from %s", logerr("%s: no authentication from %s",
ifp->name, ctx->sfrom); ifp->name, sfrom);
return; return;
} }
logwarnx("%s: no authentication from %s", logwarnx("%s: no authentication from %s", ifp->name, sfrom);
ifp->name, ctx->sfrom);
} }
#endif #endif
@ -3274,8 +3285,7 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len)
return; return;
break; break;
case DH6S_CONFIRM: case DH6S_CONFIRM:
if (dhcp6_validatelease(ifp, r, len, if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1)
ctx->sfrom, NULL) == -1)
{ {
dhcp6_startdiscover(ifp); dhcp6_startdiscover(ifp);
return; return;
@ -3297,8 +3307,7 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len)
case DH6S_REQUEST: /* FALLTHROUGH */ case DH6S_REQUEST: /* FALLTHROUGH */
case DH6S_RENEW: /* FALLTHROUGH */ case DH6S_RENEW: /* FALLTHROUGH */
case DH6S_REBIND: case DH6S_REBIND:
if (dhcp6_validatelease(ifp, r, len, if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1)
ctx->sfrom, NULL) == -1)
{ {
/* /*
* If we can't use the lease, fallback to * If we can't use the lease, fallback to
@ -3366,7 +3375,7 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len)
logerrx("%s: invalid INF_MAX_RT %u", logerrx("%s: invalid INF_MAX_RT %u",
ifp->name, max_rt); ifp->name, max_rt);
} }
if (dhcp6_validatelease(ifp, r, len, ctx->sfrom, NULL) == -1) if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1)
return; return;
break; break;
case DHCP6_RECONFIGURE: case DHCP6_RECONFIGURE:
@ -3374,12 +3383,12 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len)
if (auth == NULL) { if (auth == NULL) {
#endif #endif
logerrx("%s: unauthenticated %s from %s", logerrx("%s: unauthenticated %s from %s",
ifp->name, op, ctx->sfrom); ifp->name, op, sfrom);
if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) if (ifo->auth.options & DHCPCD_AUTH_REQUIRE)
return; return;
#ifdef AUTH #ifdef AUTH
} }
loginfox("%s: %s from %s", ifp->name, op, ctx->sfrom); loginfox("%s: %s from %s", ifp->name, op, sfrom);
o = dhcp6_findmoption(r, len, D6_OPTION_RECONF_MSG, &ol); o = dhcp6_findmoption(r, len, D6_OPTION_RECONF_MSG, &ol);
if (o == NULL) { if (o == NULL) {
logerrx("%s: missing Reconfigure Message option", logerrx("%s: missing Reconfigure Message option",
@ -3456,10 +3465,10 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len)
ia = TAILQ_FIRST(&state->addrs); ia = TAILQ_FIRST(&state->addrs);
if (ia == NULL) if (ia == NULL)
loginfox("%s: ADV (no address) from %s", loginfox("%s: ADV (no address) from %s",
ifp->name, ctx->sfrom); ifp->name, sfrom);
else else
loginfox("%s: ADV %s from %s", loginfox("%s: ADV %s from %s",
ifp->name, ia->saddr, ctx->sfrom); ifp->name, ia->saddr, sfrom);
if (ifp->ctx->options & DHCPCD_TEST) if (ifp->ctx->options & DHCPCD_TEST)
break; break;
dhcp6_startrequest(ifp); dhcp6_startrequest(ifp);
@ -3467,97 +3476,81 @@ dhcp6_recvif(struct interface *ifp, struct dhcp6_message *r, size_t len)
} }
} }
dhcp6_bind(ifp, op); dhcp6_bind(ifp, op, sfrom);
} }
static void static void
dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia) dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia)
{ {
struct sockaddr_in6 from;
unsigned char buf[64 * 1024]; /* Maximum UDP message size */
struct iovec iov = {
.iov_base = buf,
.iov_len = sizeof(buf),
};
unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
struct msghdr msg = {
.msg_name = &from, .msg_namelen = sizeof(from),
.msg_iov = &iov, .msg_iovlen = 1,
.msg_control = ctl, .msg_controllen = sizeof(ctl),
};
int s; int s;
size_t len; size_t len;
ssize_t bytes; ssize_t bytes;
char sfrom[INET6_ADDRSTRLEN];
struct interface *ifp; struct interface *ifp;
struct dhcp6_message *r; struct dhcp6_message *r;
const struct dhcp6_state *state; const struct dhcp6_state *state;
uint8_t *o; uint8_t *o;
uint16_t ol; uint16_t ol;
ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_fd; s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_fd;
bytes = recvmsg_realloc(s, &ctx->rcvhdr, 0); bytes = recvmsg(s, &msg, 0);
if (bytes == -1) { if (bytes == -1) {
logerr("%s: recvmsg_realloc", __func__); logerr(__func__);
return; return;
} }
len = (size_t)bytes; len = (size_t)bytes;
ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr, inet_ntop(AF_INET6, &from.sin6_addr, sfrom, sizeof(sfrom));
ctx->ntopbuf, sizeof(ctx->ntopbuf));
if (len < sizeof(struct dhcp6_message)) { if (len < sizeof(struct dhcp6_message)) {
logerrx("DHCPv6 packet too short from %s", ctx->sfrom); logerrx("DHCPv6 packet too short from %s", sfrom);
return; return;
} }
if (ia != NULL) if (ia != NULL)
ifp = ia->iface; ifp = ia->iface;
else { else {
struct cmsghdr *cm; ifp = if_findifpfromcmsg(ctx, &msg, NULL);
struct in6_pktinfo pi;
pi.ipi6_ifindex = 0;
for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr);
cm;
cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm))
{
if (cm->cmsg_level != IPPROTO_IPV6)
continue;
switch(cm->cmsg_type) {
case IPV6_PKTINFO:
if (cm->cmsg_len == CMSG_LEN(sizeof(pi)))
memcpy(&pi, CMSG_DATA(cm), sizeof(pi));
break;
}
}
if (pi.ipi6_ifindex == 0) {
logerrx("DHCPv6 reply did not contain index from %s",
ctx->sfrom);
return;
}
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
if (ifp->index == (unsigned int)pi.ipi6_ifindex)
break;
}
if (ifp == NULL) { if (ifp == NULL) {
logerrx("DHCPv6 reply for unexpected interface from %s", logerr(__func__);
ctx->sfrom);
return; return;
} }
} }
r = (struct dhcp6_message *)ctx->rcvhdr.msg_iov[0].iov_base; r = (struct dhcp6_message *)buf;
o = dhcp6_findmoption(r, len, D6_OPTION_CLIENTID, &ol); o = dhcp6_findmoption(r, len, D6_OPTION_CLIENTID, &ol);
if (o == NULL || ol != ctx->duid_len || if (o == NULL || ol != ctx->duid_len ||
memcmp(o, ctx->duid, ol) != 0) memcmp(o, ctx->duid, ol) != 0)
{ {
logdebugx("%s: incorrect client ID from %s", logdebugx("%s: incorrect client ID from %s",
ifp->name, ctx->sfrom); ifp->name, sfrom);
return; return;
} }
if (dhcp6_findmoption(r, len, D6_OPTION_SERVERID, NULL) == NULL) { if (dhcp6_findmoption(r, len, D6_OPTION_SERVERID, NULL) == NULL) {
logdebugx("%s: no DHCPv6 server ID from %s", logdebugx("%s: no DHCPv6 server ID from %s",
ifp->name, ctx->sfrom); ifp->name, sfrom);
return; return;
} }
if (r->type == DHCP6_RECONFIGURE) { if (r->type == DHCP6_RECONFIGURE) {
logdebugx("%s: RECONFIGURE6 recv from %s," logdebugx("%s: RECONFIGURE6 recv from %s,"
" sending to all interfaces", " sending to all interfaces",
ifp->name, ctx->sfrom); ifp->name, sfrom);
TAILQ_FOREACH(ifp, ctx->ifaces, next) { TAILQ_FOREACH(ifp, ctx->ifaces, next) {
state = D6_CSTATE(ifp); state = D6_CSTATE(ifp);
if (state != NULL && state->send != NULL) if (state != NULL && state->send != NULL)
dhcp6_recvif(ifp, r, len); dhcp6_recvif(ifp, sfrom, r, len);
} }
return; return;
} }
@ -3591,7 +3584,7 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia)
state->send->xid[0], state->send->xid[0],
state->send->xid[1], state->send->xid[1],
state->send->xid[2], state->send->xid[2],
ctx->sfrom); sfrom);
return; return;
} }
logdebugx("%s: redirecting DHCP6 message to %s", logdebugx("%s: redirecting DHCP6 message to %s",
@ -3599,7 +3592,7 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia)
ifp = ifp1; ifp = ifp1;
} }
dhcp6_recvif(ifp, r, len); dhcp6_recvif(ifp, sfrom, r, len);
} }
static void static void
@ -3812,6 +3805,7 @@ dhcp6_start(struct interface *ifp, enum DH6S init_state)
gogogo: gogogo:
state->state = init_state; state->state = init_state;
state->lerror = 0;
dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile), dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
AF_INET6, ifp); AF_INET6, ifp);
if (ipv6_linklocal(ifp) == NULL) { if (ipv6_linklocal(ifp) == NULL) {
@ -3831,18 +3825,20 @@ dhcp6_reboot(struct interface *ifp)
struct dhcp6_state *state; struct dhcp6_state *state;
state = D6_STATE(ifp); state = D6_STATE(ifp);
if (state) { if (state == NULL)
switch (state->state) { return;
case DH6S_BOUND:
dhcp6_startrebind(ifp); state->lerror = 0;
break; switch (state->state) {
case DH6S_INFORMED: case DH6S_BOUND:
dhcp6_startinform(ifp); dhcp6_startrebind(ifp);
break; break;
default: case DH6S_INFORMED:
dhcp6_startdiscover(ifp); dhcp6_startinform(ifp);
break; break;
} default:
dhcp6_startdiscover(ifp);
break;
} }
} }

View File

@ -206,7 +206,7 @@ struct dhcp6_state {
/* The +3 is for the possible .pd extension for prefix delegation */ /* The +3 is for the possible .pd extension for prefix delegation */
char leasefile[sizeof(LEASEFILE6) + IF_NAMESIZE + (IF_SSIDLEN * 4) +3]; char leasefile[sizeof(LEASEFILE6) + IF_NAMESIZE + (IF_SSIDLEN * 4) +3];
const char *reason; const char *reason;
uint16_t lerror; /* Last error received from DHCPv6 reply. */
struct authstate auth; struct authstate auth;
}; };

View File

@ -584,7 +584,7 @@ This has no effect on DHCPv6 other than skipping the reboot phase.
.Nm .Nm
will try to do as much as it can by default. will try to do as much as it can by default.
However, there are sometimes situations where you don't want the things to be However, there are sometimes situations where you don't want the things to be
configured exactly how the the DHCP server wants. configured exactly how the DHCP server wants.
Here are some options that deal with turning these bits off. Here are some options that deal with turning these bits off.
.Pp .Pp
Note that when Note that when

View File

@ -54,6 +54,7 @@ const char dhcpcd_copyright[] = "Copyright (c) 2006-2019 Roy Marples";
#include "dev.h" #include "dev.h"
#include "dhcp-common.h" #include "dhcp-common.h"
#include "dhcpcd.h" #include "dhcpcd.h"
#include "dhcp.h"
#include "dhcp6.h" #include "dhcp6.h"
#include "duid.h" #include "duid.h"
#include "eloop.h" #include "eloop.h"
@ -978,7 +979,12 @@ dhcpcd_prestartinterface(void *arg)
if ((!(ifp->ctx->options & DHCPCD_MASTER) || if ((!(ifp->ctx->options & DHCPCD_MASTER) ||
ifp->options->options & DHCPCD_IF_UP) && ifp->options->options & DHCPCD_IF_UP) &&
if_up(ifp) == -1) if_up(ifp) == -1
#ifdef __sun
/* Interface could not yet be plumbed. */
&& errno != ENXIO
#endif
)
logerr("%s: %s", __func__, ifp->name); logerr("%s: %s", __func__, ifp->name);
if (ifp->options->options & DHCPCD_LINK && if (ifp->options->options & DHCPCD_LINK &&
@ -1606,9 +1612,6 @@ main(int argc, char **argv)
ctx.cffile = CONFIG; ctx.cffile = CONFIG;
ctx.control_fd = ctx.control_unpriv_fd = ctx.link_fd = -1; ctx.control_fd = ctx.control_unpriv_fd = ctx.link_fd = -1;
ctx.pf_inet_fd = -1; ctx.pf_inet_fd = -1;
#ifdef IFLR_ACTIVE
ctx.pf_link_fd = -1;
#endif
TAILQ_INIT(&ctx.control_fds); TAILQ_INIT(&ctx.control_fds);
#ifdef PLUGIN_DEV #ifdef PLUGIN_DEV
@ -2142,7 +2145,6 @@ exit1:
#endif #endif
dev_stop(&ctx); dev_stop(&ctx);
eloop_free(ctx.eloop); eloop_free(ctx.eloop);
free(ctx.iov[0].iov_base);
if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED)) if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED))
loginfox(PACKAGE " exited"); loginfox(PACKAGE " exited");

View File

@ -142,14 +142,10 @@ struct dhcpcd_ctx {
struct rt_head froutes; /* free routes for re-use */ struct rt_head froutes; /* free routes for re-use */
int pf_inet_fd; int pf_inet_fd;
#ifdef IFLR_ACTIVE
int pf_link_fd;
#endif
void *priv; void *priv;
int link_fd; int link_fd;
int seq; /* route message sequence no */ int seq; /* route message sequence no */
int sseq; /* successful seq no sent */ int sseq; /* successful seq no sent */
struct iovec iov[1]; /* generic iovec buffer */
#ifdef USE_SIGNALS #ifdef USE_SIGNALS
sigset_t sigset; sigset_t sigset;
@ -184,15 +180,6 @@ struct dhcpcd_ctx {
uint8_t *secret; uint8_t *secret;
size_t secret_len; size_t secret_len;
unsigned char ctlbuf[IP6BUFLEN];
struct sockaddr_in6 from;
struct msghdr sndhdr;
struct iovec sndiov[1];
unsigned char sndbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
struct msghdr rcvhdr;
char ntopbuf[INET6_ADDRSTRLEN];
const char *sfrom;
int nd_fd; int nd_fd;
struct ra_head *ra_routers; struct ra_head *ra_routers;

View File

@ -90,6 +90,7 @@ duid_machineuuid(char *uuid, size_t uuid_len)
fclose(fp); fclose(fp);
r = len == 1 ? -1 : 0; r = len == 1 ? -1 : 0;
#else #else
UNUSED(uuid);
r = -1; r = -1;
errno = ENOSYS; errno = ENOSYS;
#endif #endif

View File

@ -99,14 +99,20 @@
#endif #endif
#ifdef INET6 #ifdef INET6
static void static void ifa_setscope(struct sockaddr_in6 *, unsigned int);
ifa_scope(struct sockaddr_in6 *, unsigned int); static unsigned int ifa_getscope(const struct sockaddr_in6 *);
#endif #endif
struct priv { struct priv {
int pf_inet6_fd; int pf_inet6_fd;
}; };
struct rtm
{
struct rt_msghdr hdr;
char buffer[sizeof(struct sockaddr_storage) * RTAX_MAX];
};
int int
if_init(__unused struct interface *iface) if_init(__unused struct interface *iface)
{ {
@ -418,9 +424,13 @@ if_findsa(struct dhcpcd_ctx *ctx, const struct sockaddr *sa)
case AF_INET6: case AF_INET6:
{ {
const struct sockaddr_in6 *sin; const struct sockaddr_in6 *sin;
unsigned int scope;
struct ipv6_addr *ia; struct ipv6_addr *ia;
sin = (const void *)sa; sin = (const void *)sa;
scope = ifa_getscope(sin);
if (scope != 0)
return if_findindex(ctx->ifaces, scope);
if ((ia = ipv6_findmaskaddr(ctx, &sin->sin6_addr))) if ((ia = ipv6_findmaskaddr(ctx, &sin->sin6_addr)))
return ia->iface; return ia->iface;
break; break;
@ -458,11 +468,7 @@ int
if_route(unsigned char cmd, const struct rt *rt) if_route(unsigned char cmd, const struct rt *rt)
{ {
struct dhcpcd_ctx *ctx; struct dhcpcd_ctx *ctx;
struct rtm struct rtm rtmsg;
{
struct rt_msghdr hdr;
char buffer[sizeof(struct sockaddr_storage) * RTAX_MAX];
} rtmsg;
struct rt_msghdr *rtm = &rtmsg.hdr; struct rt_msghdr *rtm = &rtmsg.hdr;
char *bp = rtmsg.buffer; char *bp = rtmsg.buffer;
struct sockaddr_dl sdl; struct sockaddr_dl sdl;
@ -577,7 +583,7 @@ if_route(unsigned char cmd, const struct rt *rt)
if_copysa(&gateway.sa, &rt->rt_gateway); if_copysa(&gateway.sa, &rt->rt_gateway);
#ifdef INET6 #ifdef INET6
if (gateway.sa.sa_family == AF_INET6) if (gateway.sa.sa_family == AF_INET6)
ifa_scope(&gateway.sin6, rt->rt_ifp->index); ifa_setscope(&gateway.sin6, rt->rt_ifp->index);
#endif #endif
ADDSA(&gateway.sa); ADDSA(&gateway.sa);
} }
@ -605,19 +611,27 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, const struct rt_msghdr *rtm)
{ {
const struct sockaddr *rti_info[RTAX_MAX]; const struct sockaddr *rti_info[RTAX_MAX];
if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY)) if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY)) {
errno = EINVAL;
return -1; return -1;
}
#ifdef RTF_CLONED #ifdef RTF_CLONED
if (rtm->rtm_flags & RTF_CLONED) if (rtm->rtm_flags & RTF_CLONED) {
errno = ENOTSUP;
return -1; return -1;
}
#endif #endif
#ifdef RTF_LOCAL #ifdef RTF_LOCAL
if (rtm->rtm_flags & RTF_LOCAL) if (rtm->rtm_flags & RTF_LOCAL) {
errno = ENOTSUP;
return -1; return -1;
}
#endif #endif
#ifdef RTF_BROADCAST #ifdef RTF_BROADCAST
if (rtm->rtm_flags & RTF_BROADCAST) if (rtm->rtm_flags & RTF_BROADCAST) {
errno = ENOTSUP;
return -1; return -1;
}
#endif #endif
get_addrs(rtm->rtm_addrs, rtm + 1, rti_info); get_addrs(rtm->rtm_addrs, rtm + 1, rti_info);
@ -688,7 +702,7 @@ if_initrt(struct dhcpcd_ctx *ctx, int af)
rtm = (void *)p; rtm = (void *)p;
if (if_copyrt(ctx, &rt, rtm) == 0) { if (if_copyrt(ctx, &rt, rtm) == 0) {
rt.rt_dflags |= RTDF_INIT; rt.rt_dflags |= RTDF_INIT;
rt_recvrt(RTM_ADD, &rt); rt_recvrt(RTM_ADD, &rt, rtm->rtm_pid);
} }
} }
free(buf); free(buf);
@ -751,7 +765,7 @@ if_addrflags(const struct interface *ifp, const struct in_addr *addr,
#ifdef INET6 #ifdef INET6
static void static void
ifa_scope(struct sockaddr_in6 *sin, unsigned int ifindex) ifa_setscope(struct sockaddr_in6 *sin, unsigned int ifindex)
{ {
#ifdef __KAME__ #ifdef __KAME__
@ -771,6 +785,23 @@ ifa_scope(struct sockaddr_in6 *sin, unsigned int ifindex)
#endif #endif
} }
static unsigned int
ifa_getscope(const struct sockaddr_in6 *sin)
{
#ifdef __KAME__
uint16_t scope;
#endif
if (!IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
return 0;
#ifdef __KAME__
memcpy(&scope, &sin->sin6_addr.s6_addr[2], sizeof(scope));
return (unsigned int)ntohs(scope);
#else
return (unsigned int)sin->sin6_scope_id;
#endif
}
int int
if_address6(unsigned char cmd, const struct ipv6_addr *ia) if_address6(unsigned char cmd, const struct ipv6_addr *ia)
{ {
@ -810,7 +841,7 @@ if_address6(unsigned char cmd, const struct ipv6_addr *ia)
} }
ADDADDR(&ifa.ifra_addr, &ia->addr); ADDADDR(&ifa.ifra_addr, &ia->addr);
ifa_scope(&ifa.ifra_addr, ia->iface->index); ifa_setscope(&ifa.ifra_addr, ia->iface->index);
ipv6_mask(&mask, ia->prefix_len); ipv6_mask(&mask, ia->prefix_len);
ADDADDR(&ifa.ifra_prefixmask, &mask); ADDADDR(&ifa.ifra_prefixmask, &mask);
@ -887,7 +918,7 @@ if_addrflags6(const struct interface *ifp, const struct in6_addr *addr,
strlcpy(ifr6.ifr_name, ifp->name, sizeof(ifr6.ifr_name)); strlcpy(ifr6.ifr_name, ifp->name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr.sin6_family = AF_INET6; ifr6.ifr_addr.sin6_family = AF_INET6;
ifr6.ifr_addr.sin6_addr = *addr; ifr6.ifr_addr.sin6_addr = *addr;
ifa_scope(&ifr6.ifr_addr, ifp->index); ifa_setscope(&ifr6.ifr_addr, ifp->index);
priv = (struct priv *)ifp->ctx->priv; priv = (struct priv *)ifp->ctx->priv;
if (ioctl(priv->pf_inet6_fd, SIOCGIFAFLAG_IN6, &ifr6) != -1) if (ioctl(priv->pf_inet6_fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
flags = ifr6.ifr_ifru.ifru_flags6; flags = ifr6.ifr_ifru.ifru_flags6;
@ -908,7 +939,7 @@ if_getlifetime6(struct ipv6_addr *ia)
strlcpy(ifr6.ifr_name, ia->iface->name, sizeof(ifr6.ifr_name)); strlcpy(ifr6.ifr_name, ia->iface->name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr.sin6_family = AF_INET6; ifr6.ifr_addr.sin6_family = AF_INET6;
ifr6.ifr_addr.sin6_addr = ia->addr; ifr6.ifr_addr.sin6_addr = ia->addr;
ifa_scope(&ifr6.ifr_addr, ia->iface->index); ifa_setscope(&ifr6.ifr_addr, ia->iface->index);
priv = (struct priv *)ia->iface->ctx->priv; priv = (struct priv *)ia->iface->ctx->priv;
if (ioctl(priv->pf_inet6_fd, SIOCGIFALIFETIME_IN6, &ifr6) == -1) if (ioctl(priv->pf_inet6_fd, SIOCGIFALIFETIME_IN6, &ifr6) == -1)
return -1; return -1;
@ -1010,7 +1041,7 @@ if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
} }
#endif #endif
rt_recvrt(rtm->rtm_type, &rt); rt_recvrt(rtm->rtm_type, &rt, rtm->rtm_pid);
} }
static void static void
@ -1095,7 +1126,7 @@ if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam)
ifra.ifra_addr.sin_len = sizeof(ifra.ifra_addr); ifra.ifra_addr.sin_len = sizeof(ifra.ifra_addr);
ifra.ifra_addr.sin_addr = addr; ifra.ifra_addr.sin_addr = addr;
if (ioctl(ctx->pf_inet_fd, SIOCGIFALIAS, &ifra) == -1) { if (ioctl(ctx->pf_inet_fd, SIOCGIFALIAS, &ifra) == -1) {
if (errno != EADDRNOTAVAIL) if (errno != ENXIO && errno != EADDRNOTAVAIL)
logerr("%s: SIOCGIFALIAS", __func__); logerr("%s: SIOCGIFALIAS", __func__);
if (ifam->ifam_type != RTM_DELADDR) if (ifam->ifam_type != RTM_DELADDR)
break; break;
@ -1229,18 +1260,16 @@ if_dispatch(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
int int
if_handlelink(struct dhcpcd_ctx *ctx) if_handlelink(struct dhcpcd_ctx *ctx)
{ {
struct msghdr msg; struct rtm rtm;
struct iovec iov = { .iov_base = &rtm, .iov_len = sizeof(rtm) };
struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 };
ssize_t len; ssize_t len;
memset(&msg, 0, sizeof(msg)); len = recvmsg(ctx->link_fd, &msg, 0);
msg.msg_iov = ctx->iov;
msg.msg_iovlen = 1;
len = recvmsg_realloc(ctx->link_fd, &msg, 0);
if (len == -1) if (len == -1)
return -1; return -1;
if (len != 0) if (len != 0)
if_dispatch(ctx, ctx->iov[0].iov_base); if_dispatch(ctx, &rtm.hdr);
return 0; return 0;
} }

View File

@ -207,11 +207,12 @@ const struct option cf_options[] = {
{NULL, 0, NULL, '\0'} {NULL, 0, NULL, '\0'}
}; };
static const char *default_script = SCRIPT;
static char * static char *
add_environ(struct if_options *ifo, const char *value, int uniq) add_environ(char ***array, const char *value, int uniq)
{ {
char **newlist; char **newlist, **list = *array;
char **lst = ifo->environ;
size_t i = 0, l, lv; size_t i = 0, l, lv;
char *match = NULL, *p, *n; char *match = NULL, *p, *n;
@ -229,8 +230,8 @@ add_environ(struct if_options *ifo, const char *value, int uniq)
*p++ = '\0'; *p++ = '\0';
l = strlen(match); l = strlen(match);
while (lst && lst[i]) { while (list && list[i]) {
if (match && strncmp(lst[i], match, l) == 0) { if (match && strncmp(list[i], match, l) == 0) {
if (uniq) { if (uniq) {
n = strdup(value); n = strdup(value);
if (n == NULL) { if (n == NULL) {
@ -238,25 +239,25 @@ add_environ(struct if_options *ifo, const char *value, int uniq)
free(match); free(match);
return NULL; return NULL;
} }
free(lst[i]); free(list[i]);
lst[i] = n; list[i] = n;
} else { } else {
/* Append a space and the value to it */ /* Append a space and the value to it */
l = strlen(lst[i]); l = strlen(list[i]);
lv = strlen(p); lv = strlen(p);
n = realloc(lst[i], l + lv + 2); n = realloc(list[i], l + lv + 2);
if (n == NULL) { if (n == NULL) {
logerr(__func__); logerr(__func__);
free(match); free(match);
return NULL; return NULL;
} }
lst[i] = n; list[i] = n;
lst[i][l] = ' '; list[i][l] = ' ';
memcpy(lst[i] + l + 1, p, lv); memcpy(list[i] + l + 1, p, lv);
lst[i][l + lv + 1] = '\0'; list[i][l + lv + 1] = '\0';
} }
free(match); free(match);
return lst[i]; return list[i];
} }
i++; i++;
} }
@ -267,7 +268,7 @@ add_environ(struct if_options *ifo, const char *value, int uniq)
logerr(__func__); logerr(__func__);
return NULL; return NULL;
} }
newlist = reallocarray(lst, i + 2, sizeof(char *)); newlist = reallocarray(list, i + 2, sizeof(char *));
if (newlist == NULL) { if (newlist == NULL) {
logerr(__func__); logerr(__func__);
free(n); free(n);
@ -275,26 +276,31 @@ add_environ(struct if_options *ifo, const char *value, int uniq)
} }
newlist[i] = n; newlist[i] = n;
newlist[i + 1] = NULL; newlist[i + 1] = NULL;
ifo->environ = newlist; *array = newlist;
return newlist[i]; return newlist[i];
} }
#define parse_string(buf, len, arg) parse_string_hwaddr(buf, len, arg, 0) #define PARSE_STRING 0
#define PARSE_STRING_NULL 1
#define PARSE_HWADDR 2
#define parse_string(a, b, c) parse_str((a), (b), (c), PARSE_STRING)
#define parse_hwaddr(a, b, c) parse_str((a), (b), (c), PARSE_HWADDR)
static ssize_t static ssize_t
parse_string_hwaddr(char *sbuf, size_t slen, const char *str, int clid) parse_str(char *sbuf, size_t slen, const char *str, int flags)
{ {
size_t l; size_t l;
const char *p; const char *p, *end;
int i, punt_last = 0; int i;
char c[4], cmd; char c[4], cmd;
end = str + strlen(str);
/* If surrounded by quotes then it's a string */ /* If surrounded by quotes then it's a string */
if (*str == '"') { if (*str == '"') {
str++; p = end - 1;
l = strlen(str); if (*p == '"') {
p = str + l - 1; str++;
if (*p == '"') end = p;
punt_last = 1; }
} else { } else {
l = (size_t)hwaddr_aton(NULL, str); l = (size_t)hwaddr_aton(NULL, str);
if ((ssize_t) l != -1 && l > 1) { if ((ssize_t) l != -1 && l > 1) {
@ -311,13 +317,13 @@ parse_string_hwaddr(char *sbuf, size_t slen, const char *str, int clid)
l = 0; l = 0;
/* If processing a string on the clientid, first byte should be /* If processing a string on the clientid, first byte should be
* 0 to indicate a non hardware type */ * 0 to indicate a non hardware type */
if (clid && *str) { if (flags == PARSE_HWADDR && *str) {
if (sbuf) if (sbuf)
*sbuf++ = 0; *sbuf++ = 0;
l++; l++;
} }
c[3] = '\0'; c[3] = '\0';
while (*str) { while (str < end) {
if (++l > slen && sbuf) { if (++l > slen && sbuf) {
errno = ENOBUFS; errno = ENOBUFS;
return -1; return -1;
@ -385,11 +391,8 @@ parse_string_hwaddr(char *sbuf, size_t slen, const char *str, int clid)
str++; str++;
} }
} }
if (punt_last) { if (flags == PARSE_STRING_NULL && sbuf)
if (sbuf) *sbuf = '\0';
*--sbuf = '\0';
l--;
}
return (ssize_t)l; return (ssize_t)l;
} }
@ -654,7 +657,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
int e, i, t; int e, i, t;
long l; long l;
unsigned long u; unsigned long u;
char *p = NULL, *bp, *fp, *np, **nconf; char *p = NULL, *bp, *fp, *np;
ssize_t s; ssize_t s;
struct in_addr addr, addr2; struct in_addr addr, addr2;
in_addr_t *naddr; in_addr_t *naddr;
@ -708,17 +711,33 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
break; break;
case 'c': case 'c':
ARG_REQUIRED; ARG_REQUIRED;
free(ifo->script); if (ifo->script != default_script)
ifo->script = strdup(arg); free(ifo->script);
if (ifo->script == NULL) s = parse_str(NULL, 0, arg, PARSE_STRING_NULL);
if (s == 0) {
ifo->script = NULL;
break;
}
dl = (size_t)s;
if (s == -1 || (ifo->script = malloc(dl)) == NULL) {
ifo->script = NULL;
logerr(__func__); logerr(__func__);
return -1;
}
parse_str(ifo->script, dl, arg, PARSE_STRING_NULL);
if (ifo->script[0] == '\0' ||
strcmp(ifo->script, "/dev/null") == 0)
{
free(ifo->script);
ifo->script = NULL;
}
break; break;
case 'd': case 'd':
ifo->options |= DHCPCD_DEBUG; ifo->options |= DHCPCD_DEBUG;
break; break;
case 'e': case 'e':
ARG_REQUIRED; ARG_REQUIRED;
add_environ(ifo, arg, 1); add_environ(&ifo->environ, arg, 1);
break; break;
case 'h': case 'h':
if (!arg) { if (!arg) {
@ -969,7 +988,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
return -1; return -1;
} }
snprintf(p, dl, "skip_hooks=%s", arg); snprintf(p, dl, "skip_hooks=%s", arg);
add_environ(ifo, p, 0); add_environ(&ifo->environ, p, 0);
free(p); free(p);
break; break;
case 'D': case 'D':
@ -1006,8 +1025,8 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
/* Strings have a type of 0 */; /* Strings have a type of 0 */;
ifo->clientid[1] = 0; ifo->clientid[1] = 0;
if (arg) if (arg)
s = parse_string_hwaddr((char *)ifo->clientid + 1, s = parse_hwaddr((char *)ifo->clientid + 1,
CLIENTID_MAX_LEN, arg, 1); CLIENTID_MAX_LEN, arg);
else else
s = 0; s = 0;
if (s == -1) { if (s == -1) {
@ -1112,6 +1131,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
sa_in_init(&rt->rt_gateway, &addr3); sa_in_init(&rt->rt_gateway, &addr3);
TAILQ_INSERT_TAIL(&ifo->routes, rt, rt_next); TAILQ_INSERT_TAIL(&ifo->routes, rt, rt_next);
*fp = ' '; *fp = ' ';
add_environ(&ifo->config, arg, 0);
} else if (strncmp(arg, "routers=", strlen("routers=")) == 0) { } else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
if (parse_addr(&addr, NULL, p) == -1) if (parse_addr(&addr, NULL, p) == -1)
return -1; return -1;
@ -1122,6 +1142,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
sa_in_init(&rt->rt_netmask, &addr2); sa_in_init(&rt->rt_netmask, &addr2);
sa_in_init(&rt->rt_gateway, &addr); sa_in_init(&rt->rt_gateway, &addr);
TAILQ_INSERT_TAIL(&ifo->routes, rt, rt_next); TAILQ_INSERT_TAIL(&ifo->routes, rt, rt_next);
add_environ(&ifo->config, arg, 0);
} else if (strncmp(arg, "interface_mtu=", } else if (strncmp(arg, "interface_mtu=",
strlen("interface_mtu=")) == 0 || strlen("interface_mtu=")) == 0 ||
strncmp(arg, "mtu=", strlen("mtu=")) == 0) strncmp(arg, "mtu=", strlen("mtu=")) == 0)
@ -1149,40 +1170,8 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
} else } else
ifo->req_prefix_len = 128; ifo->req_prefix_len = 128;
} }
} else { } else
dl = 0; add_environ(&ifo->config, arg, 1);
if (ifo->config != NULL) {
while (ifo->config[dl] != NULL) {
if (strncmp(ifo->config[dl], arg,
(size_t)(p - arg)) == 0)
{
p = strdup(arg);
if (p == NULL) {
logerr(__func__);
return -1;
}
free(ifo->config[dl]);
ifo->config[dl] = p;
return 1;
}
dl++;
}
}
p = strdup(arg);
if (p == NULL) {
logerr(__func__);
return -1;
}
nconf = reallocarray(ifo->config, dl+2, sizeof(char *));
if (nconf == NULL) {
logerr(__func__);
free(p);
return -1;
}
ifo->config = nconf;
ifo->config[dl] = p;
ifo->config[dl + 1] = NULL;
}
break; break;
case 'W': case 'W':
if (parse_addr(&addr, &addr2, arg) != 0) if (parse_addr(&addr, &addr2, arg) != 0)
@ -2277,6 +2266,7 @@ default_config(struct dhcpcd_ctx *ctx)
ifo->options |= DHCPCD_IF_UP | DHCPCD_LINK | DHCPCD_INITIAL_DELAY; ifo->options |= DHCPCD_IF_UP | DHCPCD_LINK | DHCPCD_INITIAL_DELAY;
ifo->timeout = DEFAULT_TIMEOUT; ifo->timeout = DEFAULT_TIMEOUT;
ifo->reboot = DEFAULT_REBOOT; ifo->reboot = DEFAULT_REBOOT;
ifo->script = UNCONST(default_script);
ifo->metric = -1; ifo->metric = -1;
ifo->auth.options |= DHCPCD_AUTH_REQUIRE; ifo->auth.options |= DHCPCD_AUTH_REQUIRE;
TAILQ_INIT(&ifo->routes); TAILQ_INIT(&ifo->routes);
@ -2626,7 +2616,8 @@ free_options(struct dhcpcd_ctx *ctx, struct if_options *ifo)
free(ifo->config); free(ifo->config);
} }
rt_headclear0(ctx, &ifo->routes, AF_UNSPEC); rt_headclear0(ctx, &ifo->routes, AF_UNSPEC);
free(ifo->script); if (ifo->script != default_script)
free(ifo->script);
free(ifo->arping); free(ifo->arping);
free(ifo->blacklist); free(ifo->blacklist);
free(ifo->fallback); free(ifo->fallback);

View File

@ -109,12 +109,6 @@ if_opensockets(struct dhcpcd_ctx *ctx)
if (ctx->pf_inet_fd == -1) if (ctx->pf_inet_fd == -1)
return -1; return -1;
#ifdef IFLR_ACTIVE
ctx->pf_link_fd = xsocket(PF_LINK, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (ctx->pf_link_fd == -1)
return -1;
#endif
return 0; return 0;
} }
@ -124,10 +118,6 @@ if_closesockets(struct dhcpcd_ctx *ctx)
if (ctx->pf_inet_fd != -1) if (ctx->pf_inet_fd != -1)
close(ctx->pf_inet_fd); close(ctx->pf_inet_fd);
#ifdef IFLR_ACTIVE
if (ctx->pf_link_fd != -1)
close(ctx->pf_link_fd);
#endif
if (ctx->priv) { if (ctx->priv) {
if_closesockets_os(ctx); if_closesockets_os(ctx);
@ -146,9 +136,15 @@ if_carrier(struct interface *ifp)
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == -1) r = ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr);
if (r != -1)
ifp->flags = (unsigned int)ifr.ifr_flags;
#ifdef __sun
return if_carrier_os(ifp);
#else
if (r == -1)
return LINK_UNKNOWN; return LINK_UNKNOWN;
ifp->flags = (unsigned int)ifr.ifr_flags;
#ifdef SIOCGIFMEDIA #ifdef SIOCGIFMEDIA
memset(&ifmr, 0, sizeof(ifmr)); memset(&ifmr, 0, sizeof(ifmr));
@ -165,6 +161,7 @@ if_carrier(struct interface *ifp)
#else #else
r = ifr.ifr_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN; r = ifr.ifr_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN;
#endif #endif
#endif /* __sun */
return r; return r;
} }
@ -342,12 +339,10 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
struct ifreq ifr; struct ifreq ifr;
#endif #endif
#ifdef IFLR_ACTIVE #ifdef IFLR_ACTIVE
struct if_laddrreq iflr; struct if_laddrreq iflr = { .flags = IFLR_PREFIX };
int link_fd;
#endif #endif
#ifdef IFLR_ACTIVE
memset(&iflr, 0, sizeof(iflr));
#endif
#elif AF_PACKET #elif AF_PACKET
const struct sockaddr_ll *sll; const struct sockaddr_ll *sll;
#endif #endif
@ -356,11 +351,21 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
logerr(__func__); logerr(__func__);
return NULL; return NULL;
} }
TAILQ_INIT(ifs);
if (getifaddrs(ifaddrs) == -1) { if (getifaddrs(ifaddrs) == -1) {
logerr(__func__); logerr(__func__);
goto out; free(ifs);
return NULL;
} }
TAILQ_INIT(ifs);
#ifdef IFLR_ACTIVE
link_fd = xsocket(PF_LINK, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (link_fd == -1) {
logerr(__func__);
free(ifs);
return NULL;
}
#endif
for (ifa = *ifaddrs; ifa; ifa = ifa->ifa_next) { for (ifa = *ifaddrs; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr != NULL) { if (ifa->ifa_addr != NULL) {
@ -457,7 +462,7 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr))); MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr)));
iflr.flags = IFLR_PREFIX; iflr.flags = IFLR_PREFIX;
iflr.prefixlen = (unsigned int)sdl->sdl_alen * NBBY; iflr.prefixlen = (unsigned int)sdl->sdl_alen * NBBY;
if (ioctl(ctx->pf_link_fd, SIOCGLIFADDR, &iflr) == -1 || if (ioctl(link_fd, SIOCGLIFADDR, &iflr) == -1 ||
!(iflr.flags & IFLR_ACTIVE)) !(iflr.flags & IFLR_ACTIVE))
{ {
if_free(ifp); if_free(ifp);
@ -610,7 +615,9 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
TAILQ_INSERT_TAIL(ifs, ifp, next); TAILQ_INSERT_TAIL(ifs, ifp, next);
} }
out: #ifdef IFLR_ACTIVE
close(link_fd);
#endif
return ifs; return ifs;
} }
@ -711,6 +718,11 @@ if_domtu(const struct interface *ifp, short int mtu)
int r; int r;
struct ifreq ifr; struct ifreq ifr;
#ifdef __sun
if (mtu == 0)
return if_mtu_os(ifp);
#endif
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
ifr.ifr_mtu = mtu; ifr.ifr_mtu = mtu;
@ -772,6 +784,17 @@ if_cmp(const struct interface *si, const struct interface *ti)
return 0; return 0;
} }
#ifdef ALIAS_ADDR
int
if_makealias(char *alias, size_t alias_len, const char *ifname, int lun)
{
if (lun == 0)
return strlcpy(alias, ifname, alias_len);
return snprintf(alias, alias_len, "%s:%u", ifname, lun);
}
#endif
/* Sort the interfaces into a preferred order - best first, worst last. */ /* Sort the interfaces into a preferred order - best first, worst last. */
void void
if_sortinterfaces(struct dhcpcd_ctx *ctx) if_sortinterfaces(struct dhcpcd_ctx *ctx)
@ -801,6 +824,68 @@ if_sortinterfaces(struct dhcpcd_ctx *ctx)
TAILQ_CONCAT(ctx->ifaces, &sorted, next); TAILQ_CONCAT(ctx->ifaces, &sorted, next);
} }
struct interface *
if_findifpfromcmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, int *hoplimit)
{
struct cmsghdr *cm;
unsigned int ifindex = 0;
struct interface *ifp;
#if defined(INET) && defined(IP_PKTINFO)
struct in_pktinfo ipi;
#endif
#ifdef INET6
struct in6_pktinfo ipi6;
#else
UNUSED(hoplimit);
#endif
for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(msg);
cm;
cm = (struct cmsghdr *)CMSG_NXTHDR(msg, cm))
{
#if defined(INET) && defined(IP_PKTINFO)
if (cm->cmsg_level == IPPROTO_IP) {
switch(cm->cmsg_type) {
case IP_PKTINFO:
if (cm->cmsg_len != CMSG_LEN(sizeof(ipi)))
continue;
memcpy(&ipi, CMSG_DATA(cm), sizeof(ipi));
ifindex = (unsigned int)ipi.ipi_ifindex;
break;
}
}
#endif
#ifdef INET6
if (cm->cmsg_level == IPPROTO_IPV6) {
switch(cm->cmsg_type) {
case IPV6_PKTINFO:
if (cm->cmsg_len != CMSG_LEN(sizeof(ipi6)))
continue;
memcpy(&ipi6, CMSG_DATA(cm), sizeof(ipi6));
ifindex = (unsigned int)ipi6.ipi6_ifindex;
break;
case IPV6_HOPLIMIT:
if (cm->cmsg_len != CMSG_LEN(sizeof(int)))
continue;
if (hoplimit == NULL)
break;
memcpy(hoplimit, CMSG_DATA(cm), sizeof(int));
break;
}
}
#endif
}
/* Find the receiving interface */
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
if (ifp->index == ifindex)
break;
}
if (ifp == NULL)
errno = ESRCH;
return ifp;
}
int int
xsocket(int domain, int type, int protocol) xsocket(int domain, int type, int protocol)
{ {

View File

@ -129,6 +129,13 @@ int if_domtu(const struct interface *, short int);
#define if_setmtu(ifp, mtu) if_domtu((ifp), (mtu)) #define if_setmtu(ifp, mtu) if_domtu((ifp), (mtu))
int if_carrier(struct interface *); int if_carrier(struct interface *);
#ifdef ALIAS_ADDR
int if_makealias(char *, size_t, const char *, int);
#endif
int if_carrier_os(struct interface *);
int if_mtu_os(const struct interface *);
/* /*
* Helper to decode an interface name of bge0:1 to * Helper to decode an interface name of bge0:1 to
* devname = bge0, drvname = bge0, ppa = 0, lun = 1. * devname = bge0, drvname = bge0, ppa = 0, lun = 1.
@ -209,5 +216,7 @@ int if_getlifetime6(struct ipv6_addr *);
#endif #endif
int if_machinearch(char *, size_t); int if_machinearch(char *, size_t);
struct interface *if_findifpfromcmsg(struct dhcpcd_ctx *,
struct msghdr *, int *);
int xsocket(int, int, int); int xsocket(int, int, int);
#endif #endif

View File

@ -563,10 +563,12 @@ ipv4_aliasaddr(struct ipv4_addr *ia, struct ipv4_addr **repl)
lun = 0; lun = 0;
state = IPV4_STATE(ia->iface); state = IPV4_STATE(ia->iface);
find_lun: find_lun:
if (lun == 0) if (if_makealias(alias, IF_NAMESIZE, ia->iface->name, lun) >=
strlcpy(alias, ia->iface->name, sizeof(alias)); IF_NAMESIZE)
else {
snprintf(alias, sizeof(alias), "%s:%u", ia->iface->name, lun); errno = ENOMEM;
return -1;
}
TAILQ_FOREACH(iap, &state->addrs, next) { TAILQ_FOREACH(iap, &state->addrs, next) {
if (iap->alias[0] != '\0' && iap->addr.s_addr == INADDR_ANY) { if (iap->alias[0] != '\0' && iap->addr.s_addr == INADDR_ANY) {
/* No address assigned? Lets use it. */ /* No address assigned? Lets use it. */

View File

@ -305,6 +305,8 @@ ipv4ll_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
ipv4_deladdr(state->addr, 1); ipv4_deladdr(state->addr, 1);
state->down = 1; state->down = 1;
state->addr = NULL; state->addr = NULL;
if_initrt(ifp->ctx, AF_INET);
rt_build(ifp->ctx, AF_INET);
script_runreason(ifp, "IPV4LL"); script_runreason(ifp, "IPV4LL");
} }

View File

@ -129,29 +129,14 @@ int
ipv6_init(struct dhcpcd_ctx *ctx) ipv6_init(struct dhcpcd_ctx *ctx)
{ {
if (ctx->sndhdr.msg_iovlen == 1) if (ctx->ra_routers != NULL)
return 0; return 0;
if (ctx->ra_routers == NULL) { ctx->ra_routers = malloc(sizeof(*ctx->ra_routers));
ctx->ra_routers = malloc(sizeof(*ctx->ra_routers)); if (ctx->ra_routers == NULL)
if (ctx->ra_routers == NULL) return -1;
return -1;
}
TAILQ_INIT(ctx->ra_routers); TAILQ_INIT(ctx->ra_routers);
ctx->sndhdr.msg_namelen = sizeof(struct sockaddr_in6);
ctx->sndhdr.msg_iov = ctx->sndiov;
ctx->sndhdr.msg_iovlen = 1;
ctx->sndhdr.msg_control = ctx->sndbuf;
ctx->sndhdr.msg_controllen = sizeof(ctx->sndbuf);
ctx->rcvhdr.msg_name = &ctx->from;
ctx->rcvhdr.msg_namelen = sizeof(ctx->from);
ctx->rcvhdr.msg_iov = ctx->iov;
ctx->rcvhdr.msg_iovlen = 1;
ctx->rcvhdr.msg_control = ctx->ctlbuf;
// controllen is set at recieve
//ctx->rcvhdr.msg_controllen = sizeof(ctx->rcvbuf);
ctx->nd_fd = -1; ctx->nd_fd = -1;
ctx->dhcp6_fd = -1; ctx->dhcp6_fd = -1;
return 0; return 0;
@ -639,6 +624,10 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
uint32_t pltime, vltime; uint32_t pltime, vltime;
bool vltime_was_zero; bool vltime_was_zero;
__printflike(1, 2) void (*logfunc)(const char *, ...); __printflike(1, 2) void (*logfunc)(const char *, ...);
#ifdef __sun
struct ipv6_state *state;
struct ipv6_addr *ia2;
#endif
/* Remember the interface of the address. */ /* Remember the interface of the address. */
ifp = ia->iface; ifp = ia->iface;
@ -774,13 +763,13 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
} }
#ifdef ALIAS_ADDR #ifdef ALIAS_ADDR
/* Find the next logical aliase address we can use. */ /* Find the next logical alias address we can use. */
static int static int
ipv6_aliasaddr(struct ipv6_addr *ia, struct ipv6_addr **repl) ipv6_aliasaddr(struct ipv6_addr *ia, struct ipv6_addr **repl)
{ {
struct ipv6_state *state; struct ipv6_state *state;
struct ipv6_addr *iap; struct ipv6_addr *iap;
unsigned int unit; unsigned int lun;
char alias[IF_NAMESIZE]; char alias[IF_NAMESIZE];
if (ia->alias[0] != '\0') if (ia->alias[0] != '\0')
@ -799,12 +788,14 @@ ipv6_aliasaddr(struct ipv6_addr *ia, struct ipv6_addr **repl)
} }
} }
unit = 0; lun = 0;
find_unit: find_unit:
if (unit == 0) if (if_makealias(alias, IF_NAMESIZE, ia->iface->name, lun) >=
strlcpy(alias, ia->iface->name, sizeof(alias)); IF_NAMESIZE)
else {
snprintf(alias, sizeof(alias), "%s:%u", ia->iface->name, unit); errno = ENOMEM;
return -1;
}
TAILQ_FOREACH(iap, &state->addrs, next) { TAILQ_FOREACH(iap, &state->addrs, next) {
if (iap->alias[0] == '\0') if (iap->alias[0] == '\0')
continue; continue;
@ -820,11 +811,11 @@ find_unit:
} }
if (iap != NULL) { if (iap != NULL) {
if (unit == UINT_MAX) { if (lun == UINT_MAX) {
errno = ERANGE; errno = ERANGE;
return -1; return -1;
} }
unit++; lun++;
goto find_unit; goto find_unit;
} }

View File

@ -274,10 +274,17 @@ ipv6nd_sendrsprobe(void *arg)
{ {
struct interface *ifp = arg; struct interface *ifp = arg;
struct dhcpcd_ctx *ctx; struct dhcpcd_ctx *ctx;
struct rs_state *state; struct rs_state *state = RS_STATE(ifp);
struct sockaddr_in6 dst; struct sockaddr_in6 dst = { .sin6_family = AF_INET6 };
struct iovec iov = { .iov_base = state->rs, .iov_len = state->rslen };
unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
struct msghdr msg = {
.msg_name = &dst, .msg_namelen = sizeof(dst),
.msg_iov = &iov, .msg_iovlen = 1,
.msg_control = ctl, .msg_controllen = sizeof(ctl),
};
struct cmsghdr *cm; struct cmsghdr *cm;
struct in6_pktinfo pi; struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
if (ipv6_linklocal(ifp) == NULL) { if (ipv6_linklocal(ifp) == NULL) {
logdebugx("%s: delaying Router Solicitation for LL address", logdebugx("%s: delaying Router Solicitation for LL address",
@ -286,8 +293,6 @@ ipv6nd_sendrsprobe(void *arg)
return; return;
} }
memset(&dst, 0, sizeof(dst));
dst.sin6_family = AF_INET6;
#ifdef HAVE_SA_LEN #ifdef HAVE_SA_LEN
dst.sin6_len = sizeof(dst); dst.sin6_len = sizeof(dst);
#endif #endif
@ -297,25 +302,19 @@ ipv6nd_sendrsprobe(void *arg)
return; return;
} }
state = RS_STATE(ifp);
ctx = ifp->ctx; ctx = ifp->ctx;
ctx->sndhdr.msg_name = (void *)&dst;
ctx->sndhdr.msg_iov[0].iov_base = state->rs;
ctx->sndhdr.msg_iov[0].iov_len = state->rslen;
/* Set the outbound interface */ /* Set the outbound interface */
cm = CMSG_FIRSTHDR(&ctx->sndhdr); cm = CMSG_FIRSTHDR(&msg);
if (cm == NULL) /* unlikely */ if (cm == NULL) /* unlikely */
return; return;
cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_PKTINFO; cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(pi)); cm->cmsg_len = CMSG_LEN(sizeof(pi));
memset(&pi, 0, sizeof(pi));
pi.ipi6_ifindex = ifp->index;
memcpy(CMSG_DATA(cm), &pi, sizeof(pi)); memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
logdebugx("%s: sending Router Solicitation", ifp->name); logdebugx("%s: sending Router Solicitation", ifp->name);
if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) { if (sendmsg(ctx->nd_fd, &msg, 0) == -1) {
logerr(__func__); logerr(__func__);
/* Allow IPv6ND to continue .... at most a few errors /* Allow IPv6ND to continue .... at most a few errors
* would be logged. * would be logged.
@ -341,41 +340,42 @@ ipv6nd_sendadvertisement(void *arg)
struct ipv6_addr *ia = arg; struct ipv6_addr *ia = arg;
struct interface *ifp = ia->iface; struct interface *ifp = ia->iface;
struct dhcpcd_ctx *ctx = ifp->ctx; struct dhcpcd_ctx *ctx = ifp->ctx;
struct sockaddr_in6 dst; struct sockaddr_in6 dst = {
.sin6_family = AF_INET6,
.sin6_scope_id = ifp->index,
};
struct iovec iov = { .iov_base = ia->na, .iov_len = ia->na_len };
unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
struct msghdr msg = {
.msg_name = &dst, .msg_namelen = sizeof(dst),
.msg_iov = &iov, .msg_iovlen = 1,
.msg_control = ctl, .msg_controllen = sizeof(ctl),
};
struct cmsghdr *cm; struct cmsghdr *cm;
struct in6_pktinfo pi; struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
const struct rs_state *state = RS_CSTATE(ifp); const struct rs_state *state = RS_CSTATE(ifp);
if (state == NULL || ifp->carrier <= LINK_DOWN) if (state == NULL || ifp->carrier <= LINK_DOWN)
goto freeit; goto freeit;
memset(&dst, 0, sizeof(dst));
dst.sin6_family = AF_INET6;
#ifdef SIN6_LEN #ifdef SIN6_LEN
dst.sin6_len = sizeof(dst); dst.sin6_len = sizeof(dst);
#endif #endif
dst.sin6_scope_id = ifp->index;
if (inet_pton(AF_INET6, ALLNODES, &dst.sin6_addr) != 1) { if (inet_pton(AF_INET6, ALLNODES, &dst.sin6_addr) != 1) {
logerr(__func__); logerr(__func__);
return; return;
} }
ctx->sndhdr.msg_name = (void *)&dst;
ctx->sndhdr.msg_iov[0].iov_base = ia->na;
ctx->sndhdr.msg_iov[0].iov_len = ia->na_len;
/* Set the outbound interface. */ /* Set the outbound interface. */
cm = CMSG_FIRSTHDR(&ctx->sndhdr); cm = CMSG_FIRSTHDR(&msg);
assert(cm != NULL); assert(cm != NULL);
cm->cmsg_level = IPPROTO_IPV6; cm->cmsg_level = IPPROTO_IPV6;
cm->cmsg_type = IPV6_PKTINFO; cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(pi)); cm->cmsg_len = CMSG_LEN(sizeof(pi));
memset(&pi, 0, sizeof(pi));
pi.ipi6_ifindex = ifp->index;
memcpy(CMSG_DATA(cm), &pi, sizeof(pi)); memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
logdebugx("%s: sending NA for %s", ifp->name, ia->saddr); logdebugx("%s: sending NA for %s", ifp->name, ia->saddr);
if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) if (sendmsg(ctx->nd_fd, &msg, 0) == -1)
logerr(__func__); logerr(__func__);
if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) { if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) {
@ -872,8 +872,9 @@ dhcp6_start(__unused struct interface *ifp, __unused enum DH6S init_state)
#endif #endif
static void static void
ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp, ipv6nd_handlera(struct dhcpcd_ctx *ctx,
struct icmp6_hdr *icp, size_t len, int hoplimit) const struct sockaddr_in6 *from, const char *sfrom,
struct interface *ifp, struct icmp6_hdr *icp, size_t len, int hoplimit)
{ {
size_t i, olen; size_t i, olen;
struct nd_router_advert *nd_ra; struct nd_router_advert *nd_ra;
@ -895,33 +896,29 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
if (ifp == NULL) { if (ifp == NULL) {
#ifdef DEBUG_RS #ifdef DEBUG_RS
logdebugx("RA for unexpected interface from %s", logdebugx("RA for unexpected interface from %s", sfrom);
ctx->sfrom);
#endif #endif
return; return;
} }
if (len < sizeof(struct nd_router_advert)) { if (len < sizeof(struct nd_router_advert)) {
logerrx("IPv6 RA packet too short from %s", ctx->sfrom); logerrx("IPv6 RA packet too short from %s", sfrom);
return; return;
} }
/* RFC 4861 7.1.2 */ /* RFC 4861 7.1.2 */
if (hoplimit != 255) { if (hoplimit != 255) {
logerrx("invalid hoplimit(%d) in RA from %s", logerrx("invalid hoplimit(%d) in RA from %s", hoplimit, sfrom);
hoplimit, ctx->sfrom);
return; return;
} }
if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) {
if (!IN6_IS_ADDR_LINKLOCAL(&ctx->from.sin6_addr)) { logerrx("RA from non local address %s", sfrom);
logerrx("RA from non local address %s", ctx->sfrom);
return; return;
} }
if (!(ifp->options->options & DHCPCD_IPV6RS)) { if (!(ifp->options->options & DHCPCD_IPV6RS)) {
#ifdef DEBUG_RS #ifdef DEBUG_RS
logerrx("%s: unexpected RA from %s", logerrx("%s: unexpected RA from %s", ifp->name, sfrom);
ifp->name, ctx->sfrom);
#endif #endif
return; return;
} }
@ -930,20 +927,20 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
if (ipv6_linklocal(ifp) == NULL) { if (ipv6_linklocal(ifp) == NULL) {
#ifdef DEBUG_RS #ifdef DEBUG_RS
logdebugx("%s: received RA from %s (no link-local)", logdebugx("%s: received RA from %s (no link-local)",
ifp->name, ctx->sfrom); ifp->name, sfrom);
#endif #endif
return; return;
} }
if (ipv6_iffindaddr(ifp, &ctx->from.sin6_addr, IN6_IFF_TENTATIVE)) { if (ipv6_iffindaddr(ifp, &from->sin6_addr, IN6_IFF_TENTATIVE)) {
logdebugx("%s: ignoring RA from ourself %s", logdebugx("%s: ignoring RA from ourself %s",
ifp->name, ctx->sfrom); ifp->name, sfrom);
return; return;
} }
TAILQ_FOREACH(rap, ctx->ra_routers, next) { TAILQ_FOREACH(rap, ctx->ra_routers, next) {
if (ifp == rap->iface && if (ifp == rap->iface &&
IN6_ARE_ADDR_EQUAL(&rap->from, &ctx->from.sin6_addr)) IN6_ARE_ADDR_EQUAL(&rap->from, &from->sin6_addr))
break; break;
} }
@ -968,8 +965,8 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
return; return;
} }
rap->iface = ifp; rap->iface = ifp;
rap->from = ctx->from.sin6_addr; rap->from = from->sin6_addr;
strlcpy(rap->sfrom, ctx->sfrom, sizeof(rap->sfrom)); strlcpy(rap->sfrom, sfrom, sizeof(rap->sfrom));
TAILQ_INIT(&rap->addrs); TAILQ_INIT(&rap->addrs);
new_rap = true; new_rap = true;
} else } else
@ -991,8 +988,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
* in accordance with the own prefix times which would result in too * in accordance with the own prefix times which would result in too
* much needless log spam. */ * much needless log spam. */
logfunc = new_rap ? loginfox : logdebugx, logfunc = new_rap ? loginfox : logdebugx,
logfunc("%s: Router Advertisement from %s", logfunc("%s: Router Advertisement from %s", ifp->name, rap->sfrom);
ifp->name, ctx->sfrom);
clock_gettime(CLOCK_MONOTONIC, &rap->acquired); clock_gettime(CLOCK_MONOTONIC, &rap->acquired);
rap->flags = nd_ra->nd_ra_flags_reserved; rap->flags = nd_ra->nd_ra_flags_reserved;
@ -1053,10 +1049,10 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
} }
if (dho != NULL) if (dho != NULL)
logwarnx("%s: reject RA (option %s) from %s", logwarnx("%s: reject RA (option %s) from %s",
ifp->name, dho->var, ctx->sfrom); ifp->name, dho->var, rap->sfrom);
else else
logwarnx("%s: reject RA (option %d) from %s", logwarnx("%s: reject RA (option %d) from %s",
ifp->name, ndo.nd_opt_type, ctx->sfrom); ifp->name, ndo.nd_opt_type, rap->sfrom);
if (new_rap) if (new_rap)
ipv6nd_removefreedrop_ra(rap, 0, 0); ipv6nd_removefreedrop_ra(rap, 0, 0);
else else
@ -1196,7 +1192,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *ctx, struct interface *ifp,
dho->option)) dho->option))
{ {
logwarnx("%s: reject RA (no option %s) from %s", logwarnx("%s: reject RA (no option %s) from %s",
ifp->name, dho->var, ctx->sfrom); ifp->name, dho->var, rap->sfrom);
if (new_rap) if (new_rap)
ipv6nd_removefreedrop_ra(rap, 0, 0); ipv6nd_removefreedrop_ra(rap, 0, 0);
else else
@ -1584,8 +1580,8 @@ ipv6nd_drop(struct interface *ifp)
} }
static void static void
ipv6nd_handlena(struct dhcpcd_ctx *ctx, struct interface *ifp, ipv6nd_handlena(struct dhcpcd_ctx *ctx, const char *sfrom,
struct icmp6_hdr *icp, size_t len, int hoplimit) struct interface *ifp, struct icmp6_hdr *icp, size_t len, int hoplimit)
{ {
struct nd_neighbor_advert *nd_na; struct nd_neighbor_advert *nd_na;
struct in6_addr nd_na_target; struct in6_addr nd_na_target;
@ -1596,22 +1592,20 @@ ipv6nd_handlena(struct dhcpcd_ctx *ctx, struct interface *ifp,
if (ifp == NULL) { if (ifp == NULL) {
#ifdef DEBUG_NS #ifdef DEBUG_NS
logdebugx("NA for unexpected interface from %s", logdebugx("NA for unexpected interface from %s", sfrom);
ctx->sfrom);
#endif #endif
return; return;
} }
if ((size_t)len < sizeof(struct nd_neighbor_advert)) { if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
logerrx("%s: IPv6 NA too short from %s", logerrx("%s: IPv6 NA too short from %s", ifp->name, sfrom);
ifp->name, ctx->sfrom);
return; return;
} }
/* RFC 4861 7.1.2 */ /* RFC 4861 7.1.2 */
if (hoplimit != 255) { if (hoplimit != 255) {
logerrx("invalid hoplimit(%d) in NA from %s", logerrx("invalid hoplimit(%d) in NA from %s",
hoplimit, ctx->sfrom); hoplimit, sfrom);
return; return;
} }
@ -1625,7 +1619,7 @@ ipv6nd_handlena(struct dhcpcd_ctx *ctx, struct interface *ifp,
memcpy(&nd_na_target, &nd_na->nd_na_target, sizeof(nd_na_target)); memcpy(&nd_na_target, &nd_na->nd_na_target, sizeof(nd_na_target));
if (IN6_IS_ADDR_MULTICAST(&nd_na_target)) { if (IN6_IS_ADDR_MULTICAST(&nd_na_target)) {
logerrx("%s: NA multicast address %s (%s)", logerrx("%s: NA multicast address %s (%s)",
ifp->name, taddr, ctx->sfrom); ifp->name, taddr, sfrom);
return; return;
} }
@ -1637,20 +1631,20 @@ ipv6nd_handlena(struct dhcpcd_ctx *ctx, struct interface *ifp,
if (rap == NULL) { if (rap == NULL) {
#ifdef DEBUG_NS #ifdef DEBUG_NS
logdebugx("%s: unexpected NA from %s for %s", logdebugx("%s: unexpected NA from %s for %s",
ifp->name, ctx->sfrom, taddr); ifp->name, sfrom, taddr);
#endif #endif
return; return;
} }
#ifdef DEBUG_NS #ifdef DEBUG_NS
logdebugx("%s: %sNA for %s from %s", logdebugx("%s: %sNA for %s from %s",
ifp->name, is_solicited ? "solicited " : "", taddr, ctx->sfrom); ifp->name, is_solicited ? "solicited " : "", taddr, sfrom);
#endif #endif
/* Node is no longer a router, so remove it from consideration */ /* Node is no longer a router, so remove it from consideration */
if (!is_router && !rap->expired) { if (!is_router && !rap->expired) {
loginfox("%s: %s not a router (%s)", loginfox("%s: %s not a router (%s)",
ifp->name, taddr, ctx->sfrom); ifp->name, taddr, sfrom);
rap->expired = 1; rap->expired = 1;
rt_build(ifp->ctx, AF_INET6); rt_build(ifp->ctx, AF_INET6);
script_runreason(ifp, "ROUTERADVERT"); script_runreason(ifp, "ROUTERADVERT");
@ -1665,81 +1659,63 @@ static void
ipv6nd_handledata(void *arg) ipv6nd_handledata(void *arg)
{ {
struct dhcpcd_ctx *ctx; struct dhcpcd_ctx *ctx;
struct sockaddr_in6 from;
unsigned char buf[64 * 1024]; /* Maximum ICMPv6 size */
struct iovec iov = {
.iov_base = buf,
.iov_len = sizeof(buf),
};
unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))] = { 0 };
struct msghdr msg = {
.msg_name = &from, .msg_namelen = sizeof(from),
.msg_iov = &iov, .msg_iovlen = 1,
.msg_control = ctl, .msg_controllen = sizeof(ctl),
};
ssize_t len; ssize_t len;
struct cmsghdr *cm; char sfrom[INET6_ADDRSTRLEN];
int hoplimit; int hoplimit = 0;
struct in6_pktinfo pkt;
struct icmp6_hdr *icp; struct icmp6_hdr *icp;
struct interface *ifp; struct interface *ifp;
ctx = arg; ctx = arg;
ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + len = recvmsg(ctx->nd_fd, &msg, 0);
CMSG_SPACE(sizeof(int));
len = recvmsg_realloc(ctx->nd_fd, &ctx->rcvhdr, 0);
if (len == -1) { if (len == -1) {
logerr(__func__); logerr(__func__);
return; return;
} }
ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr, inet_ntop(AF_INET6, &from.sin6_addr, sfrom, sizeof(sfrom));
ctx->ntopbuf, INET6_ADDRSTRLEN);
if ((size_t)len < sizeof(struct icmp6_hdr)) { if ((size_t)len < sizeof(struct icmp6_hdr)) {
logerrx("IPv6 ICMP packet too short from %s", ctx->sfrom); logerrx("IPv6 ICMP packet too short from %s", sfrom);
return; return;
} }
pkt.ipi6_ifindex = 0; ifp = if_findifpfromcmsg(ctx, &msg, &hoplimit);
hoplimit = 0; if (ifp == NULL) {
for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr); logerr(__func__);
cm;
cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm))
{
if (cm->cmsg_level != IPPROTO_IPV6)
continue;
switch(cm->cmsg_type) {
case IPV6_PKTINFO:
if (cm->cmsg_len == CMSG_LEN(sizeof(pkt)))
memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt));
break;
case IPV6_HOPLIMIT:
if (cm->cmsg_len == CMSG_LEN(sizeof(int)))
memcpy(&hoplimit, CMSG_DATA(cm), sizeof(int));
break;
}
}
if (pkt.ipi6_ifindex == 0) {
logerrx("IPv6 RA/NA did not contain index from %s", ctx->sfrom);
return; return;
} }
/* Find the receiving interface */
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
if (ifp->index == (unsigned int)pkt.ipi6_ifindex)
break;
}
/* Don't do anything if the user hasn't configured it. */ /* Don't do anything if the user hasn't configured it. */
if (ifp != NULL && if (ifp->active != IF_ACTIVE_USER ||
(ifp->active != IF_ACTIVE_USER || !(ifp->options->options & DHCPCD_IPV6))
!(ifp->options->options & DHCPCD_IPV6)))
return; return;
icp = (struct icmp6_hdr *)ctx->rcvhdr.msg_iov[0].iov_base; icp = (struct icmp6_hdr *)buf;
if (icp->icmp6_code == 0) { if (icp->icmp6_code == 0) {
switch(icp->icmp6_type) { switch(icp->icmp6_type) {
case ND_NEIGHBOR_ADVERT: case ND_NEIGHBOR_ADVERT:
ipv6nd_handlena(ctx, ifp, icp, (size_t)len, ipv6nd_handlena(ctx, sfrom,
hoplimit); ifp, icp, (size_t)len, hoplimit);
return; return;
case ND_ROUTER_ADVERT: case ND_ROUTER_ADVERT:
ipv6nd_handlera(ctx, ifp, icp, (size_t)len, ipv6nd_handlera(ctx, &from, sfrom,
hoplimit); ifp, icp, (size_t)len, hoplimit);
return; return;
} }
} }
logerrx("invalid IPv6 type %d or code %d from %s", logerrx("invalid IPv6 type %d or code %d from %s",
icp->icmp6_type, icp->icmp6_code, ctx->sfrom); icp->icmp6_type, icp->icmp6_code, sfrom);
} }
static void static void

View File

@ -272,7 +272,7 @@ rt_kfree(struct rt *rt)
/* If something other than dhcpcd removes a route, /* If something other than dhcpcd removes a route,
* we need to remove it from our internal table. */ * we need to remove it from our internal table. */
void void
rt_recvrt(int cmd, const struct rt *rt) rt_recvrt(int cmd, const struct rt *rt, pid_t pid)
{ {
struct dhcpcd_ctx *ctx; struct dhcpcd_ctx *ctx;
struct rt *f; struct rt *f;
@ -288,8 +288,11 @@ rt_recvrt(int cmd, const struct rt *rt)
rt_free(f); rt_free(f);
} }
if ((f = rt_find(&ctx->routes, rt)) != NULL) { if ((f = rt_find(&ctx->routes, rt)) != NULL) {
char buf[32];
TAILQ_REMOVE(&ctx->routes, f, rt_next); TAILQ_REMOVE(&ctx->routes, f, rt_next);
rt_desc("deleted", f); snprintf(buf, sizeof(buf), "pid %d deleted", pid);
rt_desc(buf, f);
rt_free(f); rt_free(f);
} }
break; break;
@ -303,7 +306,7 @@ rt_recvrt(int cmd, const struct rt *rt)
break; break;
} }
#if defined(INET) && defined(HAVE_ROUTE_METRIC) #if defined(IPV4LL) && defined(HAVE_ROUTE_METRIC)
if (rt->rt_dest.sa_family == AF_INET) if (rt->rt_dest.sa_family == AF_INET)
ipv4ll_recvrt(cmd, rt); ipv4ll_recvrt(cmd, rt);
#endif #endif

View File

@ -92,7 +92,7 @@ void rt_headfreeif(struct rt_head *);
struct rt * rt_new0(struct dhcpcd_ctx *); struct rt * rt_new0(struct dhcpcd_ctx *);
void rt_setif(struct rt *, struct interface *); void rt_setif(struct rt *, struct interface *);
struct rt * rt_new(struct interface *); struct rt * rt_new(struct interface *);
void rt_recvrt(int, const struct rt *); void rt_recvrt(int, const struct rt *, pid_t);
void rt_build(struct dhcpcd_ctx *, int); void rt_build(struct dhcpcd_ctx *, int);
#endif #endif

View File

@ -704,9 +704,7 @@ script_runreason(const struct interface *ifp, const char *reason)
int status = 0; int status = 0;
struct fd_list *fd; struct fd_list *fd;
if (ifp->options->script && if (ifp->options->script == NULL &&
(ifp->options->script[0] == '\0' ||
strcmp(ifp->options->script, "/dev/null") == 0) &&
TAILQ_FIRST(&ifp->ctx->control_fds) == NULL) TAILQ_FIRST(&ifp->ctx->control_fds) == NULL)
return 0; return 0;
@ -717,12 +715,10 @@ script_runreason(const struct interface *ifp, const char *reason)
return -1; return -1;
} }
if (ifp->options->script && if (ifp->options->script == NULL)
(ifp->options->script[0] == '\0' ||
strcmp(ifp->options->script, "/dev/null") == 0))
goto send_listeners; goto send_listeners;
argv[0] = ifp->options->script ? ifp->options->script : UNCONST(SCRIPT); argv[0] = ifp->options->script;
argv[1] = NULL; argv[1] = NULL;
logdebugx("%s: executing `%s' %s", ifp->name, argv[0], reason); logdebugx("%s: executing `%s' %s", ifp->name, argv[0], reason);