Import dhcpcd-8.1.1 with the following changes:
* IPv6: Fix a potential crash when learning interface addresses. * DHCP: Fix fallout from dhcpcd-8.1.0 for checksum calculation.
This commit is contained in:
parent
3191a42627
commit
1cc3fcda30
|
@ -31,6 +31,10 @@
|
|||
#define PACKAGE "dhcpcd"
|
||||
#define VERSION "8.1.0"
|
||||
|
||||
#ifndef DHCPCD_USER
|
||||
# define DHCPCD_USER "_dhcpcd"
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG
|
||||
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"
|
||||
#endif
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
#include "ipv4.h"
|
||||
#include "ipv4ll.h"
|
||||
#include "logerr.h"
|
||||
#include "privsep.h"
|
||||
#include "sa.h"
|
||||
#include "script.h"
|
||||
|
||||
|
@ -164,8 +165,6 @@ dhcp_printoptions(const struct dhcpcd_ctx *ctx,
|
|||
}
|
||||
}
|
||||
|
||||
#define get_option_raw(ctx, bootp, bootp_len, opt) \
|
||||
get_option((ctx), (bootp), (bootp_len), NULL)
|
||||
static const uint8_t *
|
||||
get_option(struct dhcpcd_ctx *ctx,
|
||||
const struct bootp *bootp, size_t bootp_len,
|
||||
|
@ -1650,39 +1649,43 @@ static ssize_t
|
|||
dhcp_sendudp(struct interface *ifp, struct in_addr *to, void *data, size_t len)
|
||||
{
|
||||
int s;
|
||||
struct msghdr msg;
|
||||
struct sockaddr_in sin;
|
||||
struct iovec iov[1];
|
||||
struct sockaddr_in sin = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr = *to,
|
||||
.sin_port = htons(BOOTPS),
|
||||
#ifdef HAVE_SA_LEN
|
||||
.sin_len = sizeof(sin),
|
||||
#endif
|
||||
};
|
||||
struct iovec iov[] = {
|
||||
{ .iov_base = data, .iov_len = len }
|
||||
};
|
||||
struct msghdr msg = {
|
||||
.msg_name = (void *)&sin,
|
||||
.msg_namelen = sizeof(sin),
|
||||
.msg_iov = iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
struct dhcp_state *state = D_STATE(ifp);
|
||||
ssize_t r;
|
||||
|
||||
iov[0].iov_base = data;
|
||||
iov[0].iov_len = len;
|
||||
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr = *to;
|
||||
sin.sin_port = htons(BOOTPS);
|
||||
#ifdef HAVE_SA_LEN
|
||||
sin.sin_len = sizeof(sin);
|
||||
#ifdef PRIVSEP
|
||||
if (ifp->ctx->options & DHCPCD_PRIVSEP)
|
||||
return privsep_sendmsg(ifp->ctx, PS_BOOTP, &msg);
|
||||
else
|
||||
#endif
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_name = (void *)&sin;
|
||||
msg.msg_namelen = sizeof(sin);
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
s = state->udp_fd;
|
||||
if (s == -1) {
|
||||
s = dhcp_openudp(ifp);
|
||||
if (s == -1)
|
||||
return -1;
|
||||
{
|
||||
s = state->udp_fd;
|
||||
if (s == -1) {
|
||||
s = dhcp_openudp(ifp);
|
||||
if (s == -1)
|
||||
return -1;
|
||||
}
|
||||
r = sendmsg(s, &msg, 0);
|
||||
if (state->udp_fd == -1)
|
||||
close(s);
|
||||
return r;
|
||||
}
|
||||
r = sendmsg(s, &msg, 0);
|
||||
if (state->udp_fd == -1)
|
||||
close(s);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -3275,26 +3278,35 @@ is_packet_udp_bootp(void *packet, size_t plen)
|
|||
{
|
||||
struct ip *ip = packet;
|
||||
size_t ip_hlen;
|
||||
struct udphdr *udp;
|
||||
struct udphdr udp;
|
||||
|
||||
if (sizeof(*ip) > plen)
|
||||
if (plen < sizeof(*ip))
|
||||
return false;
|
||||
|
||||
if (ip->ip_v != IPVERSION || ip->ip_p != IPPROTO_UDP)
|
||||
return false;
|
||||
|
||||
/* Sanity. */
|
||||
if (ntohs(ip->ip_len) != plen)
|
||||
if (ntohs(ip->ip_len) > plen)
|
||||
return false;
|
||||
|
||||
ip_hlen = (size_t)ip->ip_hl * 4;
|
||||
if (ip_hlen < sizeof(*ip))
|
||||
return false;
|
||||
|
||||
/* Check we have a UDP header and BOOTP. */
|
||||
if (ip_hlen + sizeof(*udp) + offsetof(struct bootp, vend) > plen)
|
||||
if (ip_hlen + sizeof(udp) + offsetof(struct bootp, vend) > plen)
|
||||
return false;
|
||||
|
||||
/* Sanity. */
|
||||
memcpy(&udp, (char *)ip + ip_hlen, sizeof(udp));
|
||||
if (ntohs(udp.uh_ulen) < sizeof(udp))
|
||||
return false;
|
||||
if (ip_hlen + ntohs(udp.uh_ulen) > plen)
|
||||
return false;
|
||||
|
||||
/* Check it's to and from the right ports. */
|
||||
udp = (struct udphdr *)(void *)((char *)ip + ip_hlen);
|
||||
if (udp->uh_dport != htons(BOOTPC) || udp->uh_sport != htons(BOOTPS))
|
||||
if (udp.uh_dport != htons(BOOTPC) || udp.uh_sport != htons(BOOTPS))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -3306,14 +3318,17 @@ checksums_valid(void *packet,
|
|||
struct in_addr *from, unsigned int flags)
|
||||
{
|
||||
struct ip *ip = packet;
|
||||
struct ip pseudo_ip = {
|
||||
.ip_p = IPPROTO_UDP,
|
||||
.ip_src = ip->ip_src,
|
||||
.ip_dst = ip->ip_dst
|
||||
union pip {
|
||||
struct ip ip;
|
||||
uint16_t w[sizeof(struct ip)];
|
||||
} pip = {
|
||||
.ip.ip_p = IPPROTO_UDP,
|
||||
.ip.ip_src = ip->ip_src,
|
||||
.ip.ip_dst = ip->ip_dst,
|
||||
};
|
||||
size_t ip_hlen;
|
||||
uint16_t udp_len, uh_sum;
|
||||
struct udphdr *udp;
|
||||
struct udphdr udp;
|
||||
char *udpp, *uh_sump;
|
||||
uint32_t csum;
|
||||
|
||||
if (from != NULL)
|
||||
|
@ -3324,22 +3339,32 @@ checksums_valid(void *packet,
|
|||
return false;
|
||||
|
||||
if (flags & BPF_PARTIALCSUM)
|
||||
return 0;
|
||||
return true;
|
||||
|
||||
udp = (struct udphdr *)(void *)((char *)ip + ip_hlen);
|
||||
if (udp->uh_sum == 0)
|
||||
return 0;
|
||||
udpp = (char *)ip + ip_hlen;
|
||||
memcpy(&udp, udpp, sizeof(udp));
|
||||
if (udp.uh_sum == 0)
|
||||
return true;
|
||||
|
||||
/* UDP checksum is based on a pseudo IP header alongside
|
||||
* the UDP header and payload. */
|
||||
udp_len = ntohs(udp->uh_ulen);
|
||||
uh_sum = udp->uh_sum;
|
||||
udp->uh_sum = 0;
|
||||
pseudo_ip.ip_len = udp->uh_ulen;
|
||||
pip.ip.ip_len = udp.uh_ulen;
|
||||
csum = 0;
|
||||
in_cksum(&pseudo_ip, sizeof(pseudo_ip), &csum);
|
||||
csum = in_cksum(udp, udp_len, &csum);
|
||||
return csum == uh_sum;
|
||||
|
||||
/* Need to zero the UDP sum in the packet for the checksum to work. */
|
||||
uh_sump = udpp + offsetof(struct udphdr, uh_sum);
|
||||
memset(uh_sump, 0, sizeof(udp.uh_sum));
|
||||
|
||||
/* Checksum psuedo header and then UDP + payload. */
|
||||
in_cksum(pip.w, sizeof(pip.w), &csum);
|
||||
csum = in_cksum(udpp, ntohs(udp.uh_ulen), &csum);
|
||||
|
||||
#if 0 /* Not needed, just here for completeness. */
|
||||
/* Put the checksum back. */
|
||||
memcpy(uh_sump, &udp.uh_sum, sizeof(udp.uh_sum));
|
||||
#endif
|
||||
|
||||
return csum == udp.uh_sum;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -3430,6 +3455,40 @@ dhcp_readbpf(void *arg)
|
|||
state->bpf_flags &= ~BPF_READING;
|
||||
}
|
||||
|
||||
void
|
||||
dhcp_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg)
|
||||
{
|
||||
#ifdef IP_PKTINFO
|
||||
struct sockaddr_in *from = (struct sockaddr_in *)msg->msg_name;
|
||||
struct iovec *iov = &msg->msg_iov[0];
|
||||
char sfrom[INET_ADDRSTRLEN];
|
||||
struct interface *ifp;
|
||||
const struct dhcp_state *state;
|
||||
|
||||
inet_ntop(AF_INET, &from->sin_addr, sfrom, sizeof(sfrom));
|
||||
|
||||
ifp = if_findifpfromcmsg(ctx, msg, NULL);
|
||||
if (ifp == NULL) {
|
||||
logerr(__func__);
|
||||
return;
|
||||
}
|
||||
state = D_CSTATE(ifp);
|
||||
if (state == NULL) {
|
||||
logdebugx("%s: received BOOTP for inactive interface",
|
||||
ifp->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->bpf_fd != -1) {
|
||||
/* Avoid a duplicate read if BPF is open for the interface. */
|
||||
return;
|
||||
}
|
||||
|
||||
dhcp_handlebootp(ifp, (struct bootp *)iov->iov_base, iov->iov_len,
|
||||
&from->sin_addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp)
|
||||
{
|
||||
|
@ -3442,7 +3501,6 @@ dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp)
|
|||
};
|
||||
#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),
|
||||
|
@ -3466,31 +3524,8 @@ dhcp_readudp(struct dhcpcd_ctx *ctx, struct interface *ifp)
|
|||
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;
|
||||
}
|
||||
state = D_CSTATE(ifp);
|
||||
if (state == NULL) {
|
||||
logdebugx("%s: received BOOTP for inactive interface",
|
||||
ifp->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (state->bpf_fd != -1) {
|
||||
/* Avoid a duplicate read if BPF is open for the interface. */
|
||||
return;
|
||||
}
|
||||
|
||||
dhcp_handlebootp(ifp, (struct bootp *)(void *)buf, (size_t)bytes,
|
||||
&from.sin_addr);
|
||||
#endif
|
||||
iov.iov_len = (size_t)bytes;
|
||||
dhcp_recvmsg(ctx, &msg);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -3512,6 +3547,18 @@ dhcp_handleifudp(void *arg)
|
|||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
dhcp_open(struct dhcpcd_ctx *ctx)
|
||||
{
|
||||
|
||||
if (ctx->udp_fd != -1 || (ctx->udp_fd = dhcp_openudp(NULL)) == -1)
|
||||
return ctx->udp_fd;
|
||||
|
||||
if (!(ctx->options & DHCPCD_PRIVSEP))
|
||||
eloop_event_add(ctx->eloop, ctx->udp_fd, dhcp_handleudp, ctx);
|
||||
return ctx->udp_fd;
|
||||
}
|
||||
|
||||
static int
|
||||
dhcp_openbpf(struct interface *ifp)
|
||||
{
|
||||
|
@ -3720,16 +3767,13 @@ dhcp_start1(void *arg)
|
|||
* ICMP port unreachable message back to the DHCP server.
|
||||
* Only do this in master mode so we don't swallow messages
|
||||
* for dhcpcd running on another interface. */
|
||||
if (ctx->udp_fd == -1 && ctx->options & DHCPCD_MASTER) {
|
||||
ctx->udp_fd = dhcp_openudp(NULL);
|
||||
if (ctx->udp_fd == -1) {
|
||||
if (!(ctx->options & DHCPCD_PRIVSEP) && ctx->options & DHCPCD_MASTER) {
|
||||
if (dhcp_open(ctx) == -1) {
|
||||
/* Don't log an error if some other process
|
||||
* is handling this. */
|
||||
if (errno != EADDRINUSE)
|
||||
logerr("%s: dhcp_openudp", __func__);
|
||||
} else
|
||||
eloop_event_add(ctx->eloop,
|
||||
ctx->udp_fd, dhcp_handleudp, ctx);
|
||||
logerr("%s: dhcp_open", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
if (dhcp_init(ifp) == -1) {
|
||||
|
|
|
@ -253,6 +253,8 @@ struct dhcp_state {
|
|||
ssize_t print_rfc3361(FILE *, const uint8_t *, size_t);
|
||||
ssize_t print_rfc3442(FILE *, const uint8_t *, size_t);
|
||||
|
||||
int dhcp_open(struct dhcpcd_ctx *);
|
||||
void dhcp_recvmsg(struct dhcpcd_ctx *, struct msghdr *);
|
||||
void dhcp_printoptions(const struct dhcpcd_ctx *,
|
||||
const struct dhcp_opt *, size_t);
|
||||
uint16_t dhcp_get_mtu(const struct interface *);
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "if-options.h"
|
||||
#include "ipv6nd.h"
|
||||
#include "logerr.h"
|
||||
#include "privsep.h"
|
||||
#include "script.h"
|
||||
|
||||
#ifdef HAVE_SYS_BITOPS_H
|
||||
|
@ -1321,21 +1322,28 @@ logsend:
|
|||
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
|
||||
}
|
||||
|
||||
if (ctx->dhcp6_fd != -1)
|
||||
s = ctx->dhcp6_fd;
|
||||
else if (lla != NULL && lla->dhcp6_fd != -1)
|
||||
s = lla->dhcp6_fd;
|
||||
else {
|
||||
logerrx("%s: no socket to send from", ifp->name);
|
||||
return -1;
|
||||
}
|
||||
#ifdef PRIVSEP
|
||||
if (ifp->ctx->options & DHCPCD_PRIVSEP)
|
||||
privsep_sendmsg(ifp->ctx, PS_DHCP6, &msg);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (ctx->dhcp6_fd != -1)
|
||||
s = ctx->dhcp6_fd;
|
||||
else if (lla != NULL && lla->dhcp6_fd != -1)
|
||||
s = lla->dhcp6_fd;
|
||||
else {
|
||||
logerrx("%s: no socket to send from", ifp->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sendmsg(s, &msg, 0) == -1) {
|
||||
logerr("%s: %s: sendmsg", __func__, ifp->name);
|
||||
/* Allow DHCPv6 to continue .... the errors
|
||||
* would be rate limited by the protocol.
|
||||
* Generally the error is ENOBUFS when struggling to
|
||||
* associate with an access point. */
|
||||
if (sendmsg(s, &msg, 0) == -1) {
|
||||
logerr("%s: %s: sendmsg", __func__, ifp->name);
|
||||
/* Allow DHCPv6 to continue .... the errors
|
||||
* would be rate limited by the protocol.
|
||||
* Generally the error is ENOBUFS when struggling to
|
||||
* associate with an access point. */
|
||||
}
|
||||
}
|
||||
|
||||
state->RTC++;
|
||||
|
@ -3464,24 +3472,11 @@ dhcp6_recvif(struct interface *ifp, const char *sfrom,
|
|||
dhcp6_bind(ifp, op, sfrom);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia)
|
||||
void
|
||||
dhcp6_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, 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;
|
||||
size_t len;
|
||||
ssize_t bytes;
|
||||
struct sockaddr_in6 *from = msg->msg_name;
|
||||
size_t len = msg->msg_iov[0].iov_len;
|
||||
char sfrom[INET6_ADDRSTRLEN];
|
||||
struct interface *ifp;
|
||||
struct dhcp6_message *r;
|
||||
|
@ -3489,14 +3484,7 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia)
|
|||
uint8_t *o;
|
||||
uint16_t ol;
|
||||
|
||||
s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_fd;
|
||||
bytes = recvmsg(s, &msg, 0);
|
||||
if (bytes == -1) {
|
||||
logerr(__func__);
|
||||
return;
|
||||
}
|
||||
len = (size_t)bytes;
|
||||
inet_ntop(AF_INET6, &from.sin6_addr, sfrom, sizeof(sfrom));
|
||||
inet_ntop(AF_INET6, &from->sin6_addr, sfrom, sizeof(sfrom));
|
||||
if (len < sizeof(struct dhcp6_message)) {
|
||||
logerrx("DHCPv6 packet too short from %s", sfrom);
|
||||
return;
|
||||
|
@ -3505,14 +3493,14 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia)
|
|||
if (ia != NULL)
|
||||
ifp = ia->iface;
|
||||
else {
|
||||
ifp = if_findifpfromcmsg(ctx, &msg, NULL);
|
||||
ifp = if_findifpfromcmsg(ctx, msg, NULL);
|
||||
if (ifp == NULL) {
|
||||
logerr(__func__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
r = (struct dhcp6_message *)buf;
|
||||
r = (struct dhcp6_message *)msg->msg_iov[0].iov_base;
|
||||
o = dhcp6_findmoption(r, len, D6_OPTION_CLIENTID, &ol);
|
||||
if (o == NULL || ol != ctx->duid_len ||
|
||||
memcmp(o, ctx->duid, ol) != 0)
|
||||
|
@ -3580,6 +3568,35 @@ dhcp6_recv(struct dhcpcd_ctx *ctx, struct ipv6_addr *ia)
|
|||
dhcp6_recvif(ifp, sfrom, r, len);
|
||||
}
|
||||
|
||||
static void
|
||||
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;
|
||||
ssize_t bytes;
|
||||
|
||||
s = ia != NULL ? ia->dhcp6_fd : ctx->dhcp6_fd;
|
||||
bytes = recvmsg(s, &msg, 0);
|
||||
if (bytes == -1) {
|
||||
logerr(__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
iov.iov_len = (size_t)bytes;
|
||||
dhcp6_recvmsg(ctx, &msg, ia);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp6_recvaddr(void *arg)
|
||||
{
|
||||
|
@ -3677,6 +3694,19 @@ dhcp6_activateinterfaces(struct interface *ifp)
|
|||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
dhcp6_open(struct dhcpcd_ctx *ctx)
|
||||
{
|
||||
|
||||
if (ctx->dhcp6_fd != -1 ||
|
||||
(ctx->dhcp6_fd = dhcp6_listen(ctx, NULL)) == -1)
|
||||
return ctx->dhcp6_fd;
|
||||
|
||||
if (!(ctx->options & DHCPCD_PRIVSEP))
|
||||
eloop_event_add(ctx->eloop, ctx->dhcp6_fd, dhcp6_recvctx, ctx);
|
||||
return ctx->dhcp6_fd;
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp6_start1(void *arg)
|
||||
{
|
||||
|
@ -3687,11 +3717,9 @@ dhcp6_start1(void *arg)
|
|||
size_t i;
|
||||
const struct dhcp_compat *dhc;
|
||||
|
||||
if (ctx->dhcp6_fd == -1 && ctx->options & DHCPCD_MASTER) {
|
||||
ctx->dhcp6_fd = dhcp6_listen(ctx, NULL);
|
||||
if (ctx->dhcp6_fd == -1)
|
||||
if (!(ctx->options & DHCPCD_PRIVSEP) && ctx->options & DHCPCD_MASTER) {
|
||||
if (dhcp6_open(ctx) == -1)
|
||||
return;
|
||||
eloop_event_add(ctx->eloop, ctx->dhcp6_fd, dhcp6_recvctx, ctx);
|
||||
}
|
||||
|
||||
state = D6_STATE(ifp);
|
||||
|
|
|
@ -220,6 +220,8 @@ struct dhcp6_state {
|
|||
(D6_CSTATE((ifp)) && \
|
||||
D6_CSTATE((ifp))->reason && dhcp6_dadcompleted((ifp)))
|
||||
|
||||
int dhcp6_open(struct dhcpcd_ctx *);
|
||||
void dhcp6_recvmsg(struct dhcpcd_ctx *, struct msghdr *, struct ipv6_addr *);
|
||||
void dhcp6_printoptions(const struct dhcpcd_ctx *,
|
||||
const struct dhcp_opt *, size_t);
|
||||
const struct ipv6_addr *dhcp6_iffindaddr(const struct interface *ifp,
|
||||
|
|
|
@ -41,6 +41,7 @@ const char dhcpcd_copyright[] = "Copyright (c) 2006-2019 Roy Marples";
|
|||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <paths.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -66,6 +67,7 @@ const char dhcpcd_copyright[] = "Copyright (c) 2006-2019 Roy Marples";
|
|||
#include "ipv6.h"
|
||||
#include "ipv6nd.h"
|
||||
#include "logerr.h"
|
||||
#include "privsep.h"
|
||||
#include "script.h"
|
||||
|
||||
#ifdef HAVE_UTIL_H
|
||||
|
@ -1597,6 +1599,9 @@ main(int argc, char **argv)
|
|||
#endif
|
||||
#ifdef AUTH
|
||||
" AUTH"
|
||||
#endif
|
||||
#ifdef PRIVSEP
|
||||
" PRIVSEP"
|
||||
#endif
|
||||
"\n");
|
||||
return EXIT_SUCCESS;
|
||||
|
@ -1616,6 +1621,12 @@ main(int argc, char **argv)
|
|||
#endif
|
||||
#ifdef INET
|
||||
ctx.udp_fd = -1;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
ctx.nd_fd = -1;
|
||||
#endif
|
||||
#ifdef DHCP6
|
||||
ctx.dhcp6_fd = -1;
|
||||
#endif
|
||||
rt_init(&ctx);
|
||||
|
||||
|
@ -1984,11 +1995,21 @@ printpidfile:
|
|||
logdebugx(PACKAGE "-" VERSION " starting");
|
||||
ctx.options |= DHCPCD_STARTED;
|
||||
|
||||
#ifdef HAVE_SETPROCTITLE
|
||||
setproctitle("%s%s%s",
|
||||
ctx.options & DHCPCD_MASTER ? "[master]" : argv[optind],
|
||||
ctx.options & DHCPCD_IPV4 ? " [ip4]" : "",
|
||||
ctx.options & DHCPCD_IPV6 ? " [ip6]" : "");
|
||||
|
||||
#ifdef PRIVSEP
|
||||
switch (pid = privsep_start(&ctx)) {
|
||||
case -1:
|
||||
goto exit_failure;
|
||||
case 0:
|
||||
goto run_loop;
|
||||
default:
|
||||
logdebugx("spawned unprivledged process %d", pid);
|
||||
ctx.options |= DHCPCD_PRIVSEP;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (if_opensockets(&ctx) == -1) {
|
||||
|
@ -2103,6 +2124,9 @@ printpidfile:
|
|||
dhcpcd_prestartinterface, ifp);
|
||||
}
|
||||
|
||||
#ifdef PRIVSEP
|
||||
run_loop:
|
||||
#endif
|
||||
i = eloop_start(ctx.eloop, &ctx.sigset);
|
||||
if (i < 0) {
|
||||
logerr("%s: eloop_start", __func__);
|
||||
|
@ -2155,6 +2179,9 @@ exit1:
|
|||
loginfox(PACKAGE " exited");
|
||||
logclose();
|
||||
free(ctx.logfile);
|
||||
#ifdef SETPROCTITLE_H
|
||||
setproctitle_free();
|
||||
#endif
|
||||
#ifdef USE_SIGNALS
|
||||
if (ctx.options & DHCPCD_FORKED)
|
||||
_exit(i); /* so atexit won't remove our pidfile */
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "config.h"
|
||||
#ifdef HAVE_SYS_QUEUE_H
|
||||
#include <sys/queue.h>
|
||||
|
@ -177,6 +179,11 @@ struct dhcpcd_ctx {
|
|||
|
||||
char *randomstate; /* original state */
|
||||
|
||||
#ifdef PRIVSEP
|
||||
char *priv_user;
|
||||
int priv_fd;
|
||||
#endif
|
||||
|
||||
#ifdef INET
|
||||
struct dhcp_opt *dhcp_opts;
|
||||
size_t dhcp_opts_len;
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
#define DHCPCD_HOSTNAME (1ULL << 18)
|
||||
#define DHCPCD_CLIENTID (1ULL << 19)
|
||||
#define DHCPCD_LINK (1ULL << 20)
|
||||
// unused (1ULL << 21)
|
||||
#define DHCPCD_PRIVSEP (1ULL << 21)
|
||||
#define DHCPCD_BACKGROUND (1ULL << 22)
|
||||
#define DHCPCD_VENDORRAW (1ULL << 23)
|
||||
#define DHCPCD_NOWAITIP (1ULL << 24) /* To force daemonise */
|
||||
|
|
|
@ -138,10 +138,14 @@ ipv6_init(struct dhcpcd_ctx *ctx)
|
|||
return -1;
|
||||
TAILQ_INIT(ctx->ra_routers);
|
||||
|
||||
#ifdef PRIVSEP
|
||||
#else /* !PRIVSEP */
|
||||
#ifndef __sun
|
||||
ctx->nd_fd = -1;
|
||||
#endif
|
||||
ctx->dhcp6_fd = -1;
|
||||
#endif /* PRIVSEP */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1253,7 +1257,9 @@ out:
|
|||
* or DHCP6 handlers and the existance of any useable
|
||||
* global address on the interface has changed,
|
||||
* call rt_build to add/remove the default route. */
|
||||
if (ifp->active && ifp->options->options & DHCPCD_IPV6 &&
|
||||
if (ifp->active &&
|
||||
((ifp->options != NULL && ifp->options->options & DHCPCD_IPV6) ||
|
||||
(ifp->options == NULL && ctx->options & DHCPCD_IPV6)) &&
|
||||
!(ctx->options & DHCPCD_RTBUILD) &&
|
||||
(ipv6_anyglobal(ifp) != NULL) != anyglobal)
|
||||
rt_build(ctx, AF_INET6);
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "ipv6.h"
|
||||
#include "ipv6nd.h"
|
||||
#include "logerr.h"
|
||||
#include "privsep.h"
|
||||
#include "route.h"
|
||||
#include "script.h"
|
||||
|
||||
|
@ -267,7 +268,7 @@ ipv6nd_open(struct interface *ifp)
|
|||
return s;
|
||||
}
|
||||
#else
|
||||
static int
|
||||
int
|
||||
ipv6nd_open(struct dhcpcd_ctx *ctx)
|
||||
{
|
||||
int s, on;
|
||||
|
@ -288,7 +289,8 @@ ipv6nd_open(struct dhcpcd_ctx *ctx)
|
|||
}
|
||||
|
||||
ctx->nd_fd = s;
|
||||
eloop_event_add(ctx->eloop, s, ipv6nd_handledata, ctx);
|
||||
if (!(ctx->options & DHCPCD_PRIVSEP))
|
||||
eloop_event_add(ctx->eloop, s, ipv6nd_handledata, ctx);
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
@ -366,17 +368,24 @@ ipv6nd_sendrsprobe(void *arg)
|
|||
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
|
||||
|
||||
logdebugx("%s: sending Router Solicitation", ifp->name);
|
||||
#ifdef __sun
|
||||
s = state->nd_fd;
|
||||
#else
|
||||
s = ifp->ctx->nd_fd;
|
||||
#ifdef PRIVSEP
|
||||
if (ifp->ctx->options & DHCPCD_PRIVSEP)
|
||||
privsep_sendmsg(ifp->ctx, PS_ND, &msg);
|
||||
else
|
||||
#endif
|
||||
if (sendmsg(s, &msg, 0) == -1) {
|
||||
logerr(__func__);
|
||||
/* Allow IPv6ND to continue .... at most a few errors
|
||||
* would be logged.
|
||||
* Generally the error is ENOBUFS when struggling to
|
||||
* associate with an access point. */
|
||||
{
|
||||
#ifdef __sun
|
||||
s = state->nd_fd;
|
||||
#else
|
||||
s = ifp->ctx->nd_fd;
|
||||
#endif
|
||||
if (sendmsg(s, &msg, 0) == -1) {
|
||||
logerr(__func__);
|
||||
/* Allow IPv6ND to continue .... at most a few errors
|
||||
* would be logged.
|
||||
* Generally the error is ENOBUFS when struggling to
|
||||
* associate with an access point. */
|
||||
}
|
||||
}
|
||||
|
||||
if (state->rsprobes++ < MAX_RTR_SOLICITATIONS)
|
||||
|
@ -427,13 +436,21 @@ ipv6nd_sendadvertisement(void *arg)
|
|||
cm->cmsg_len = CMSG_LEN(sizeof(pi));
|
||||
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
|
||||
logdebugx("%s: sending NA for %s", ifp->name, ia->saddr);
|
||||
#ifdef __sun
|
||||
s = state->nd_fd;
|
||||
#else
|
||||
s = ctx->nd_fd;
|
||||
|
||||
#ifdef PRIVSEP
|
||||
if (ifp->ctx->options & DHCPCD_PRIVSEP)
|
||||
privsep_sendmsg(ifp->ctx, PS_ND, &msg);
|
||||
else
|
||||
#endif
|
||||
if (sendmsg(s, &msg, 0) == -1)
|
||||
logerr(__func__);
|
||||
{
|
||||
#ifdef __sun
|
||||
s = state->nd_fd;
|
||||
#else
|
||||
s = ctx->nd_fd;
|
||||
#endif
|
||||
if (sendmsg(s, &msg, 0) == -1)
|
||||
logerr(__func__);
|
||||
}
|
||||
|
||||
if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) {
|
||||
eloop_timeout_add_sec(ctx->eloop,
|
||||
|
@ -1718,6 +1735,51 @@ ipv6nd_drop(struct interface *ifp)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ipv6nd_recvmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg)
|
||||
{
|
||||
struct sockaddr_in6 *from = (struct sockaddr_in6 *)msg->msg_name;
|
||||
char sfrom[INET6_ADDRSTRLEN];
|
||||
int hoplimit = 0;
|
||||
struct icmp6_hdr *icp;
|
||||
struct interface *ifp;
|
||||
size_t len = msg->msg_iov[0].iov_len;
|
||||
|
||||
inet_ntop(AF_INET6, &from->sin6_addr, sfrom, sizeof(sfrom));
|
||||
if ((size_t)len < sizeof(struct icmp6_hdr)) {
|
||||
logerrx("IPv6 ICMP packet too short from %s", sfrom);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef __sun
|
||||
if_findifpfromcmsg(ctx, msg, &hoplimit);
|
||||
#else
|
||||
ifp = if_findifpfromcmsg(ctx, msg, &hoplimit);
|
||||
if (ifp == NULL) {
|
||||
logerr(__func__);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Don't do anything if the user hasn't configured it. */
|
||||
if (ifp->active != IF_ACTIVE_USER ||
|
||||
!(ifp->options->options & DHCPCD_IPV6))
|
||||
return;
|
||||
|
||||
icp = (struct icmp6_hdr *)msg->msg_iov[0].iov_base;
|
||||
if (icp->icmp6_code == 0) {
|
||||
switch(icp->icmp6_type) {
|
||||
case ND_ROUTER_ADVERT:
|
||||
ipv6nd_handlera(ctx, from, sfrom,
|
||||
ifp, icp, (size_t)len, hoplimit);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logerrx("invalid IPv6 type %d or code %d from %s",
|
||||
icp->icmp6_type, icp->icmp6_code, sfrom);
|
||||
}
|
||||
|
||||
static void
|
||||
ipv6nd_handledata(void *arg)
|
||||
{
|
||||
|
@ -1736,10 +1798,6 @@ ipv6nd_handledata(void *arg)
|
|||
.msg_control = ctl, .msg_controllen = sizeof(ctl),
|
||||
};
|
||||
ssize_t len;
|
||||
char sfrom[INET6_ADDRSTRLEN];
|
||||
int hoplimit = 0;
|
||||
struct icmp6_hdr *icp;
|
||||
struct interface *ifp;
|
||||
|
||||
#ifdef __sun
|
||||
struct rs_state *state;
|
||||
|
@ -1757,39 +1815,9 @@ ipv6nd_handledata(void *arg)
|
|||
logerr(__func__);
|
||||
return;
|
||||
}
|
||||
inet_ntop(AF_INET6, &from.sin6_addr, sfrom, sizeof(sfrom));
|
||||
if ((size_t)len < sizeof(struct icmp6_hdr)) {
|
||||
logerrx("IPv6 ICMP packet too short from %s", sfrom);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef __sun
|
||||
if_findifpfromcmsg(ctx, &msg, &hoplimit);
|
||||
#else
|
||||
ifp = if_findifpfromcmsg(ctx, &msg, &hoplimit);
|
||||
if (ifp == NULL) {
|
||||
logerr(__func__);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Don't do anything if the user hasn't configured it. */
|
||||
if (ifp->active != IF_ACTIVE_USER ||
|
||||
!(ifp->options->options & DHCPCD_IPV6))
|
||||
return;
|
||||
|
||||
icp = (struct icmp6_hdr *)buf;
|
||||
if (icp->icmp6_code == 0) {
|
||||
switch(icp->icmp6_type) {
|
||||
case ND_ROUTER_ADVERT:
|
||||
ipv6nd_handlera(ctx, &from, sfrom,
|
||||
ifp, icp, (size_t)len, hoplimit);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logerrx("invalid IPv6 type %d or code %d from %s",
|
||||
icp->icmp6_type, icp->icmp6_code, sfrom);
|
||||
iov.iov_len = (size_t)len;
|
||||
ipv6nd_recvmsg(ctx, &msg);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1812,17 +1840,19 @@ ipv6nd_startrs1(void *arg)
|
|||
#endif
|
||||
}
|
||||
|
||||
if (!(ifp->ctx->options & DHCPCD_PRIVSEP)) {
|
||||
#ifdef __sun
|
||||
if (ipv6nd_open(ifp) == -1) {
|
||||
logerr(__func__);
|
||||
return;
|
||||
}
|
||||
if (ipv6nd_open(ifp) == -1) {
|
||||
logerr(__func__);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (ipv6nd_open(ifp->ctx) == -1) {
|
||||
logerr(__func__);
|
||||
return;
|
||||
}
|
||||
if (ipv6nd_open(ifp->ctx) == -1) {
|
||||
logerr(__func__);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Always make a new probe as the underlying hardware
|
||||
* address could have changed. */
|
||||
|
|
|
@ -91,6 +91,8 @@ struct rs_state {
|
|||
#define RETRANS_TIMER 1000 /* milliseconds */
|
||||
#define DELAY_FIRST_PROBE_TIME 5 /* seconds */
|
||||
|
||||
int ipv6nd_open(struct dhcpcd_ctx *);
|
||||
void ipv6nd_recvmsg(struct dhcpcd_ctx *, struct msghdr *);
|
||||
void ipv6nd_printoptions(const struct dhcpcd_ctx *,
|
||||
const struct dhcp_opt *, size_t);
|
||||
void ipv6nd_startrs(struct interface *);
|
||||
|
|
Loading…
Reference in New Issue