Change the readrawsocket API a little so that we know when EOF is reached.

This allows us to remove the non blocking option from our sockets due to the way BPF works.
This commit is contained in:
Roy Marples 2014-05-02 23:54:29 +00:00
parent 94cb985a8e
commit 68e672702b
9 changed files with 204 additions and 221 deletions

12
arp.c
View File

@ -134,14 +134,20 @@ arp_packet(void *arg)
const char *hwaddr;
struct in_addr ina;
char hwbuf[HWADDR_LEN * 3];
int flags;
state = D_STATE(ifp);
state->fail.s_addr = 0;
for(;;) {
flags = 0;
while (!(flags & RAW_EOF)) {
bytes = if_readrawpacket(ifp, ETHERTYPE_ARP,
arp_buffer, sizeof(arp_buffer), NULL);
if (bytes == 0 || bytes == -1)
arp_buffer, sizeof(arp_buffer), &flags);
if (bytes == 0 || bytes == -1) {
syslog(LOG_ERR, "%s: arp if_readrawpacket: %m",
ifp->name);
dhcp_close(ifp);
return;
}
/* We must have a full ARP header */
if ((size_t)bytes < sizeof(ar))
continue;

55
dhcp.c
View File

@ -2557,55 +2557,58 @@ valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from,
static void
dhcp_handlepacket(void *arg)
{
struct interface *iface = arg;
struct interface *ifp = arg;
struct dhcp_message *dhcp = NULL;
const uint8_t *pp;
size_t bytes;
struct in_addr from;
int i, partialcsum = 0;
const struct dhcp_state *state = D_CSTATE(iface);
int i, flags;
const struct dhcp_state *state = D_CSTATE(ifp);
/* We loop through until our buffer is empty.
* The benefit is that if we get >1 DHCP packet in our buffer and
* the first one fails for any reason, we can use the next. */
for(;;) {
bytes = (size_t)if_readrawpacket(iface, ETHERTYPE_IP,
iface->ctx->packet, udp_dhcp_len, &partialcsum);
if (bytes == 0 || (ssize_t)bytes == -1)
/* Need this API due to BPF */
flags = 0;
while (!(flags & RAW_EOF)) {
bytes = (size_t)if_readrawpacket(ifp, ETHERTYPE_IP,
ifp->ctx->packet, udp_dhcp_len, &flags);
if (bytes == 0 || (ssize_t)bytes == -1) {
syslog(LOG_ERR, "%s: dhcp if_readrawpacket: %m",
ifp->name);
dhcp_close(ifp);
break;
if (valid_udp_packet(iface->ctx->packet, bytes,
&from, partialcsum) == -1)
}
if (valid_udp_packet(ifp->ctx->packet, bytes,
&from, flags & RAW_PARTIALCSUM) == -1)
{
syslog(LOG_ERR, "%s: invalid UDP packet from %s",
iface->name, inet_ntoa(from));
ifp->name, inet_ntoa(from));
continue;
}
i = whitelisted_ip(iface->options, from.s_addr);
i = whitelisted_ip(ifp->options, from.s_addr);
if (i == 0) {
syslog(LOG_WARNING,
"%s: non whitelisted DHCP packet from %s",
iface->name, inet_ntoa(from));
ifp->name, inet_ntoa(from));
continue;
} else if (i != 1 &&
blacklisted_ip(iface->options, from.s_addr) == 1)
blacklisted_ip(ifp->options, from.s_addr) == 1)
{
syslog(LOG_WARNING,
"%s: blacklisted DHCP packet from %s",
iface->name, inet_ntoa(from));
ifp->name, inet_ntoa(from));
continue;
}
if (iface->flags & IFF_POINTOPOINT &&
if (ifp->flags & IFF_POINTOPOINT &&
state->dst.s_addr != from.s_addr)
{
syslog(LOG_WARNING,
"%s: server %s is not destination",
iface->name, inet_ntoa(from));
ifp->name, inet_ntoa(from));
}
bytes = get_udp_data(&pp, iface->ctx->packet);
bytes = get_udp_data(&pp, ifp->ctx->packet);
if (bytes > sizeof(*dhcp)) {
syslog(LOG_ERR,
"%s: packet greater than DHCP size from %s",
iface->name, inet_ntoa(from));
ifp->name, inet_ntoa(from));
continue;
}
if (dhcp == NULL) {
@ -2618,22 +2621,22 @@ dhcp_handlepacket(void *arg)
memcpy(dhcp, pp, bytes);
if (dhcp->cookie != htonl(MAGIC_COOKIE)) {
syslog(LOG_DEBUG, "%s: bogus cookie from %s",
iface->name, inet_ntoa(from));
ifp->name, inet_ntoa(from));
continue;
}
/* Ensure packet is for us */
if (iface->hwlen <= sizeof(dhcp->chaddr) &&
memcmp(dhcp->chaddr, iface->hwaddr, iface->hwlen))
if (ifp->hwlen <= sizeof(dhcp->chaddr) &&
memcmp(dhcp->chaddr, ifp->hwaddr, ifp->hwlen))
{
char buf[sizeof(dhcp->chaddr) * 3];
syslog(LOG_DEBUG, "%s: xid 0x%x is not for hwaddr %s",
iface->name, ntohl(dhcp->xid),
ifp->name, ntohl(dhcp->xid),
hwaddr_ntoa(dhcp->chaddr, sizeof(dhcp->chaddr),
buf, sizeof(buf)));
continue;
}
dhcp_handledhcp(iface, &dhcp, &from);
dhcp_handledhcp(ifp, &dhcp, &from);
if (state->raw_fd == -1)
break;
}

View File

@ -2036,8 +2036,11 @@ dhcp6_handledata(void *arg)
ctx = dhcpcd_ctx->ipv6;
ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
bytes = recvmsg(ctx->dhcp_fd, &ctx->rcvhdr, 0);
if (bytes == -1) {
if (bytes == -1 || bytes == 0) {
syslog(LOG_ERR, "recvmsg: %m");
close(ctx->dhcp_fd);
eloop_event_delete(dhcpcd_ctx->eloop, ctx->dhcp_fd);
ctx->dhcp_fd = -1;
return;
}
len = (size_t)bytes;

View File

@ -641,8 +641,12 @@ handle_link(void *arg)
struct dhcpcd_ctx *ctx;
ctx = arg;
if (if_managelink(ctx) == -1 && errno != ENXIO && errno != ENODEV)
if (if_managelink(ctx) == -1) {
syslog(LOG_ERR, "if_managelink: %m");
eloop_event_delete(ctx->eloop, ctx->link_fd);
close(ctx->link_fd);
ctx->link_fd = -1;
}
}
static void

View File

@ -386,7 +386,7 @@ eloop_start(struct dhcpcd_ctx *dctx)
n = poll(ctx->fds, ctx->events_len, timeout);
#endif
if (n == -1) {
if (errno == EAGAIN || errno == EINTR)
if (errno == EINTR)
continue;
syslog(LOG_ERR, "poll: %m");
break;
@ -395,7 +395,7 @@ eloop_start(struct dhcpcd_ctx *dctx)
/* Process any triggered events. */
if (n > 0) {
TAILQ_FOREACH(e, &ctx->events, next) {
if (e->pollfd->revents & (POLLIN | POLLHUP)) {
if (e->pollfd->revents & (POLLIN)) {
e->callback(e->arg);
/* We need to break here as the
* callback could destroy the next

292
if-bsd.c
View File

@ -114,7 +114,7 @@ if_openlinksocket(void)
{
#ifdef SOCK_CLOEXEC
return socket(PF_ROUTE, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
return socket(PF_ROUTE, SOCK_RAW | SOCK_CLOEXEC, 0);
#else
int s, flags;
@ -126,12 +126,6 @@ if_openlinksocket(void)
close(s);
return -1;
}
if ((flags = fcntl(s, F_GETFL, 0)) == -1 ||
fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
{
close(s);
return -1;
}
return s;
#endif
}
@ -228,14 +222,14 @@ if_openrawsocket(struct interface *ifp, int protocol)
int flags;
#endif
#ifdef _PATH_BPF
fd = open(_PATH_BPF, O_RDWR | O_CLOEXEC | O_NONBLOCK);
fd = open(_PATH_BPF, O_RDWR | O_CLOEXEC);
#else
char device[32];
int n = 0;
do {
snprintf(device, sizeof(device), "/dev/bpf%d", n++);
fd = open(device, O_RDWR | O_CLOEXEC | O_NONBLOCK);
fd = open(device, O_RDWR | O_CLOEXEC);
} while (fd == -1 && errno == EBUSY);
#endif
@ -289,13 +283,6 @@ if_openrawsocket(struct interface *ifp, int protocol)
if (ioctl(fd, BIOCSETF, &pf) == -1)
goto eexit;
#ifdef __OpenBSD__
/* For some reason OpenBSD fails to open the fd as non blocking */
if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
goto eexit;
#endif
return fd;
eexit:
@ -333,9 +320,9 @@ if_sendrawpacket(const struct interface *ifp, int protocol,
* So we pass the buffer in the API so we can loop on >1 packet. */
ssize_t
if_readrawpacket(struct interface *ifp, int protocol,
void *data, size_t len, int *partialcsum)
void *data, size_t len, int *flags)
{
int fd = -1;
int fd;
struct bpf_hdr packet;
ssize_t bytes;
const unsigned char *payload;
@ -347,16 +334,14 @@ if_readrawpacket(struct interface *ifp, int protocol,
else
fd = state->raw_fd;
if (partialcsum != NULL)
*partialcsum = 0; /* Not supported on BSD */
if (flags != NULL)
*flags = 0; /* Not supported on BSD */
for (;;) {
if (state->buffer_len == 0) {
bytes = read(fd, state->buffer, state->buffer_size);
if (bytes == -1)
return errno == EAGAIN ? 0 : -1;
else if ((size_t)bytes < sizeof(packet))
return -1;
if (bytes == -1 || bytes == 0)
return bytes;
state->buffer_len = (size_t)bytes;
state->buffer_pos = 0;
}
@ -377,8 +362,10 @@ if_readrawpacket(struct interface *ifp, int protocol,
next:
state->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen +
packet.bh_caplen);
if (state->buffer_pos >= state->buffer_len)
if (state->buffer_pos >= state->buffer_len) {
state->buffer_len = state->buffer_pos = 0;
*flags |= RAW_EOF;
}
if (bytes != -1)
return bytes;
}
@ -774,143 +761,136 @@ if_managelink(struct dhcpcd_ctx *ctx)
int ifa_flags;
#endif
for (;;) {
bytes = read(ctx->link_fd, msg, sizeof(msg));
if (bytes == -1) {
if (errno == EAGAIN)
return 0;
if (errno == EINTR)
continue;
return -1;
}
e = msg + bytes;
for (p = msg; p < e; p += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)(void *)p;
// Ignore messages generated by us
if (rtm->rtm_pid == getpid())
break;
switch(rtm->rtm_type) {
bytes = read(ctx->link_fd, msg, sizeof(msg));
if (bytes == -1 || bytes == 0)
return bytes;
e = msg + bytes;
for (p = msg; p < e; p += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)(void *)p;
// Ignore messages generated by us
if (rtm->rtm_pid == getpid())
break;
switch(rtm->rtm_type) {
#ifdef RTM_IFANNOUNCE
case RTM_IFANNOUNCE:
ifan = (struct if_announcemsghdr *)(void *)p;
switch(ifan->ifan_what) {
case IFAN_ARRIVAL:
dhcpcd_handleinterface(ctx, 1,
ifan->ifan_name);
break;
case IFAN_DEPARTURE:
dhcpcd_handleinterface(ctx, -1,
ifan->ifan_name);
break;
}
case RTM_IFANNOUNCE:
ifan = (struct if_announcemsghdr *)(void *)p;
switch(ifan->ifan_what) {
case IFAN_ARRIVAL:
dhcpcd_handleinterface(ctx, 1,
ifan->ifan_name);
break;
#endif
case RTM_IFINFO:
ifm = (struct if_msghdr *)(void *)p;
memset(ifname, 0, sizeof(ifname));
if (!(if_indextoname(ifm->ifm_index, ifname)))
break;
switch (ifm->ifm_data.ifi_link_state) {
case LINK_STATE_DOWN:
len = LINK_DOWN;
break;
case LINK_STATE_UP:
len = LINK_UP;
break;
default:
/* handle_carrier will re-load
* the interface flags and check for
* IFF_RUNNING as some drivers that
* don't handle link state also don't
* set IFF_RUNNING when this routing
* message is generated.
* As such, it is a race ...*/
len = LINK_UNKNOWN;
break;
}
dhcpcd_handlecarrier(ctx, len,
(unsigned int)ifm->ifm_flags, ifname);
break;
case RTM_DELETE:
if (~rtm->rtm_addrs &
(RTA_DST | RTA_GATEWAY | RTA_NETMASK))
break;
cp = (char *)(void *)(rtm + 1);
sa = (struct sockaddr *)(void *)cp;
if (sa->sa_family != AF_INET)
break;
#ifdef INET
get_addrs(rtm->rtm_addrs, cp, rti_info);
memset(&rt, 0, sizeof(rt));
rt.iface = NULL;
COPYOUT(rt.dest, rti_info[RTAX_DST]);
COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
ipv4_routedeleted(ctx, &rt);
#endif
break;
#ifdef RTM_CHGADDR
case RTM_CHGADDR: /* FALLTHROUGH */
#endif
case RTM_DELADDR: /* FALLTHROUGH */
case RTM_NEWADDR:
ifam = (struct ifa_msghdr *)(void *)p;
if (!if_indextoname(ifam->ifam_index, ifname))
break;
cp = (char *)(void *)(ifam + 1);
get_addrs(ifam->ifam_addrs, cp, rti_info);
if (rti_info[RTAX_IFA] == NULL)
break;
switch (rti_info[RTAX_IFA]->sa_family) {
case AF_LINK:
#ifdef RTM_CHGADDR
if (rtm->rtm_type != RTM_CHGADDR)
break;
#else
if (rtm->rtm_type != RTM_NEWADDR)
break;
#endif
memcpy(&sdl, rti_info[RTAX_IFA],
rti_info[RTAX_IFA]->sa_len);
dhcpcd_handlehwaddr(ctx, ifname,
(const unsigned char*)CLLADDR(&sdl),
sdl.sdl_alen);
break;
#ifdef INET
case AF_INET:
case 255: /* FIXME: Why 255? */
COPYOUT(rt.dest, rti_info[RTAX_IFA]);
COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
COPYOUT(rt.gate, rti_info[RTAX_BRD]);
ipv4_handleifa(ctx, rtm->rtm_type,
NULL, ifname,
&rt.dest, &rt.net, &rt.gate);
break;
#endif
#ifdef INET6
case AF_INET6:
sin6 = (struct sockaddr_in6*)(void *)
rti_info[RTAX_IFA];
memcpy(ia6.s6_addr,
sin6->sin6_addr.s6_addr,
sizeof(ia6.s6_addr));
if (rtm->rtm_type == RTM_NEWADDR) {
ifa_flags = if_addrflags6(
ifname,
&ia6);
if (ifa_flags == -1)
break;
} else
ifa_flags = 0;
ipv6_handleifa(ctx, rtm->rtm_type, NULL,
ifname, &ia6, ifa_flags);
break;
#endif
}
case IFAN_DEPARTURE:
dhcpcd_handleinterface(ctx, -1,
ifan->ifan_name);
break;
}
break;
#endif
case RTM_IFINFO:
ifm = (struct if_msghdr *)(void *)p;
memset(ifname, 0, sizeof(ifname));
if (!(if_indextoname(ifm->ifm_index, ifname)))
break;
switch (ifm->ifm_data.ifi_link_state) {
case LINK_STATE_DOWN:
len = LINK_DOWN;
break;
case LINK_STATE_UP:
len = LINK_UP;
break;
default:
/* handle_carrier will re-load
* the interface flags and check for
* IFF_RUNNING as some drivers that
* don't handle link state also don't
* set IFF_RUNNING when this routing
* message is generated.
* As such, it is a race ...*/
len = LINK_UNKNOWN;
break;
}
dhcpcd_handlecarrier(ctx, len,
(unsigned int)ifm->ifm_flags, ifname);
break;
case RTM_DELETE:
if (~rtm->rtm_addrs &
(RTA_DST | RTA_GATEWAY | RTA_NETMASK))
break;
cp = (char *)(void *)(rtm + 1);
sa = (struct sockaddr *)(void *)cp;
if (sa->sa_family != AF_INET)
break;
#ifdef INET
get_addrs(rtm->rtm_addrs, cp, rti_info);
memset(&rt, 0, sizeof(rt));
rt.iface = NULL;
COPYOUT(rt.dest, rti_info[RTAX_DST]);
COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
ipv4_routedeleted(ctx, &rt);
#endif
break;
#ifdef RTM_CHGADDR
case RTM_CHGADDR: /* FALLTHROUGH */
#endif
case RTM_DELADDR: /* FALLTHROUGH */
case RTM_NEWADDR:
ifam = (struct ifa_msghdr *)(void *)p;
if (!if_indextoname(ifam->ifam_index, ifname))
break;
cp = (char *)(void *)(ifam + 1);
get_addrs(ifam->ifam_addrs, cp, rti_info);
if (rti_info[RTAX_IFA] == NULL)
break;
switch (rti_info[RTAX_IFA]->sa_family) {
case AF_LINK:
#ifdef RTM_CHGADDR
if (rtm->rtm_type != RTM_CHGADDR)
break;
#else
if (rtm->rtm_type != RTM_NEWADDR)
break;
#endif
memcpy(&sdl, rti_info[RTAX_IFA],
rti_info[RTAX_IFA]->sa_len);
dhcpcd_handlehwaddr(ctx, ifname,
(const unsigned char*)CLLADDR(&sdl),
sdl.sdl_alen);
break;
#ifdef INET
case AF_INET:
case 255: /* FIXME: Why 255? */
COPYOUT(rt.dest, rti_info[RTAX_IFA]);
COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
COPYOUT(rt.gate, rti_info[RTAX_BRD]);
ipv4_handleifa(ctx, rtm->rtm_type,
NULL, ifname,
&rt.dest, &rt.net, &rt.gate);
break;
#endif
#ifdef INET6
case AF_INET6:
sin6 = (struct sockaddr_in6*)(void *)
rti_info[RTAX_IFA];
memcpy(ia6.s6_addr,
sin6->sin6_addr.s6_addr,
sizeof(ia6.s6_addr));
if (rtm->rtm_type == RTM_NEWADDR) {
ifa_flags = if_addrflags6(ifname, &ia6);
if (ifa_flags == -1)
break;
} else
ifa_flags = 0;
ipv6_handleifa(ctx, rtm->rtm_type, NULL,
ifname, &ia6, ifa_flags);
break;
#endif
}
break;
}
}
return 0;
}
#ifndef SYS_NMLN /* OSX */

View File

@ -272,15 +272,9 @@ get_netlink(struct dhcpcd_ctx *ctx, int fd, int flags,
for (;;) {
bytes = recv(fd, NULL, 0,
flags | MSG_PEEK | MSG_DONTWAIT | MSG_TRUNC);
if (bytes == -1) {
if (errno == EAGAIN) {
r = 0;
goto eexit;
}
if (errno == EINTR)
continue;
if (bytes == -1 || bytes == 0)
goto eexit;
} else if ((size_t)bytes == buflen) {
if ((size_t)bytes == buflen) {
/* Support kernels older than 2.6.22 */
if (bytes == 0)
bytes = 512;
@ -297,15 +291,8 @@ get_netlink(struct dhcpcd_ctx *ctx, int fd, int flags,
}
bytes = recvfrom(fd, buf, buflen, flags,
(struct sockaddr *)&nladdr, &nladdr_len);
if (bytes == -1) {
if (errno == EAGAIN) {
r = 0;
goto eexit;
}
if (errno == EINTR)
continue;
if (bytes == -1 || bytes == 0)
goto eexit;
}
/* Check sender */
if (nladdr_len != sizeof(nladdr)) {
@ -752,7 +739,7 @@ if_openrawsocket(struct interface *ifp, int protocol)
#endif
#ifdef SOCK_CLOEXEC
if ((s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
if ((s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC,
htons(protocol))) == -1)
return -1;
#else
@ -766,12 +753,6 @@ if_openrawsocket(struct interface *ifp, int protocol)
close(s);
return -1;
}
if ((flags = fcntl(s, F_GETFL, 0)) == -1 ||
fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
{
close(s);
return -1;
}
#endif
/* Install the DHCP filter */
memset(&pf, 0, sizeof(pf));
@ -839,7 +820,7 @@ if_sendrawpacket(const struct interface *ifp, int protocol,
ssize_t
if_readrawpacket(struct interface *ifp, int protocol,
void *data, size_t len, int *partialcsum)
void *data, size_t len, int *flags)
{
struct iovec iov = {
.iov_base = data,
@ -871,9 +852,9 @@ if_readrawpacket(struct interface *ifp, int protocol,
fd = state->raw_fd;
bytes = recvmsg(fd, &msg, 0);
if (bytes == -1)
return errno == EAGAIN ? 0 : -1;
if (partialcsum != NULL) {
*partialcsum = 0;
return -1;
if (bytes) {
*flags &= ~RAW_PARTIALCSUM;
#ifdef PACKET_AUXDATA
for (cmsg = CMSG_FIRSTHDR(&msg);
cmsg;
@ -882,8 +863,8 @@ if_readrawpacket(struct interface *ifp, int protocol,
if (cmsg->cmsg_level == SOL_PACKET &&
cmsg->cmsg_type == PACKET_AUXDATA) {
aux = (void *)CMSG_DATA(cmsg);
*partialcsum = aux->tp_status &
TP_STATUS_CSUMNOTREADY;
if (aux->tp_status & TP_STATUS_CSUMNOTREADY)
*flags |= RAW_PARTIALCSUM;
}
}
#endif

3
if.h
View File

@ -80,6 +80,9 @@
# define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == LINKLOCAL_ADDR)
#endif
#define RAW_EOF 1 << 0
#define RAW_PARTIALCSUM 2 << 0
struct if_head *if_discover(struct dhcpcd_ctx *, int, char * const *);
struct interface *if_find(struct dhcpcd_ctx *, const char *);
void if_free(struct interface *);

View File

@ -1166,10 +1166,10 @@ ipv6nd_proberouter(void *arg)
pi.ipi6_ifindex = rap->iface->index;
memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
#ifdef DEBUG_NS
//#ifdef DEBUG_NS
syslog(LOG_INFO, "%s: sending IPv6 NS for %s",
rap->iface->name, rap->sfrom);
#endif
//#endif
if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) {
syslog(LOG_ERR, "%s: %s: sendmsg: %m",
rap->iface->name, __func__);
@ -1432,8 +1432,11 @@ ipv6nd_handledata(void *arg)
ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
CMSG_SPACE(sizeof(int));
len = recvmsg(ctx->nd_fd, &ctx->rcvhdr, 0);
if (len == -1) {
if (len == -1 || len == 0) {
syslog(LOG_ERR, "recvmsg: %m");
eloop_event_delete(dhcpcd_ctx->eloop, ctx->nd_fd);
close(ctx->nd_fd);
ctx->nd_fd = -1;
return;
}
ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr,