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:
roy 2019-10-16 14:50:27 +00:00
parent 3191a42627
commit 1cc3fcda30
11 changed files with 348 additions and 196 deletions

View File

@ -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

View File

@ -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,29 +1649,32 @@ 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);
@ -1684,6 +1686,7 @@ dhcp_sendudp(struct interface *ifp, struct in_addr *to, void *data, size_t len)
close(s);
return r;
}
}
static void
send_message(struct interface *ifp, uint8_t type,
@ -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) {

View File

@ -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 *);

View File

@ -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,6 +1322,12 @@ logsend:
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
}
#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)
@ -1337,6 +1344,7 @@ logsend:
* Generally the error is ENOBUFS when struggling to
* associate with an access point. */
}
}
state->RTC++;
if (callback) {
@ -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);

View File

@ -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,

View File

@ -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 */

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -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,6 +289,7 @@ ipv6nd_open(struct dhcpcd_ctx *ctx)
}
ctx->nd_fd = s;
if (!(ctx->options & DHCPCD_PRIVSEP))
eloop_event_add(ctx->eloop, s, ipv6nd_handledata, ctx);
return s;
}
@ -366,6 +368,12 @@ ipv6nd_sendrsprobe(void *arg)
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
logdebugx("%s: sending Router Solicitation", ifp->name);
#ifdef PRIVSEP
if (ifp->ctx->options & DHCPCD_PRIVSEP)
privsep_sendmsg(ifp->ctx, PS_ND, &msg);
else
#endif
{
#ifdef __sun
s = state->nd_fd;
#else
@ -378,6 +386,7 @@ ipv6nd_sendrsprobe(void *arg)
* Generally the error is ENOBUFS when struggling to
* associate with an access point. */
}
}
if (state->rsprobes++ < MAX_RTR_SOLICITATIONS)
eloop_timeout_add_sec(ifp->ctx->eloop,
@ -427,6 +436,13 @@ 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 PRIVSEP
if (ifp->ctx->options & DHCPCD_PRIVSEP)
privsep_sendmsg(ifp->ctx, PS_ND, &msg);
else
#endif
{
#ifdef __sun
s = state->nd_fd;
#else
@ -434,6 +450,7 @@ ipv6nd_sendadvertisement(void *arg)
#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,6 +1840,7 @@ ipv6nd_startrs1(void *arg)
#endif
}
if (!(ifp->ctx->options & DHCPCD_PRIVSEP)) {
#ifdef __sun
if (ipv6nd_open(ifp) == -1) {
logerr(__func__);
@ -1823,6 +1852,7 @@ ipv6nd_startrs1(void *arg)
return;
}
#endif
}
/* Always make a new probe as the underlying hardware
* address could have changed. */

View File

@ -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 *);