#ifdef HAVE_GNU_LIB_NAMES_H
#include <gnu/lib-names.h>
#endif
+#ifdef HAVE_RPC_RPC_H
+#include <rpc/rpc.h>
+#endif
enum swrap_dbglvl_e {
SWRAP_LOG_ERROR = 0,
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
#endif
+#ifndef ZERO_STRUCTP
+#define ZERO_STRUCTP(x) do { \
+ if ((x) != NULL) \
+ memset((char *)(x), 0, sizeof(*(x))); \
+ } while(0)
+#endif
+
#ifndef discard_const
#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
#endif
if (s == NULL) {
return NULL;
}
+ /* TODO use realpath(3) here, when we add support for threads */
if (strncmp(s, "./", 2) == 0) {
s += 2;
}
return NULL;
}
+#if 0 /* FIXME */
+static bool check_addr_port_in_use(const struct sockaddr *sa, socklen_t len)
+{
+ struct socket_info *s;
+
+ /* first catch invalid input */
+ switch (sa->sa_family) {
+ case AF_INET:
+ if (len < sizeof(struct sockaddr_in)) {
+ return false;
+ }
+ break;
+#if HAVE_IPV6
+ case AF_INET6:
+ if (len < sizeof(struct sockaddr_in6)) {
+ return false;
+ }
+ break;
+#endif
+ default:
+ return false;
+ break;
+ }
+
+ for (s = sockets; s != NULL; s = s->next) {
+ if (s->myname == NULL) {
+ continue;
+ }
+ if (s->myname->sa_family != sa->sa_family) {
+ continue;
+ }
+ switch (s->myname->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in *sin1, *sin2;
+
+ sin1 = (struct sockaddr_in *)s->myname;
+ sin2 = (struct sockaddr_in *)sa;
+
+ if (sin1->sin_addr.s_addr == htonl(INADDR_ANY)) {
+ continue;
+ }
+ if (sin1->sin_port != sin2->sin_port) {
+ continue;
+ }
+ if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) {
+ continue;
+ }
+
+ /* found */
+ return true;
+ break;
+ }
+#if HAVE_IPV6
+ case AF_INET6: {
+ struct sockaddr_in6 *sin1, *sin2;
+
+ sin1 = (struct sockaddr_in6 *)s->myname;
+ sin2 = (struct sockaddr_in6 *)sa;
+
+ if (sin1->sin6_port != sin2->sin6_port) {
+ continue;
+ }
+ if (!IN6_ARE_ADDR_EQUAL(&sin1->sin6_addr,
+ &sin2->sin6_addr))
+ {
+ continue;
+ }
+
+ /* found */
+ return true;
+ break;
+ }
+#endif
+ default:
+ continue;
+ break;
+
+ }
+ }
+
+ return false;
+}
+#endif
+
static void swrap_remove_stale(int fd)
{
struct socket_info *si = find_socket_info(fd);
#endif
switch (in_addr->sa_family) {
+ case AF_UNSPEC: {
+ const struct sockaddr_in *sin;
+ if (si->family != AF_INET) {
+ break;
+ }
+ if (in_len < sizeof(struct sockaddr_in)) {
+ break;
+ }
+ sin = (const struct sockaddr_in *)in_addr;
+ if(sin->sin_addr.s_addr != htonl(INADDR_ANY)) {
+ break;
+ }
+
+ /*
+ * Note: in the special case of AF_UNSPEC and INADDR_ANY,
+ * AF_UNSPEC is mapped to AF_INET and must be treated here.
+ */
+
+ /* FALL THROUGH */
+ }
case AF_INET:
#ifdef HAVE_IPV6
case AF_INET6:
si->type = real_type;
si->protocol = protocol;
+ /*
+ * Setup myname so getsockname() can succeed to find out the socket
+ * type.
+ */
+ switch(si->family) {
+ case AF_INET: {
+ struct sockaddr_in sin = {
+ .sin_family = AF_INET,
+ };
+
+ si->myname_len = sizeof(struct sockaddr_in);
+ si->myname = sockaddr_dup(&sin, si->myname_len);
+ break;
+ }
+ case AF_INET6: {
+ struct sockaddr_in6 sin6 = {
+ .sin6_family = AF_INET6,
+ };
+
+ si->myname_len = sizeof(struct sockaddr_in6);
+ si->myname = sockaddr_dup(&sin6, si->myname_len);
+ break;
+ }
+ default:
+ free(si);
+ errno = EINVAL;
+ return -1;
+ }
+
fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
if (fi == NULL) {
+ if (si->myname != NULL) {
+ free (si->myname);
+ }
free(si);
errno = ENOMEM;
return -1;
in.sin_addr.s_addr = htonl(127<<24 |
socket_wrapper_default_iface());
+ free(si->myname);
si->myname_len = sizeof(in);
si->myname = sockaddr_dup(&in, si->myname_len);
break;
in6.sin6_family = AF_INET6;
in6.sin6_addr = *swrap_ipv6();
in6.sin6_addr.s6_addr[15] = socket_wrapper_default_iface();
+ free(si->myname);
si->myname_len = sizeof(in6);
si->myname = sockaddr_dup(&in6, si->myname_len);
break;
int ret;
struct sockaddr_un un_addr;
struct socket_info *si = find_socket_info(s);
+ int bind_error = 0;
+#if 0 /* FIXME */
+ bool in_use;
+#endif
if (!si) {
return libc_bind(s, myaddr, addrlen);
}
+ switch (si->family) {
+ case AF_INET: {
+ const struct sockaddr_in *sin;
+ if (addrlen < sizeof(struct sockaddr_in)) {
+ bind_error = EINVAL;
+ break;
+ }
+
+ sin = (const struct sockaddr_in *)myaddr;
+
+ if (sin->sin_family != AF_INET) {
+ bind_error = EAFNOSUPPORT;
+ }
+
+ /* special case for AF_UNSPEC */
+ if (sin->sin_family == AF_UNSPEC &&
+ (sin->sin_addr.s_addr == htonl(INADDR_ANY)))
+ {
+ bind_error = 0;
+ }
+
+ break;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6: {
+ const struct sockaddr_in6 *sin6;
+ if (addrlen < sizeof(struct sockaddr_in6)) {
+ bind_error = EINVAL;
+ break;
+ }
+
+ sin6 = (const struct sockaddr_in6 *)myaddr;
+
+ if (sin6->sin6_family != AF_INET6) {
+ bind_error = EAFNOSUPPORT;
+ }
+
+ break;
+ }
+#endif
+ default:
+ bind_error = EINVAL;
+ break;
+ }
+
+ if (bind_error != 0) {
+ errno = bind_error;
+ return -1;
+ }
+
+#if 0 /* FIXME */
+ in_use = check_addr_port_in_use(myaddr, addrlen);
+ if (in_use) {
+ errno = EADDRINUSE;
+ return -1;
+ }
+#endif
+
+ free(si->myname);
si->myname_len = addrlen;
si->myname = sockaddr_dup(myaddr, addrlen);
return swrap_bind(s, myaddr, addrlen);
}
+/****************************************************************************
+ * BINDRESVPORT
+ ***************************************************************************/
+
+#ifdef HAVE_BINDRESVPORT
+static int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen);
+
+static int swrap_bindresvport_sa(int sd, struct sockaddr *sa)
+{
+ struct sockaddr_storage myaddr;
+ socklen_t salen;
+ static uint16_t port;
+ uint16_t i;
+ int rc = -1;
+ int af;
+
+#define SWRAP_STARTPORT 600
+#define SWRAP_ENDPORT (IPPORT_RESERVED - 1)
+#define SWRAP_NPORTS (SWRAP_ENDPORT - SWRAP_STARTPORT + 1)
+
+ if (port == 0) {
+ port = (getpid() % SWRAP_NPORTS) + SWRAP_STARTPORT;
+ }
+
+ if (sa == NULL) {
+ salen = sizeof(struct sockaddr);
+ sa = (struct sockaddr *)&myaddr;
+
+ rc = swrap_getsockname(sd, (struct sockaddr *)&myaddr, &salen);
+ if (rc < 0) {
+ return -1;
+ }
+
+ af = sa->sa_family;
+ memset(&myaddr, 0, salen);
+ } else {
+ af = sa->sa_family;
+ }
+
+ for (i = 0; i < SWRAP_NPORTS; i++, port++) {
+ switch(af) {
+ case AF_INET: {
+ struct sockaddr_in *sinp = (struct sockaddr_in *)sa;
+
+ salen = sizeof(struct sockaddr_in);
+ sinp->sin_port = htons(port);
+ break;
+ }
+ case AF_INET6: {
+ struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *)sa;
+
+ salen = sizeof(struct sockaddr_in6);
+ sin6p->sin6_port = htons(port);
+ break;
+ }
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+ sa->sa_family = af;
+
+ if (port > SWRAP_ENDPORT) {
+ port = SWRAP_STARTPORT;
+ }
+
+ rc = swrap_bind(sd, (struct sockaddr *)sa, salen);
+ if (rc == 0 || errno != EADDRINUSE) {
+ break;
+ }
+ }
+
+ return rc;
+}
+
+int bindresvport(int sockfd, struct sockaddr_in *sinp)
+{
+ return swrap_bindresvport_sa(sockfd, (struct sockaddr *)sinp);
+}
+#endif
+
/****************************************************************************
* LISTEN
***************************************************************************/
*(int *)optval = si->family;
return 0;
#endif /* SO_DOMAIN */
+
+#ifdef SO_PROTOCOL
case SO_PROTOCOL:
if (optval == NULL || optlen == NULL ||
*optlen < (socklen_t)sizeof(int)) {
*optlen = sizeof(int);
*(int *)optval = si->protocol;
return 0;
+#endif /* SO_PROTOCOL */
case SO_TYPE:
if (optval == NULL || optlen == NULL ||
*optlen < (socklen_t)sizeof(int)) {
{
/* Add packet info */
switch (si->pktinfo) {
-#if defined(IP_PKTINFO)
-/* && (defined(HAVE_STRUCT_IN_PKTINFO) || defined(IP_RECVDSTADDR)) */
+#if defined(IP_PKTINFO) && (defined(HAVE_STRUCT_IN_PKTINFO) || defined(IP_RECVDSTADDR))
case AF_INET: {
struct sockaddr_in *sin;
#if defined(HAVE_STRUCT_IN_PKTINFO)
if (cmlen == 0) {
msg->msg_controllen = 0;
msg->msg_control = NULL;
- } else if (cmlen < msg->msg_controllen) {
+ } else if (cmlen < msg->msg_controllen && cmbuf != NULL) {
memcpy(msg->msg_control, cmbuf, cmlen);
msg->msg_controllen = cmlen;
}