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:
parent
a5e54c894f
commit
dbd4cee32e
|
@ -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
|
||||||
|
|
|
@ -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 *);
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue