diff options
Diffstat (limited to 'usr.sbin/bind/lib/isc/unix/socket.c')
| -rw-r--r-- | usr.sbin/bind/lib/isc/unix/socket.c | 371 |
1 files changed, 245 insertions, 126 deletions
diff --git a/usr.sbin/bind/lib/isc/unix/socket.c b/usr.sbin/bind/lib/isc/unix/socket.c index 3cfc215e735..9005d145154 100644 --- a/usr.sbin/bind/lib/isc/unix/socket.c +++ b/usr.sbin/bind/lib/isc/unix/socket.c @@ -1,21 +1,21 @@ /* + * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM - * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING - * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. */ -/* $ISC: socket.c,v 1.207.2.19 2003/07/23 06:57:54 marka Exp $ */ +/* $ISC: socket.c,v 1.207.2.19.2.13 2004/07/01 04:51:15 marka Exp $ */ #include <config.h> @@ -63,8 +63,12 @@ * some as socklen_t. This is here so it can be easily changed if needed. */ #ifndef ISC_SOCKADDR_LEN_T +#ifdef _BSD_SOCKLEN_T_ +#define ISC_SOCKADDR_LEN_T _BSD_SOCKLEN_T_ +#else #define ISC_SOCKADDR_LEN_T unsigned int #endif +#endif /* * Define what the possible "soft" errors can be. These are non-fatal returns @@ -128,35 +132,6 @@ typedef isc_event_t intev_t; #endif /* - * Check to see if we have even basic support for cracking messages from - * the control data returned from/sent via recvmsg()/sendmsg(). - */ -#if defined(USE_CMSG) && (!defined(CMSG_LEN) || !defined(CMSG_SPACE)) -#undef USE_CMSG -#endif - -/* - * Determine the size of the control data buffer. - */ -#if USE_CMSG - -#ifdef ISC_PLATFORM_HAVEIPV6 -#define CMSG_BUF_V6_SIZE (CMSG_SPACE(sizeof(struct in6_pktinfo))) -#else -#define CMSG_BUF_V6_SIZE 0 -#endif - -#ifdef SO_TIMESTAMP -#define CMSG_BUF_TS_SIZE (CMSG_SPACE(sizeof(struct timeval))) -#else -#define CMSG_BUF_TS_SIZE 0 -#endif - -#define CMSG_BUF_SIZE (CMSG_BUF_V6_SIZE + CMSG_BUF_TS_SIZE) - -#endif /* USE_CMSG */ - -/* * The number of times a send operation is repeated if the result is EINTR. */ #define NRETRIES 10 @@ -200,6 +175,11 @@ struct isc_socket { #ifdef ISC_NET_RECVOVERFLOW unsigned char overflow; /* used for MSG_TRUNC fake */ #endif + + char *recvcmsgbuf; + ISC_SOCKADDR_LEN_T recvcmsgbuflen; + char *sendcmsgbuf; + ISC_SOCKADDR_LEN_T sendcmsgbuflen; }; #define SOCKET_MANAGER_MAGIC ISC_MAGIC('I', 'O', 'm', 'g') @@ -258,11 +238,9 @@ static void internal_recv(isc_task_t *, isc_event_t *); static void internal_send(isc_task_t *, isc_event_t *); static void process_cmsg(isc_socket_t *, struct msghdr *, isc_socketevent_t *); static void build_msghdr_send(isc_socket_t *, isc_socketevent_t *, - struct msghdr *, char *cmsg, - struct iovec *, size_t *); + struct msghdr *, struct iovec *, size_t *); static void build_msghdr_recv(isc_socket_t *, isc_socketevent_t *, - struct msghdr *, char *cmsg, - struct iovec *, size_t *); + struct msghdr *, struct iovec *, size_t *); #define SELECT_POKE_SHUTDOWN (-1) #define SELECT_POKE_NOTHING (-2) @@ -324,7 +302,7 @@ socket_log(isc_socket_t *sock, isc_sockaddr_t *address, msgcat, msgset, message, "socket %p: %s", sock, msgbuf); } else { - isc_sockaddr_format(address, peerbuf, sizeof peerbuf); + isc_sockaddr_format(address, peerbuf, sizeof(peerbuf)); isc_log_iwrite(isc_lctx, category, module, level, msgcat, msgset, message, "socket %p %s: %s", sock, peerbuf, msgbuf); @@ -347,7 +325,7 @@ wakeup_socket(isc_socketmgr_t *manager, int fd, int msg) { manager->fdstate[fd] = CLOSED; FD_CLR(fd, &manager->read_fds); FD_CLR(fd, &manager->write_fds); - close(fd); + (void)close(fd); return; } if (manager->fdstate[fd] != MANAGED) @@ -475,6 +453,55 @@ make_nonblock(int fd) { return (ISC_R_SUCCESS); } +#ifdef USE_CMSG +/* + * Not all OSes support advanced CMSG macros: CMSG_LEN and CMSG_SPACE. + * In order to ensure as much portability as possible, we provide wrapper + * functions of these macros. + * Note that cmsg_space() could run slow on OSes that do not have + * CMSG_SPACE. + */ +static inline ISC_SOCKADDR_LEN_T +cmsg_len(ISC_SOCKADDR_LEN_T len) { +#ifdef CMSG_LEN + return (CMSG_LEN(len)); +#else + ISC_SOCKADDR_LEN_T hdrlen; + + hdrlen = (ISC_SOCKADDR_LEN_T)CMSG_DATA(NULL); /* XXX */ + return (hdrlen + len); +#endif +} + +static inline ISC_SOCKADDR_LEN_T +cmsg_space(ISC_SOCKADDR_LEN_T len) { +#ifdef CMSG_SPACE + return (CMSG_SPACE(len)); +#else + struct msghdr msg; + struct cmsghdr *cmsgp; + /* + * XXX: The buffer length is an ad-hoc value, but should be enough + * in a practical sense. + */ + char dummybuf[sizeof(struct cmsghdr) + 1024]; + + memset(&msg, 0, sizeof(msg)); + msg.msg_control = dummybuf; + msg.msg_controllen = sizeof(dummybuf); + + cmsgp = (struct cmsghdr *)dummybuf; + cmsgp->cmsg_len = cmsg_len(len); + + cmsgp = CMSG_NXTHDR(&msg, cmsgp); + if (cmsgp != NULL) + return ((char *)cmsgp - (char *)msg.msg_control); + else + return (0); +#endif +} +#endif /* USE_CMSG */ + /* * Process control messages received on a socket. */ @@ -515,7 +542,7 @@ process_cmsg(isc_socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev) { #ifndef USE_CMSG return; #else - if (msg->msg_controllen == 0 || msg->msg_control == NULL) + if (msg->msg_controllen == 0U || msg->msg_control == NULL) return; #ifdef SO_TIMESTAMP @@ -583,8 +610,7 @@ process_cmsg(isc_socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev) { */ static void build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev, - struct msghdr *msg, char *cmsg, - struct iovec *iov, size_t *write_countp) + struct msghdr *msg, struct iovec *iov, size_t *write_countp) { unsigned int iovcount; isc_buffer_t *buffer; @@ -592,11 +618,7 @@ build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev, size_t write_count; size_t skip_count; -#ifndef USE_CMSG - UNUSED(cmsg); -#endif - - memset(msg, 0, sizeof (*msg)); + memset(msg, 0, sizeof(*msg)); if (sock->type == isc_sockettype_udp) { msg->msg_name = (void *)&dev->address.type.sa; @@ -672,13 +694,14 @@ build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev, "sendto pktinfo data, ifindex %u", dev->pktinfo.ipi6_ifindex); - msg->msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); - msg->msg_control = (void *)cmsg; + msg->msg_controllen = cmsg_space(sizeof(struct in6_pktinfo)); + INSIST(msg->msg_controllen <= sock->sendcmsgbuflen); + msg->msg_control = (void *)sock->sendcmsgbuf; - cmsgp = (struct cmsghdr *)cmsg; + cmsgp = (struct cmsghdr *)sock->sendcmsgbuf; cmsgp->cmsg_level = IPPROTO_IPV6; cmsgp->cmsg_type = IPV6_PKTINFO; - cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + cmsgp->cmsg_len = cmsg_len(sizeof(struct in6_pktinfo)); pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp); memcpy(pktinfop, &dev->pktinfo, sizeof(struct in6_pktinfo)); } @@ -706,19 +729,14 @@ build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev, */ static void build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev, - struct msghdr *msg, char *cmsg, - struct iovec *iov, size_t *read_countp) + struct msghdr *msg, struct iovec *iov, size_t *read_countp) { unsigned int iovcount; isc_buffer_t *buffer; isc_region_t available; size_t read_count; -#ifndef USE_CMSG - UNUSED(cmsg); -#endif - - memset(msg, 0, sizeof (struct msghdr)); + memset(msg, 0, sizeof(struct msghdr)); if (sock->type == isc_sockettype_udp) { memset(&dev->address, 0, sizeof(dev->address)); @@ -799,8 +817,8 @@ build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev, msg->msg_flags = 0; #if defined(USE_CMSG) if (sock->type == isc_sockettype_udp) { - msg->msg_control = cmsg; - msg->msg_controllen = CMSG_BUF_SIZE; + msg->msg_control = sock->recvcmsgbuf; + msg->msg_controllen = sock->recvcmsgbuflen; } #endif /* USE_CMSG */ #else /* ISC_NET_BSD44MSGHDR */ @@ -836,7 +854,7 @@ allocate_socketevent(isc_socket_t *sock, isc_eventtype_t eventtype, ev = (isc_socketevent_t *)isc_event_allocate(sock->manager->mctx, sock, eventtype, action, arg, - sizeof (*ev)); + sizeof(*ev)); if (ev == NULL) return (NULL); @@ -860,7 +878,7 @@ dump_msg(struct msghdr *msg) { printf("MSGHDR %p\n", msg); printf("\tname %p, namelen %d\n", msg->msg_name, msg->msg_namelen); printf("\tiov %p, iovlen %d\n", msg->msg_iov, msg->msg_iovlen); - for (i = 0 ; i < (unsigned int)msg->msg_iovlen ; i++) + for (i = 0; i < (unsigned int)msg->msg_iovlen; i++) printf("\t\t%d\tbase %p, len %d\n", i, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); @@ -885,14 +903,9 @@ doio_recv(isc_socket_t *sock, isc_socketevent_t *dev) { struct msghdr msghdr; isc_buffer_t *buffer; int recv_errno; -#if USE_CMSG - char cmsg[CMSG_BUF_SIZE]; -#else - char *cmsg = NULL; -#endif char strbuf[ISC_STRERRORSIZE]; - build_msghdr_recv(sock, dev, &msghdr, cmsg, iov, &read_count); + build_msghdr_recv(sock, dev, &msghdr, iov, &read_count); #if defined(ISC_SOCKET_DEBUG) dump_msg(&msghdr); @@ -1044,16 +1057,11 @@ doio_send(isc_socket_t *sock, isc_socketevent_t *dev) { size_t write_count; struct msghdr msghdr; char addrbuf[ISC_SOCKADDR_FORMATSIZE]; -#if USE_CMSG - char cmsg[CMSG_BUF_SIZE]; -#else - char *cmsg = NULL; -#endif int attempts = 0; int send_errno; char strbuf[ISC_STRERRORSIZE]; - build_msghdr_send(sock, dev, &msghdr, cmsg, iov, &write_count); + build_msghdr_send(sock, dev, &msghdr, iov, &write_count); resend: cc = sendmsg(sock->fd, &msghdr, 0); @@ -1189,8 +1197,9 @@ allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type, { isc_socket_t *sock; isc_result_t ret; + ISC_SOCKADDR_LEN_T cmsgbuflen; - sock = isc_mem_get(manager->mctx, sizeof *sock); + sock = isc_mem_get(manager->mctx, sizeof(*sock)); if (sock == NULL) return (ISC_R_NOMEMORY); @@ -1206,6 +1215,37 @@ allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type, ISC_LINK_INIT(sock, link); + sock->recvcmsgbuf = NULL; + sock->sendcmsgbuf = NULL; + + /* + * set up cmsg buffers + */ + cmsgbuflen = 0; +#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIPV6) + cmsgbuflen = cmsg_space(sizeof(struct in6_pktinfo)); +#endif +#if defined(USE_CMSG) && defined(SO_TIMESTAMP) + cmsgbuflen += cmsg_space(sizeof(struct timeval)); +#endif + sock->recvcmsgbuflen = cmsgbuflen; + if (sock->recvcmsgbuflen != 0) { + sock->recvcmsgbuf = isc_mem_get(manager->mctx, cmsgbuflen); + if (sock->recvcmsgbuf == NULL) + goto error; + } + + cmsgbuflen = 0; +#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIPV6) + cmsgbuflen = cmsg_space(sizeof(struct in6_pktinfo)); +#endif + sock->sendcmsgbuflen = cmsgbuflen; + if (sock->sendcmsgbuflen != 0) { + sock->sendcmsgbuf = isc_mem_get(manager->mctx, cmsgbuflen); + if (sock->sendcmsgbuf == NULL) + goto error; + } + /* * set up list of readers and writers to be initially empty */ @@ -1249,7 +1289,14 @@ allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type, return (ISC_R_SUCCESS); - error: /* socket allocated */ + error: + if (sock->recvcmsgbuf != NULL) + isc_mem_put(manager->mctx, sock->recvcmsgbuf, + sock->recvcmsgbuflen); + if (sock->sendcmsgbuf != NULL) + isc_mem_put(manager->mctx, sock->sendcmsgbuf, + sock->sendcmsgbuflen); + isc_mem_put(manager->mctx, sock, sizeof(*sock)); return (ret); } @@ -1276,11 +1323,18 @@ free_socket(isc_socket_t **socketp) { INSIST(ISC_LIST_EMPTY(sock->accept_list)); INSIST(!ISC_LINK_LINKED(sock, link)); + if (sock->recvcmsgbuf != NULL) + isc_mem_put(sock->manager->mctx, sock->recvcmsgbuf, + sock->recvcmsgbuflen); + if (sock->sendcmsgbuf != NULL) + isc_mem_put(sock->manager->mctx, sock->sendcmsgbuf, + sock->sendcmsgbuflen); + sock->magic = 0; DESTROYLOCK(&sock->lock); - isc_mem_put(sock->manager->mctx, sock, sizeof *sock); + isc_mem_put(sock->manager->mctx, sock, sizeof(*sock)); *socketp = NULL; } @@ -1384,7 +1438,7 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, #ifdef SO_BSDCOMPAT if (setsockopt(sock->fd, SOL_SOCKET, SO_BSDCOMPAT, - (void *)&on, sizeof on) < 0) { + (void *)&on, sizeof(on)) < 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "setsockopt(%d, SO_BSDCOMPAT) %s: %s", @@ -1401,7 +1455,7 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, #if defined(SO_TIMESTAMP) if (setsockopt(sock->fd, SOL_SOCKET, SO_TIMESTAMP, - (void *)&on, sizeof on) < 0 + (void *)&on, sizeof(on)) < 0 && errno != ENOPROTOOPT) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, @@ -1417,11 +1471,20 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, #endif /* SO_TIMESTAMP */ #if defined(ISC_PLATFORM_HAVEIPV6) + if (pf == AF_INET6 && sock->recvcmsgbuflen == 0) { + /* + * Warn explicitly because this anomaly can be hidden + * in usual operation (and unexpectedly appear later). + */ + UNEXPECTED_ERROR(__FILE__, __LINE__, + "No buffer available to receive " + "IPv6 destination"); + } #ifdef IPV6_RECVPKTINFO /* 2292bis */ if ((pf == AF_INET6) && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, - (void *)&on, sizeof (on)) < 0)) { + (void *)&on, sizeof(on)) < 0)) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "setsockopt(%d, IPV6_RECVPKTINFO) " @@ -1436,7 +1499,7 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, /* 2292 */ if ((pf == AF_INET6) && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_PKTINFO, - (void *)&on, sizeof (on)) < 0)) { + (void *)&on, sizeof(on)) < 0)) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "setsockopt(%d, IPV6_PKTINFO) %s: %s", @@ -1453,7 +1516,7 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, if (pf == AF_INET6) { (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU, - (void *)&on, sizeof (on)); + (void *)&on, sizeof(on)); } #endif #endif /* ISC_PLATFORM_HAVEIPV6 */ @@ -1753,7 +1816,7 @@ internal_accept(isc_task_t *me, isc_event_t *ev) { * deamons such as BIND 8 and Apache. */ - addrlen = sizeof dev->newsocket->address.type; + addrlen = sizeof(dev->newsocket->address.type); memset(&dev->newsocket->address.type.sa, 0, addrlen); fd = accept(sock->fd, &dev->newsocket->address.type.sa, (void *)&addrlen); @@ -1858,7 +1921,7 @@ internal_accept(isc_task_t *me, isc_event_t *ev) { UNLOCK(&sock->lock); if (fd != -1 && (make_nonblock(fd) != ISC_R_SUCCESS)) { - close(fd); + (void)close(fd); fd = -1; result = ISC_R_UNEXPECTED; } @@ -1902,7 +1965,7 @@ internal_accept(isc_task_t *me, isc_event_t *ev) { task = dev->ev_sender; dev->ev_sender = sock; - isc_task_sendanddetach(&task, (isc_event_t **)&dev); + isc_task_sendanddetach(&task, ISC_EVENT_PTR(&dev)); return; soft_error: @@ -2045,7 +2108,7 @@ process_fds(isc_socketmgr_t *manager, int maxfd, * Process read/writes on other fds here. Avoid locking * and unlocking twice if both reads and writes are possible. */ - for (i = 0 ; i < maxfd ; i++) { + for (i = 0; i < maxfd; i++) { #ifdef ISC_PLATFORM_USETHREADS if (i == manager->pipe_fds[0] || i == manager->pipe_fds[1]) continue; @@ -2056,7 +2119,7 @@ process_fds(isc_socketmgr_t *manager, int maxfd, FD_CLR(i, &manager->read_fds); FD_CLR(i, &manager->write_fds); - close(i); + (void)close(i); continue; } @@ -2229,7 +2292,7 @@ isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) { } #endif /* ISC_PLATFORM_USETHREADS */ - manager = isc_mem_get(mctx, sizeof *manager); + manager = isc_mem_get(mctx, sizeof(*manager)); if (manager == NULL) return (ISC_R_NOMEMORY); @@ -2238,7 +2301,7 @@ isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) { memset(manager->fds, 0, sizeof(manager->fds)); ISC_LIST_INIT(manager->socklist); if (isc_mutex_init(&manager->lock) != ISC_R_SUCCESS) { - isc_mem_put(mctx, manager, sizeof *manager); + isc_mem_put(mctx, manager, sizeof(*manager)); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_mutex_init() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, @@ -2248,7 +2311,7 @@ isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) { #ifdef ISC_PLATFORM_USETHREADS if (isc_condition_init(&manager->shutdown_ok) != ISC_R_SUCCESS) { DESTROYLOCK(&manager->lock); - isc_mem_put(mctx, manager, sizeof *manager); + isc_mem_put(mctx, manager, sizeof(*manager)); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_condition_init() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, @@ -2262,7 +2325,7 @@ isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) { */ if (pipe(manager->pipe_fds) != 0) { DESTROYLOCK(&manager->lock); - isc_mem_put(mctx, manager, sizeof *manager); + isc_mem_put(mctx, manager, sizeof(*manager)); isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "pipe() %s: %s", @@ -2300,10 +2363,10 @@ isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) { */ if (isc_thread_create(watcher, manager, &manager->watcher) != ISC_R_SUCCESS) { - close(manager->pipe_fds[0]); - close(manager->pipe_fds[1]); + (void)close(manager->pipe_fds[0]); + (void)close(manager->pipe_fds[1]); DESTROYLOCK(&manager->lock); - isc_mem_put(mctx, manager, sizeof *manager); + isc_mem_put(mctx, manager, sizeof(*manager)); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_thread_create() %s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, @@ -2393,19 +2456,19 @@ isc_socketmgr_destroy(isc_socketmgr_t **managerp) { * Clean up. */ #ifdef ISC_PLATFORM_USETHREADS - close(manager->pipe_fds[0]); - close(manager->pipe_fds[1]); + (void)close(manager->pipe_fds[0]); + (void)close(manager->pipe_fds[1]); (void)isc_condition_destroy(&manager->shutdown_ok); #endif /* ISC_PLATFORM_USETHREADS */ - for (i = 0 ; i < (int)FD_SETSIZE ; i++) + for (i = 0; i < (int)FD_SETSIZE; i++) if (manager->fdstate[i] == CLOSE_PENDING) - close(i); + (void)close(i); DESTROYLOCK(&manager->lock); manager->magic = 0; mctx= manager->mctx; - isc_mem_put(mctx, manager, sizeof *manager); + isc_mem_put(mctx, manager, sizeof(*manager)); isc_mem_detach(&mctx); @@ -2602,18 +2665,22 @@ socket_send(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task, set_dev_address(address, sock, dev); if (pktinfo != NULL) { - socket_log(sock, NULL, TRACE, isc_msgcat, ISC_MSGSET_SOCKET, - ISC_MSG_PKTINFOPROVIDED, - "pktinfo structure provided, ifindex %u (set to 0)", - pktinfo->ipi6_ifindex); - dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO; dev->pktinfo = *pktinfo; - /* - * Set the pktinfo index to 0 here, to let the kernel decide - * what interface it should send on. - */ - dev->pktinfo.ipi6_ifindex = 0; + + if (!isc_sockaddr_issitelocal(address) && + !isc_sockaddr_islinklocal(address)) { + socket_log(sock, NULL, TRACE, isc_msgcat, + ISC_MSGSET_SOCKET, ISC_MSG_PKTINFOPROVIDED, + "pktinfo structure provided, ifindex %u " + "(set to 0)", pktinfo->ipi6_ifindex); + + /* + * Set the pktinfo index to 0 here, to let the + * kernel decide what interface it should send on. + */ + dev->pktinfo.ipi6_ifindex = 0; + } } if (sock->type == isc_sockettype_udp) @@ -2795,8 +2862,12 @@ isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr) { UNLOCK(&sock->lock); return (ISC_R_FAMILYMISMATCH); } - if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, - sizeof on) < 0) { + /* + * Only set SO_REUSEADDR when we want a specific port. + */ + if (isc_sockaddr_getport(sockaddr) != (in_port_t)0 && + setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, + sizeof(on)) < 0) { UNEXPECTED_ERROR(__FILE__, __LINE__, "setsockopt(%d) %s", sock->fd, isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, @@ -2838,6 +2909,35 @@ isc_socket_privsep(int flag) { return (ISC_R_SUCCESS); } +isc_result_t +isc_socket_filter(isc_socket_t *sock, const char *filter) { +#ifdef SO_ACCEPTFILTER + char strbuf[ISC_STRERRORSIZE]; + struct accept_filter_arg afa; +#else + UNUSED(sock); + UNUSED(filter); +#endif + + REQUIRE(VALID_SOCKET(sock)); + +#ifdef SO_ACCEPTFILTER + bzero(&afa, sizeof(afa)); + strlcpy(afa.af_name, filter, sizeof(afa.af_name)); + if (setsockopt(sock->fd, SOL_SOCKET, SO_ACCEPTFILTER, + &afa, sizeof(afa)) == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_FILTER, "setsockopt(SO_ACCEPTFILTER): %s", + strbuf); + return (ISC_R_FAILURE); + } + return (ISC_R_SUCCESS); +#else + return (ISC_R_NOTIMPLEMENTED); +#endif +} + /* * Set up to listen on a given socket. We do this by creating an internal * event that will be dispatched when the socket has read activity. The @@ -2907,7 +3007,7 @@ isc_socket_accept(isc_socket_t *sock, */ dev = (isc_socket_newconnev_t *) isc_event_allocate(manager->mctx, task, ISC_SOCKEVENT_NEWCONN, - action, arg, sizeof (*dev)); + action, arg, sizeof(*dev)); if (dev == NULL) { UNLOCK(&sock->lock); return (ISC_R_NOMEMORY); @@ -2916,7 +3016,7 @@ isc_socket_accept(isc_socket_t *sock, ret = allocate_socket(manager, sock->type, &nsock); if (ret != ISC_R_SUCCESS) { - isc_event_free((isc_event_t **)&dev); + isc_event_free(ISC_EVENT_PTR(&dev)); UNLOCK(&sock->lock); return (ret); } @@ -2976,7 +3076,7 @@ isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr, dev = (isc_socket_connev_t *)isc_event_allocate(manager->mctx, sock, ISC_SOCKEVENT_CONNECT, action, arg, - sizeof (*dev)); + sizeof(*dev)); if (dev == NULL) { UNLOCK(&sock->lock); return (ISC_R_NOMEMORY); @@ -3016,12 +3116,12 @@ isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr, UNEXPECTED_ERROR(__FILE__, __LINE__, "%d/%s", errno, strbuf); UNLOCK(&sock->lock); - isc_event_free((isc_event_t **)&dev); + isc_event_free(ISC_EVENT_PTR(&dev)); return (ISC_R_UNEXPECTED); err_exit: sock->connected = 0; - isc_task_send(task, (isc_event_t **)&dev); + isc_task_send(task, ISC_EVENT_PTR(&dev)); UNLOCK(&sock->lock); return (ISC_R_SUCCESS); @@ -3034,7 +3134,7 @@ isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr, sock->connected = 1; sock->bound = 1; dev->result = ISC_R_SUCCESS; - isc_task_send(task, (isc_event_t **)&dev); + isc_task_send(task, ISC_EVENT_PTR(&dev)); UNLOCK(&sock->lock); return (ISC_R_SUCCESS); @@ -3172,7 +3272,7 @@ internal_connect(isc_task_t *me, isc_event_t *ev) { task = dev->ev_sender; dev->ev_sender = sock; - isc_task_sendanddetach(&task, (isc_event_t **)&dev); + isc_task_sendanddetach(&task, ISC_EVENT_PTR(&dev)); } isc_result_t @@ -3214,7 +3314,7 @@ isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp) { ret = ISC_R_SUCCESS; - len = sizeof addressp->type; + len = sizeof(addressp->type); if (getsockname(sock->fd, &addressp->type.sa, (void *)&len) < 0) { isc__strerror(errno, strbuf, sizeof(strbuf)); UNEXPECTED_ERROR(__FILE__, __LINE__, "getsockname: %s", @@ -3320,7 +3420,7 @@ isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) { dev->result = ISC_R_CANCELED; dev->ev_sender = sock; isc_task_sendanddetach(¤t_task, - (isc_event_t **)&dev); + ISC_EVENT_PTR(&dev)); } dev = next; @@ -3347,7 +3447,7 @@ isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) { dev->result = ISC_R_CANCELED; dev->ev_sender = sock; isc_task_sendanddetach(¤t_task, - (isc_event_t **)&dev); + ISC_EVENT_PTR(&dev)); } } @@ -3372,6 +3472,25 @@ isc_socket_isbound(isc_socket_t *sock) { return (val); } +void +isc_socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes) { +#if defined(IPV6_V6ONLY) + int onoff = yes ? 1 : 0; +#else + UNUSED(yes); + UNUSED(sock); +#endif + + REQUIRE(VALID_SOCKET(sock)); + +#ifdef IPV6_V6ONLY + if (sock->pf == AF_INET6) { + (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, + (void *)&onoff, sizeof(onoff)); + } +#endif +} + #ifndef ISC_PLATFORM_USETHREADS void isc__socketmgr_getfdsets(fd_set *readset, fd_set *writeset, int *maxfd) { |
