swrap: Fix access to struct members in log messages.
[sfrench/samba-autobuild/.git] / lib / socket_wrapper / socket_wrapper.c
index c5b1fdf85e00bdfce5e672bd2e7caf8117695950..430904d5a0f3e4a5d1fa31a874399589875672e8 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) Jelmer Vernooij 2005,2008 <jelmer@samba.org>
- * Copyright (C) Stefan Metzmacher 2006-2009 <metze@samba.org>
- * Copyright (C) Andreas Schneider 2013 <asn@samba.org>
+ * Copyright (c) 2005-2008 Jelmer Vernooij <jelmer@samba.org>
+ * Copyright (C) 2006-2014 Stefan Metzmacher <metze@samba.org>
+ * Copyright (C) 2013-2014 Andreas Schneider <asn@samba.org>
  *
  * All rights reserved.
  *
 #include <stdarg.h>
 #include <stdbool.h>
 #include <unistd.h>
+#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,
@@ -108,6 +114,13 @@ enum swrap_dbglvl_e {
 #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
@@ -116,6 +129,24 @@ enum swrap_dbglvl_e {
 #define discard_const_p(type, ptr) ((type *)discard_const(ptr))
 #endif
 
+#ifdef IPV6_PKTINFO
+# ifndef IPV6_RECVPKTINFO
+#  define IPV6_RECVPKTINFO IPV6_PKTINFO
+# endif /* IPV6_RECVPKTINFO */
+#endif /* IPV6_PKTINFO */
+
+/*
+ * On BSD IP_PKTINFO has a different name because during
+ * the time when they implemented it, there was no RFC.
+ * The name for IPv6 is the same as on Linux.
+ */
+#ifndef IP_PKTINFO
+# ifdef IP_RECVDSTADDR
+#  define IP_PKTINFO IP_RECVDSTADDR
+# endif
+#endif
+
+
 #define SWRAP_DLIST_ADD(list,item) do { \
        if (!(list)) { \
                (item)->prev    = NULL; \
@@ -179,6 +210,19 @@ enum swrap_dbglvl_e {
  * without changing the format above */
 #define MAX_WRAPPED_INTERFACES 40
 
+struct swrap_address {
+       socklen_t sa_socklen;
+       union {
+               struct sockaddr s;
+               struct sockaddr_in in;
+#ifdef HAVE_IPV6
+               struct sockaddr_in6 in6;
+#endif
+               struct sockaddr_un un;
+               struct sockaddr_storage ss;
+       } sa;
+};
+
 struct socket_info_fd {
        struct socket_info_fd *prev, *next;
        int fd;
@@ -196,14 +240,14 @@ struct socket_info
        int is_server;
        int connected;
        int defer_connect;
+       int pktinfo;
 
-       char *tmp_path;
-
-       struct sockaddr *myname;
-       socklen_t myname_len;
+       /* The unix path so we can unlink it on close() */
+       struct sockaddr_un un_addr;
 
-       struct sockaddr *peername;
-       socklen_t peername_len;
+       struct swrap_address bindname;
+       struct swrap_address myname;
+       struct swrap_address peername;
 
        struct {
                unsigned long pck_snd;
@@ -293,6 +337,7 @@ struct swrap_libc_fns {
                            socklen_t addrlen);
        int (*libc_dup)(int fd);
        int (*libc_dup2)(int oldfd, int newfd);
+       FILE *(*libc_fopen)(const char *name, const char *mode);
 #ifdef HAVE_EVENTFD
        int (*libc_eventfd)(int count, int flags);
 #endif
@@ -393,10 +438,6 @@ static void *swrap_load_lib_handle(enum swrap_lib lib)
        void *handle = NULL;
        int i;
 
-#ifdef HAVE_APPLE
-       return RTLD_NEXT;
-#endif
-
 #ifdef RTLD_DEEPBIND
        flags |= RTLD_DEEPBIND;
 #endif
@@ -422,6 +463,13 @@ static void *swrap_load_lib_handle(enum swrap_lib lib)
                /* FALL TROUGH */
        case SWRAP_LIBC:
                handle = swrap.libc_handle;
+#ifdef LIBC_SO
+               if (handle == NULL) {
+                       handle = dlopen(LIBC_SO, flags);
+
+                       swrap.libc_handle = handle;
+               }
+#endif
                if (handle == NULL) {
                        for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) {
                                char soname[256] = {0};
@@ -436,10 +484,14 @@ static void *swrap_load_lib_handle(enum swrap_lib lib)
        }
 
        if (handle == NULL) {
+#ifdef RTLD_NEXT
+               handle = swrap.libc_handle = swrap.libsocket_handle = RTLD_NEXT;
+#else
                SWRAP_LOG(SWRAP_LOG_ERROR,
                          "Failed to dlopen library: %s\n",
                          dlerror());
                exit(-1);
+#endif
        }
 
        return handle;
@@ -476,7 +528,7 @@ static void *_swrap_load_lib_function(enum swrap_lib lib, const char *fn_name)
 /*
  * IMPORTANT
  *
- * Functions expeciall from libc need to be loaded individually, you can't load
+ * Functions especially from libc need to be loaded individually, you can't load
  * all at once or gdb will segfault at startup. The same applies to valgrind and
  * has probably something todo with with the linker.
  * So we need load each function at the point it is called the first time.
@@ -594,6 +646,13 @@ static int libc_listen(int sockfd, int backlog)
        return swrap.fns.libc_listen(sockfd, backlog);
 }
 
+static FILE *libc_fopen(const char *name, const char *mode)
+{
+       swrap_load_lib_function(SWRAP_LIBC, fopen);
+
+       return swrap.fns.libc_fopen(name, mode);
+}
+
 static int libc_vopen(const char *pathname, int flags, va_list ap)
 {
        long int mode = 0;
@@ -608,6 +667,18 @@ static int libc_vopen(const char *pathname, int flags, va_list ap)
        return fd;
 }
 
+static int libc_open(const char *pathname, int flags, ...)
+{
+       va_list ap;
+       int fd;
+
+       va_start(ap, flags);
+       fd = libc_vopen(pathname, flags, ap);
+       va_end(ap);
+
+       return fd;
+}
+
 static int libc_pipe(int pipefd[2])
 {
        swrap_load_lib_function(SWRAP_LIBSOCKET, pipe);
@@ -759,22 +830,15 @@ static const struct in6_addr *swrap_ipv6(void)
 }
 #endif
 
-static struct sockaddr *sockaddr_dup(const void *data, socklen_t len)
-{
-       struct sockaddr *ret = (struct sockaddr *)malloc(len);
-       memcpy(ret, data, len);
-       return ret;
-}
-
-static void set_port(int family, int prt, struct sockaddr *addr)
+static void set_port(int family, int prt, struct swrap_address *addr)
 {
        switch (family) {
        case AF_INET:
-               ((struct sockaddr_in *)addr)->sin_port = htons(prt);
+               addr->sa.in.sin_port = htons(prt);
                break;
 #ifdef HAVE_IPV6
        case AF_INET6:
-               ((struct sockaddr_in6 *)addr)->sin6_port = htons(prt);
+               addr->sa.in6.sin6_port = htons(prt);
                break;
 #endif
        }
@@ -799,6 +863,7 @@ static const char *socket_wrapper_dir(void)
        if (s == NULL) {
                return NULL;
        }
+       /* TODO use realpath(3) here, when we add support for threads */
        if (strncmp(s, "./", 2) == 0) {
                s += 2;
        }
@@ -915,7 +980,7 @@ static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *i
 
        switch (inaddr->sa_family) {
        case AF_INET: {
-               const struct sockaddr_in *in = 
+               const struct sockaddr_in *in =
                    (const struct sockaddr_in *)(const void *)inaddr;
                unsigned int addr = ntohl(in->sin_addr.s_addr);
                char u_type = '\0';
@@ -962,7 +1027,7 @@ static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *i
        }
 #ifdef HAVE_IPV6
        case AF_INET6: {
-               const struct sockaddr_in6 *in = 
+               const struct sockaddr_in6 *in =
                    (const struct sockaddr_in6 *)(const void *)inaddr;
                struct in6_addr cmp1, cmp2;
 
@@ -1009,14 +1074,14 @@ static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *i
        }
 
        if (is_bcast) {
-               snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL", 
+               snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL",
                         socket_wrapper_dir());
                SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
                /* the caller need to do more processing */
                return 0;
        }
 
-       snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 
+       snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
                 socket_wrapper_dir(), type, iface, prt);
        SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
 
@@ -1036,7 +1101,7 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
 
        switch (si->family) {
        case AF_INET: {
-               const struct sockaddr_in *in = 
+               const struct sockaddr_in *in =
                    (const struct sockaddr_in *)(const void *)inaddr;
                unsigned int addr = ntohl(in->sin_addr.s_addr);
                char u_type = '\0';
@@ -1087,11 +1152,26 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
                        errno = EADDRNOTAVAIL;
                        return -1;
                }
+
+               /* Store the bind address for connect() */
+               if (si->bindname.sa_socklen == 0) {
+                       struct sockaddr_in bind_in;
+                       socklen_t blen = sizeof(struct sockaddr_in);
+
+                       ZERO_STRUCT(bind_in);
+                       bind_in.sin_family = in->sin_family;
+                       bind_in.sin_port = in->sin_port;
+                       bind_in.sin_addr.s_addr = htonl(0x7F000000 | iface);
+
+                       si->bindname.sa_socklen = blen;
+                       memcpy(&si->bindname.sa.in, &bind_in, blen);
+               }
+
                break;
        }
 #ifdef HAVE_IPV6
        case AF_INET6: {
-               const struct sockaddr_in6 *in = 
+               const struct sockaddr_in6 *in =
                    (const struct sockaddr_in6 *)(const void *)inaddr;
                struct in6_addr cmp1, cmp2;
 
@@ -1124,6 +1204,22 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
                        return -1;
                }
 
+               /* Store the bind address for connect() */
+               if (si->bindname.sa_socklen == 0) {
+                       struct sockaddr_in6 bind_in;
+                       socklen_t blen = sizeof(struct sockaddr_in6);
+
+                       ZERO_STRUCT(bind_in);
+                       bind_in.sin6_family = in->sin6_family;
+                       bind_in.sin6_port = in->sin6_port;
+
+                       bind_in.sin6_addr = *swrap_ipv6();
+                       bind_in.sin6_addr.s6_addr[15] = iface;
+
+                       memcpy(&si->bindname.sa.in6, &bind_in, blen);
+                       si->bindname.sa_socklen = blen;
+               }
+
                break;
        }
 #endif
@@ -1144,11 +1240,13 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
        if (prt == 0) {
                /* handle auto-allocation of ephemeral ports */
                for (prt = 5001; prt < 10000; prt++) {
-                       snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 
+                       snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
                                 socket_wrapper_dir(), type, iface, prt);
                        if (stat(un->sun_path, &st) == 0) continue;
 
-                       set_port(si->family, prt, si->myname);
+                       set_port(si->family, prt, &si->myname);
+                       set_port(si->family, prt, &si->bindname);
+
                        break;
                }
                if (prt == 10000) {
@@ -1157,7 +1255,7 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
                }
        }
 
-       snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 
+       snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
                 socket_wrapper_dir(), type, iface, prt);
        SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
        return 0;
@@ -1179,6 +1277,90 @@ static struct socket_info *find_socket_info(int fd)
        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);
@@ -1221,6 +1403,26 @@ static int sockaddr_convert_to_un(struct socket_info *si,
 #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:
@@ -1248,8 +1450,8 @@ static int sockaddr_convert_to_un(struct socket_info *si,
        return -1;
 }
 
-static int sockaddr_convert_from_un(const struct socket_info *si, 
-                                   const struct sockaddr_un *in_addr, 
+static int sockaddr_convert_from_un(const struct socket_info *si,
+                                   const struct sockaddr_un *in_addr,
                                    socklen_t un_addrlen,
                                    int family,
                                    struct sockaddr *out_addr,
@@ -1257,7 +1459,7 @@ static int sockaddr_convert_from_un(const struct socket_info *si,
 {
        int ret;
 
-       if (out_addr == NULL || out_addrlen == NULL) 
+       if (out_addr == NULL || out_addrlen == NULL)
                return 0;
 
        if (un_addrlen == 0) {
@@ -1405,7 +1607,7 @@ union swrap_packet_payload {
         SWRAP_PACKET_IP_SIZE + \
         SWRAP_PACKET_PAYLOAD_SIZE)
 
-static const char *socket_wrapper_pcap_file(void)
+static const char *swrap_pcap_init_file(void)
 {
        static int initialized = 0;
        static const char *s = NULL;
@@ -1422,7 +1624,7 @@ static const char *socket_wrapper_pcap_file(void)
        /*
         * TODO: don't use the structs use plain buffer offsets
         *       and PUSH_U8(), PUSH_U16() and PUSH_U32()
-        * 
+        *
         * for now make sure we disable PCAP support
         * if the struct has alignment!
         */
@@ -1467,17 +1669,17 @@ static const char *socket_wrapper_pcap_file(void)
        return s;
 }
 
-static uint8_t *swrap_packet_init(struct timeval *tval,
-                                 const struct sockaddr *src,
-                                 const struct sockaddr *dest,
-                                 int socket_type,
-                                 const uint8_t *payload,
-                                 size_t payload_len,
-                                 unsigned long tcp_seqno,
-                                 unsigned long tcp_ack,
-                                 unsigned char tcp_ctl,
-                                 int unreachable,
-                                 size_t *_packet_len)
+static uint8_t *swrap_pcap_packet_init(struct timeval *tval,
+                                      const struct sockaddr *src,
+                                      const struct sockaddr *dest,
+                                      int socket_type,
+                                      const uint8_t *payload,
+                                      size_t payload_len,
+                                      unsigned long tcp_seqno,
+                                      unsigned long tcp_ack,
+                                      unsigned char tcp_ctl,
+                                      int unreachable,
+                                      size_t *_packet_len)
 {
        uint8_t *base;
        uint8_t *buf;
@@ -1589,7 +1791,7 @@ static uint8_t *swrap_packet_init(struct timeval *tval,
                ip->v4.tos              = 0x00;
                ip->v4.packet_length    = htons(wire_len - icmp_truncate_len);
                ip->v4.identification   = htons(0xFFFF);
-               ip->v4.flags            = 0x40; /* BIT 1 set - means don't fraqment */
+               ip->v4.flags            = 0x40; /* BIT 1 set - means don't fragment */
                ip->v4.fragment         = htons(0x0000);
                ip->v4.ttl              = 0xFF;
                ip->v4.protocol         = protocol;
@@ -1628,7 +1830,7 @@ static uint8_t *swrap_packet_init(struct timeval *tval,
                        ip->v4.tos              = 0x00;
                        ip->v4.packet_length    = htons(wire_len - icmp_hdr_len);
                        ip->v4.identification   = htons(0xFFFF);
-                       ip->v4.flags            = 0x40; /* BIT 1 set - means don't fraqment */
+                       ip->v4.flags            = 0x40; /* BIT 1 set - means don't fragment */
                        ip->v4.fragment         = htons(0x0000);
                        ip->v4.ttl              = 0xFF;
                        ip->v4.protocol         = icmp_protocol;
@@ -1701,13 +1903,13 @@ static uint8_t *swrap_packet_init(struct timeval *tval,
        return base;
 }
 
-static int swrap_get_pcap_fd(const char *fname)
+static int swrap_pcap_get_fd(const char *fname)
 {
        static int fd = -1;
 
        if (fd != -1) return fd;
 
-       fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0644);
+       fd = libc_open(fname, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0644);
        if (fd != -1) {
                struct swrap_file_hdr file_hdr;
                file_hdr.magic          = 0xA1B2C3D4;
@@ -1725,16 +1927,16 @@ static int swrap_get_pcap_fd(const char *fname)
                return fd;
        }
 
-       fd = open(fname, O_WRONLY|O_APPEND, 0644);
+       fd = libc_open(fname, O_WRONLY|O_APPEND, 0644);
 
        return fd;
 }
 
-static uint8_t *swrap_marshall_packet(struct socket_info *si,
-                                     const struct sockaddr *addr,
-                                     enum swrap_packet_type type,
-                                     const void *buf, size_t len,
-                                     size_t *packet_len)
+static uint8_t *swrap_pcap_marshall_packet(struct socket_info *si,
+                                          const struct sockaddr *addr,
+                                          enum swrap_packet_type type,
+                                          const void *buf, size_t len,
+                                          size_t *packet_len)
 {
        const struct sockaddr *src_addr;
        const struct sockaddr *dest_addr;
@@ -1760,7 +1962,7 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_CONNECT_SEND:
                if (si->type != SOCK_STREAM) return NULL;
 
-               src_addr = si->myname;
+               src_addr  = &si->myname.sa.s;
                dest_addr = addr;
 
                tcp_seqno = si->io.pck_snd;
@@ -1774,7 +1976,7 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_CONNECT_RECV:
                if (si->type != SOCK_STREAM) return NULL;
 
-               dest_addr = si->myname;
+               dest_addr = &si->myname.sa.s;
                src_addr = addr;
 
                tcp_seqno = si->io.pck_rcv;
@@ -1788,8 +1990,8 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_CONNECT_UNREACH:
                if (si->type != SOCK_STREAM) return NULL;
 
-               dest_addr = si->myname;
-               src_addr = addr;
+               dest_addr = &si->myname.sa.s;
+               src_addr  = addr;
 
                /* Unreachable: resend the data of SWRAP_CONNECT_SEND */
                tcp_seqno = si->io.pck_snd - 1;
@@ -1802,7 +2004,7 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_CONNECT_ACK:
                if (si->type != SOCK_STREAM) return NULL;
 
-               src_addr = si->myname;
+               src_addr  = &si->myname.sa.s;
                dest_addr = addr;
 
                tcp_seqno = si->io.pck_snd;
@@ -1814,7 +2016,7 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_ACCEPT_SEND:
                if (si->type != SOCK_STREAM) return NULL;
 
-               dest_addr = si->myname;
+               dest_addr = &si->myname.sa.s;
                src_addr = addr;
 
                tcp_seqno = si->io.pck_rcv;
@@ -1828,7 +2030,7 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_ACCEPT_RECV:
                if (si->type != SOCK_STREAM) return NULL;
 
-               src_addr = si->myname;
+               src_addr = &si->myname.sa.s;
                dest_addr = addr;
 
                tcp_seqno = si->io.pck_snd;
@@ -1842,7 +2044,7 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_ACCEPT_ACK:
                if (si->type != SOCK_STREAM) return NULL;
 
-               dest_addr = si->myname;
+               dest_addr = &si->myname.sa.s;
                src_addr = addr;
 
                tcp_seqno = si->io.pck_rcv;
@@ -1852,8 +2054,8 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
                break;
 
        case SWRAP_SEND:
-               src_addr = si->myname;
-               dest_addr = si->peername;
+               src_addr  = &si->myname.sa.s;
+               dest_addr = &si->peername.sa.s;
 
                tcp_seqno = si->io.pck_snd;
                tcp_ack = si->io.pck_rcv;
@@ -1864,13 +2066,16 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
                break;
 
        case SWRAP_SEND_RST:
-               dest_addr = si->myname;
-               src_addr = si->peername;
+               dest_addr = &si->myname.sa.s;
+               src_addr  = &si->peername.sa.s;
 
                if (si->type == SOCK_DGRAM) {
-                       return swrap_marshall_packet(si, si->peername,
-                                         SWRAP_SENDTO_UNREACH,
-                                         buf, len, packet_len);
+                       return swrap_pcap_marshall_packet(si,
+                                                         &si->peername.sa.s,
+                                                         SWRAP_SENDTO_UNREACH,
+                                                         buf,
+                                                         len,
+                                                         packet_len);
                }
 
                tcp_seqno = si->io.pck_rcv;
@@ -1880,8 +2085,8 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
                break;
 
        case SWRAP_PENDING_RST:
-               dest_addr = si->myname;
-               src_addr = si->peername;
+               dest_addr = &si->myname.sa.s;
+               src_addr  = &si->peername.sa.s;
 
                if (si->type == SOCK_DGRAM) {
                        return NULL;
@@ -1894,8 +2099,8 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
                break;
 
        case SWRAP_RECV:
-               dest_addr = si->myname;
-               src_addr = si->peername;
+               dest_addr = &si->myname.sa.s;
+               src_addr  = &si->peername.sa.s;
 
                tcp_seqno = si->io.pck_rcv;
                tcp_ack = si->io.pck_snd;
@@ -1906,8 +2111,8 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
                break;
 
        case SWRAP_RECV_RST:
-               dest_addr = si->myname;
-               src_addr = si->peername;
+               dest_addr = &si->myname.sa.s;
+               src_addr  = &si->peername.sa.s;
 
                if (si->type == SOCK_DGRAM) {
                        return NULL;
@@ -1920,7 +2125,7 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
                break;
 
        case SWRAP_SENDTO:
-               src_addr = si->myname;
+               src_addr = &si->myname.sa.s;
                dest_addr = addr;
 
                si->io.pck_snd += len;
@@ -1928,7 +2133,7 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
                break;
 
        case SWRAP_SENDTO_UNREACH:
-               dest_addr = si->myname;
+               dest_addr = &si->myname.sa.s;
                src_addr = addr;
 
                unreachable = 1;
@@ -1936,7 +2141,7 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
                break;
 
        case SWRAP_RECVFROM:
-               dest_addr = si->myname;
+               dest_addr = &si->myname.sa.s;
                src_addr = addr;
 
                si->io.pck_rcv += len;
@@ -1946,8 +2151,8 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_CLOSE_SEND:
                if (si->type != SOCK_STREAM) return NULL;
 
-               src_addr = si->myname;
-               dest_addr = si->peername;
+               src_addr  = &si->myname.sa.s;
+               dest_addr = &si->peername.sa.s;
 
                tcp_seqno = si->io.pck_snd;
                tcp_ack = si->io.pck_rcv;
@@ -1960,8 +2165,8 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_CLOSE_RECV:
                if (si->type != SOCK_STREAM) return NULL;
 
-               dest_addr = si->myname;
-               src_addr = si->peername;
+               dest_addr = &si->myname.sa.s;
+               src_addr  = &si->peername.sa.s;
 
                tcp_seqno = si->io.pck_rcv;
                tcp_ack = si->io.pck_snd;
@@ -1974,8 +2179,8 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_CLOSE_ACK:
                if (si->type != SOCK_STREAM) return NULL;
 
-               src_addr = si->myname;
-               dest_addr = si->peername;
+               src_addr  = &si->myname.sa.s;
+               dest_addr = &si->peername.sa.s;
 
                tcp_seqno = si->io.pck_snd;
                tcp_ack = si->io.pck_rcv;
@@ -1988,33 +2193,45 @@ static uint8_t *swrap_marshall_packet(struct socket_info *si,
 
        swrapGetTimeOfDay(&tv);
 
-       return swrap_packet_init(&tv, src_addr, dest_addr, si->type,
-                                (const uint8_t *)buf, len,
-                                tcp_seqno, tcp_ack, tcp_ctl, unreachable,
-                                packet_len);
+       return swrap_pcap_packet_init(&tv,
+                                     src_addr,
+                                     dest_addr,
+                                     si->type,
+                                     (const uint8_t *)buf,
+                                     len,
+                                     tcp_seqno,
+                                     tcp_ack,
+                                     tcp_ctl,
+                                     unreachable,
+                                     packet_len);
 }
 
-static void swrap_dump_packet(struct socket_info *si,
-                             const struct sockaddr *addr,
-                             enum swrap_packet_type type,
-                             const void *buf, size_t len)
+static void swrap_pcap_dump_packet(struct socket_info *si,
+                                  const struct sockaddr *addr,
+                                  enum swrap_packet_type type,
+                                  const void *buf, size_t len)
 {
        const char *file_name;
        uint8_t *packet;
        size_t packet_len = 0;
        int fd;
 
-       file_name = socket_wrapper_pcap_file();
+       file_name = swrap_pcap_init_file();
        if (!file_name) {
                return;
        }
 
-       packet = swrap_marshall_packet(si, addr, type, buf, len, &packet_len);
-       if (!packet) {
+       packet = swrap_pcap_marshall_packet(si,
+                                           addr,
+                                           type,
+                                           buf,
+                                           len,
+                                           &packet_len);
+       if (packet == NULL) {
                return;
        }
 
-       fd = swrap_get_pcap_fd(file_name);
+       fd = swrap_pcap_get_fd(file_name);
        if (fd != -1) {
                if (write(fd, packet, packet_len) != (ssize_t)packet_len) {
                        free(packet);
@@ -2146,6 +2363,35 @@ static int swrap_socket(int family, int type, int protocol)
        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.sa_socklen = sizeof(struct sockaddr_in);
+               memcpy(&si->myname.sa.in, &sin, si->myname.sa_socklen);
+               break;
+       }
+       case AF_INET6: {
+               struct sockaddr_in6 sin6 = {
+                       .sin6_family = AF_INET6,
+               };
+
+               si->myname.sa_socklen = sizeof(struct sockaddr_in6);
+               memcpy(&si->myname.sa.in6, &sin6, si->myname.sa_socklen);
+               break;
+       }
+       default:
+               free(si);
+               errno = EINVAL;
+               return -1;
+       }
+
        fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
        if (fi == NULL) {
                free(si);
@@ -2242,12 +2488,18 @@ static int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
        struct socket_info *parent_si, *child_si;
        struct socket_info_fd *child_fi;
        int fd;
-       struct sockaddr_un un_addr;
-       socklen_t un_addrlen = sizeof(un_addr);
-       struct sockaddr_un un_my_addr;
-       socklen_t un_my_addrlen = sizeof(un_my_addr);
-       struct sockaddr *my_addr;
-       socklen_t my_addrlen, len;
+       struct swrap_address un_addr = {
+               .sa_socklen = sizeof(struct sockaddr_un),
+       };
+       struct swrap_address un_my_addr = {
+               .sa_socklen = sizeof(struct sockaddr_un),
+       };
+       struct swrap_address in_addr = {
+               .sa_socklen = sizeof(struct sockaddr_storage),
+       };
+       struct swrap_address in_my_addr = {
+               .sa_socklen = sizeof(struct sockaddr_storage),
+       };
        int ret;
 
        parent_si = find_socket_info(s);
@@ -2255,41 +2507,34 @@ static int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
                return libc_accept(s, addr, addrlen);
        }
 
-       /* 
+       /*
         * assume out sockaddr have the same size as the in parent
         * socket family
         */
-       my_addrlen = socket_length(parent_si->family);
-       if (my_addrlen <= 0) {
+       in_addr.sa_socklen = socket_length(parent_si->family);
+       if (in_addr.sa_socklen <= 0) {
                errno = EINVAL;
                return -1;
        }
 
-       my_addr = (struct sockaddr *)malloc(my_addrlen);
-       if (my_addr == NULL) {
-               return -1;
-       }
-
-       memset(&un_addr, 0, sizeof(un_addr));
-       memset(&un_my_addr, 0, sizeof(un_my_addr));
-
-       ret = libc_accept(s, (struct sockaddr *)(void *)&un_addr, &un_addrlen);
+       ret = libc_accept(s, &un_addr.sa.s, &un_addr.sa_socklen);
        if (ret == -1) {
                if (errno == ENOTSOCK) {
                        /* Remove stale fds */
                        swrap_remove_stale(s);
                }
-               free(my_addr);
                return ret;
        }
 
        fd = ret;
 
-       len = my_addrlen;
-       ret = sockaddr_convert_from_un(parent_si, &un_addr, un_addrlen,
-                                      parent_si->family, my_addr, &len);
+       ret = sockaddr_convert_from_un(parent_si,
+                                      &un_addr.sa.un,
+                                      un_addr.sa_socklen,
+                                      parent_si->family,
+                                      &in_addr.sa.s,
+                                      &in_addr.sa_socklen);
        if (ret == -1) {
-               free(my_addr);
                close(fd);
                return ret;
        }
@@ -2300,7 +2545,6 @@ static int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
        child_fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
        if (child_fi == NULL) {
                free(child_si);
-               free(my_addr);
                close(fd);
                errno = ENOMEM;
                return -1;
@@ -2317,53 +2561,57 @@ static int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
        child_si->is_server = 1;
        child_si->connected = 1;
 
-       child_si->peername_len = len;
-       child_si->peername = sockaddr_dup(my_addr, len);
+       child_si->peername = (struct swrap_address) {
+               .sa_socklen = in_addr.sa_socklen,
+       };
+       memcpy(&child_si->peername.sa.ss, &in_addr.sa.ss, in_addr.sa_socklen);
 
        if (addr != NULL && addrlen != NULL) {
-               size_t copy_len = MIN(*addrlen, len);
+               size_t copy_len = MIN(*addrlen, in_addr.sa_socklen);
                if (copy_len > 0) {
-                       memcpy(addr, my_addr, copy_len);
+                       memcpy(addr, &in_addr.sa.ss, copy_len);
                }
-               *addrlen = len;
+               *addrlen = in_addr.sa_socklen;
        }
 
        ret = libc_getsockname(fd,
-                              (struct sockaddr *)(void *)&un_my_addr,
-                              &un_my_addrlen);
+                              &un_my_addr.sa.s,
+                              &un_my_addr.sa_socklen);
        if (ret == -1) {
                free(child_fi);
                free(child_si);
-               free(my_addr);
                close(fd);
                return ret;
        }
 
-       len = my_addrlen;
-       ret = sockaddr_convert_from_un(child_si, &un_my_addr, un_my_addrlen,
-                                      child_si->family, my_addr, &len);
+       ret = sockaddr_convert_from_un(child_si,
+                                      &un_my_addr.sa.un,
+                                      un_my_addr.sa_socklen,
+                                      child_si->family,
+                                      &in_my_addr.sa.s,
+                                      &in_my_addr.sa_socklen);
        if (ret == -1) {
                free(child_fi);
                free(child_si);
-               free(my_addr);
                close(fd);
                return ret;
        }
 
        SWRAP_LOG(SWRAP_LOG_TRACE,
                  "accept() path=%s, fd=%d",
-                 un_my_addr.sun_path, s);
+                 un_my_addr.sa.un.sun_path, s);
 
-       child_si->myname_len = len;
-       child_si->myname = sockaddr_dup(my_addr, len);
-       free(my_addr);
+       child_si->myname = (struct swrap_address) {
+               .sa_socklen = in_my_addr.sa_socklen,
+       };
+       memcpy(&child_si->myname.sa.ss, &in_my_addr.sa.ss, in_my_addr.sa_socklen);
 
        SWRAP_DLIST_ADD(sockets, child_si);
 
        if (addr != NULL) {
-               swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0);
-               swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_RECV, NULL, 0);
-               swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_ACK, NULL, 0);
+               swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0);
+               swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_RECV, NULL, 0);
+               swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_ACK, NULL, 0);
        }
 
        return fd;
@@ -2383,13 +2631,15 @@ static int autobind_start;
 
 /* using sendto() or connect() on an unbound socket would give the
    recipient no way to reply, as unlike UDP and TCP, a unix domain
-   socket can't auto-assign emphemeral port numbers, so we need to
+   socket can't auto-assign ephemeral port numbers, so we need to
    assign it here.
    Note: this might change the family from ipv6 to ipv4
 */
 static int swrap_auto_bind(int fd, struct socket_info *si, int family)
 {
-       struct sockaddr_un un_addr;
+       struct swrap_address un_addr = {
+               .sa_socklen = sizeof(struct sockaddr_un),
+       };
        int i;
        char type;
        int ret;
@@ -2403,7 +2653,7 @@ static int swrap_auto_bind(int fd, struct socket_info *si, int family)
                autobind_start += 10000;
        }
 
-       un_addr.sun_family = AF_UNIX;
+       un_addr.sa.un.sun_family = AF_UNIX;
 
        switch (family) {
        case AF_INET: {
@@ -2414,7 +2664,7 @@ static int swrap_auto_bind(int fd, struct socket_info *si, int family)
                        type = SOCKET_TYPE_CHAR_TCP;
                        break;
                case SOCK_DGRAM:
-                       type = SOCKET_TYPE_CHAR_UDP;
+                       type = SOCKET_TYPE_CHAR_UDP;
                        break;
                default:
                    errno = ESOCKTNOSUPPORT;
@@ -2423,11 +2673,13 @@ static int swrap_auto_bind(int fd, struct socket_info *si, int family)
 
                memset(&in, 0, sizeof(in));
                in.sin_family = AF_INET;
-               in.sin_addr.s_addr = htonl(127<<24 | 
+               in.sin_addr.s_addr = htonl(127<<24 |
                                           socket_wrapper_default_iface());
 
-               si->myname_len = sizeof(in);
-               si->myname = sockaddr_dup(&in, si->myname_len);
+               si->myname = (struct swrap_address) {
+                       .sa_socklen = sizeof(in),
+               };
+               memcpy(&si->myname.sa.in, &in, si->myname.sa_socklen);
                break;
        }
 #ifdef HAVE_IPV6
@@ -2444,7 +2696,7 @@ static int swrap_auto_bind(int fd, struct socket_info *si, int family)
                        type = SOCKET_TYPE_CHAR_TCP_V6;
                        break;
                case SOCK_DGRAM:
-                       type = SOCKET_TYPE_CHAR_UDP_V6;
+                       type = SOCKET_TYPE_CHAR_UDP_V6;
                        break;
                default:
                        errno = ESOCKTNOSUPPORT;
@@ -2455,8 +2707,11 @@ static int swrap_auto_bind(int fd, struct socket_info *si, int family)
                in6.sin6_family = AF_INET6;
                in6.sin6_addr = *swrap_ipv6();
                in6.sin6_addr.s6_addr[15] = socket_wrapper_default_iface();
-               si->myname_len = sizeof(in6);
-               si->myname = sockaddr_dup(&in6, si->myname_len);
+
+               si->myname = (struct swrap_address) {
+                       .sa_socklen = sizeof(in6),
+               };
+               memcpy(&si->myname.sa.in6, &in6, si->myname.sa_socklen);
                break;
        }
 #endif
@@ -2471,16 +2726,16 @@ static int swrap_auto_bind(int fd, struct socket_info *si, int family)
 
        for (i = 0; i < SOCKET_MAX_SOCKETS; i++) {
                port = autobind_start + i;
-               snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), 
+               snprintf(un_addr.sa.un.sun_path, un_addr.sa_socklen,
                         "%s/"SOCKET_FORMAT, socket_wrapper_dir(),
                         type, socket_wrapper_default_iface(), port);
-               if (stat(un_addr.sun_path, &st) == 0) continue;
+               if (stat(un_addr.sa.un.sun_path, &st) == 0) continue;
 
-               ret = libc_bind(fd, (struct sockaddr *)(void *)&un_addr,
-                               sizeof(un_addr));
+               ret = libc_bind(fd, &un_addr.sa.s, un_addr.sa_socklen);
                if (ret == -1) return ret;
 
-               si->tmp_path = strdup(un_addr.sun_path);
+               si->un_addr = un_addr.sa.un;
+
                si->bound = 1;
                autobind_start = port + 1;
                break;
@@ -2497,7 +2752,7 @@ static int swrap_auto_bind(int fd, struct socket_info *si, int family)
        }
 
        si->family = family;
-       set_port(si->family, port, si->myname);
+       set_port(si->family, port, &si->myname);
 
        return 0;
 }
@@ -2510,7 +2765,9 @@ static int swrap_connect(int s, const struct sockaddr *serv_addr,
                         socklen_t addrlen)
 {
        int ret;
-       struct sockaddr_un un_addr;
+       struct swrap_address un_addr = {
+               .sa_socklen = sizeof(struct sockaddr_un),
+       };
        struct socket_info *si = find_socket_info(s);
        int bcast = 0;
 
@@ -2529,7 +2786,7 @@ static int swrap_connect(int s, const struct sockaddr *serv_addr,
        }
 
        ret = sockaddr_convert_to_un(si, serv_addr,
-                                    addrlen, &un_addr, 0, &bcast);
+                                    addrlen, &un_addr.sa.un, 0, &bcast);
        if (ret == -1) return -1;
 
        if (bcast) {
@@ -2541,16 +2798,16 @@ static int swrap_connect(int s, const struct sockaddr *serv_addr,
                si->defer_connect = 1;
                ret = 0;
        } else {
-               swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0);
+               swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0);
 
                ret = libc_connect(s,
-                                  (struct sockaddr *)(void *)&un_addr,
-                                  sizeof(struct sockaddr_un));
+                                  &un_addr.sa.s,
+                                  un_addr.sa_socklen);
        }
 
        SWRAP_LOG(SWRAP_LOG_TRACE,
                  "connect() path=%s, fd=%d",
-                 un_addr.sun_path, s);
+                 un_addr.sa.un.sun_path, s);
 
 
        /* to give better errors */
@@ -2559,14 +2816,39 @@ static int swrap_connect(int s, const struct sockaddr *serv_addr,
        }
 
        if (ret == 0) {
-               si->peername_len = addrlen;
-               si->peername = sockaddr_dup(serv_addr, addrlen);
+               si->peername = (struct swrap_address) {
+                       .sa_socklen = addrlen,
+               };
+
+               memcpy(&si->peername.sa.ss, serv_addr, addrlen);
                si->connected = 1;
 
-               swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0);
-               swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0);
+               /*
+                * When we connect() on a socket than we have to bind the
+                * outgoing connection on the interface we use for the
+                * transport. We already bound it on the right interface
+                * but here we have to update the name so getsockname()
+                * returns correct information.
+                */
+               if (si->bindname.sa_socklen > 0) {
+                       si->myname = (struct swrap_address) {
+                               .sa_socklen = si->bindname.sa_socklen,
+                       };
+
+                       memcpy(&si->myname.sa.ss,
+                              &si->bindname.sa.ss,
+                              si->bindname.sa_socklen);
+
+                       /* Cleanup bindname */
+                       si->bindname = (struct swrap_address) {
+                               .sa_socklen = 0,
+                       };
+               }
+
+               swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0);
+               swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0);
        } else {
-               swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_UNREACH, NULL, 0);
+               swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_UNREACH, NULL, 0);
        }
 
        return ret;
@@ -2584,27 +2866,95 @@ int connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen)
 static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
 {
        int ret;
-       struct sockaddr_un un_addr;
+       struct swrap_address un_addr = {
+               .sa_socklen = sizeof(struct sockaddr_un),
+       };
        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);
        }
 
-       si->myname_len = addrlen;
-       si->myname = sockaddr_dup(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
+
+       si->myname.sa_socklen = addrlen;
+       memcpy(&si->myname.sa.ss, myaddr, addrlen);
 
-       ret = sockaddr_convert_to_un(si, myaddr, addrlen, &un_addr, 1, &si->bcast);
+       ret = sockaddr_convert_to_un(si,
+                                    myaddr,
+                                    addrlen,
+                                    &un_addr.sa.un,
+                                    1,
+                                    &si->bcast);
        if (ret == -1) return -1;
 
-       unlink(un_addr.sun_path);
+       unlink(un_addr.sa.un.sun_path);
 
-       ret = libc_bind(s, (struct sockaddr *)(void *)&un_addr,
-                       sizeof(struct sockaddr_un));
+       ret = libc_bind(s, &un_addr.sa.s, un_addr.sa_socklen);
 
        SWRAP_LOG(SWRAP_LOG_TRACE,
                  "bind() path=%s, fd=%d",
-                 un_addr.sun_path, s);
+                 un_addr.sa.un.sun_path, s);
 
        if (ret == 0) {
                si->bound = 1;
@@ -2618,6 +2968,88 @@ int bind(int s, const struct sockaddr *myaddr, socklen_t 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 swrap_address myaddr = {
+               .sa_socklen = sizeof(struct sockaddr_storage),
+       };
+       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 = myaddr.sa_socklen;
+               sa = &myaddr.sa.s;
+
+               rc = swrap_getsockname(sd, &myaddr.sa.s, &salen);
+               if (rc < 0) {
+                       return -1;
+               }
+
+               af = sa->sa_family;
+               memset(&myaddr.sa.ss, 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 *)(void *)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
  ***************************************************************************/
@@ -2641,6 +3073,29 @@ int listen(int s, int backlog)
        return swrap_listen(s, backlog);
 }
 
+/****************************************************************************
+ *   FOPEN
+ ***************************************************************************/
+
+static FILE *swrap_fopen(const char *name, const char *mode)
+{
+       FILE *fp;
+
+       fp = libc_fopen(name, mode);
+       if (fp != NULL) {
+               int fd = fileno(fp);
+
+               swrap_remove_stale(fd);
+       }
+
+       return fp;
+}
+
+FILE *fopen(const char *name, const char *mode)
+{
+       return swrap_fopen(name, mode);
+}
+
 /****************************************************************************
  *   OPEN
  ***************************************************************************/
@@ -2681,19 +3136,25 @@ int open(const char *pathname, int flags, ...)
 static int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
 {
        struct socket_info *si = find_socket_info(s);
+       socklen_t len;
 
        if (!si) {
                return libc_getpeername(s, name, addrlen);
        }
 
-       if (!si->peername)
+       if (si->peername.sa_socklen == 0)
        {
                errno = ENOTCONN;
                return -1;
        }
 
-       memcpy(name, si->peername, si->peername_len);
-       *addrlen = si->peername_len;
+       len = MIN(*addrlen, si->peername.sa_socklen);
+       if (len == 0) {
+               return 0;
+       }
+
+       memcpy(name, &si->peername.sa.ss, len);
+       *addrlen = si->peername.sa_socklen;
 
        return 0;
 }
@@ -2714,13 +3175,19 @@ int getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
 static int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
 {
        struct socket_info *si = find_socket_info(s);
+       socklen_t len;
 
        if (!si) {
                return libc_getsockname(s, name, addrlen);
        }
 
-       memcpy(name, si->myname, si->myname_len);
-       *addrlen = si->myname_len;
+       len = MIN(*addrlen, si->myname.sa_socklen);
+       if (len == 0) {
+               return 0;
+       }
+
+       memcpy(name, &si->myname.sa.ss, len);
+       *addrlen = si->myname.sa_socklen;
 
        return 0;
 }
@@ -2738,6 +3205,12 @@ int getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
  *   GETSOCKOPT
  ***************************************************************************/
 
+#ifndef SO_PROTOCOL
+# ifdef SO_PROTOTYPE /* The Solaris name */
+#  define SO_PROTOCOL SO_PROTOTYPE
+# endif /* SO_PROTOTYPE */
+#endif /* SO_PROTOCOL */
+
 static int swrap_getsockopt(int s, int level, int optname,
                            void *optval, socklen_t *optlen)
 {
@@ -2752,11 +3225,49 @@ static int swrap_getsockopt(int s, int level, int optname,
        }
 
        if (level == SOL_SOCKET) {
-               return libc_getsockopt(s,
-                                      level,
-                                      optname,
-                                      optval,
-                                      optlen);
+               switch (optname) {
+#ifdef SO_DOMAIN
+               case SO_DOMAIN:
+                       if (optval == NULL || optlen == NULL ||
+                           *optlen < (socklen_t)sizeof(int)) {
+                               errno = EINVAL;
+                               return -1;
+                       }
+
+                       *optlen = sizeof(int);
+                       *(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)) {
+                               errno = EINVAL;
+                               return -1;
+                       }
+
+                       *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)) {
+                               errno = EINVAL;
+                               return -1;
+                       }
+
+                       *optlen = sizeof(int);
+                       *(int *)optval = si->type;
+                       return 0;
+               default:
+                       return libc_getsockopt(s,
+                                              level,
+                                              optname,
+                                              optval,
+                                              optlen);
+               }
        }
 
        errno = ENOPROTOOPT;
@@ -2799,9 +3310,23 @@ static int swrap_setsockopt(int s, int level, int optname,
 
        switch (si->family) {
        case AF_INET:
+               if (level == IPPROTO_IP) {
+#ifdef IP_PKTINFO
+                       if (optname == IP_PKTINFO) {
+                               si->pktinfo = AF_INET;
+                       }
+#endif /* IP_PKTINFO */
+               }
                return 0;
 #ifdef HAVE_IPV6
        case AF_INET6:
+               if (level == IPPROTO_IPV6) {
+#ifdef IPV6_RECVPKTINFO
+                       if (optname == IPV6_RECVPKTINFO) {
+                               si->pktinfo = AF_INET6;
+                       }
+#endif /* IPV6_PKTINFO */
+               }
                return 0;
 #endif
        default:
@@ -2840,9 +3365,9 @@ static int swrap_vioctl(int s, unsigned long int r, va_list va)
                value = *((int *)va_arg(ap, int *));
 
                if (rc == -1 && errno != EAGAIN && errno != ENOBUFS) {
-                       swrap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
+                       swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
                } else if (value == 0) { /* END OF FILE */
-                       swrap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
+                       swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
                }
                break;
        }
@@ -2870,6 +3395,282 @@ int ioctl(int s, unsigned long int r, ...)
        return rc;
 }
 
+/*****************
+ * CMSG
+ *****************/
+
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+
+#ifndef CMSG_ALIGN
+# ifdef _ALIGN /* BSD */
+#define CMSG_ALIGN _ALIGN
+# else
+#define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1))
+# endif /* _ALIGN */
+#endif /* CMSG_ALIGN */
+
+/**
+ * @brief Add a cmsghdr to a msghdr.
+ *
+ * This is an function to add any type of cmsghdr. It will operate on the
+ * msg->msg_control and msg->msg_controllen you pass in by adapting them to
+ * the buffer position after the added cmsg element. Hence, this function is
+ * intended to be used with an intermediate msghdr and not on the original
+ * one handed in by the client.
+ *
+ * @param[in]  msg      The msghdr to which to add the cmsg.
+ *
+ * @param[in]  level    The cmsg level to set.
+ *
+ * @param[in]  type     The cmsg type to set.
+ *
+ * @param[in]  data     The cmsg data to set.
+ *
+ * @param[in]  len      the length of the data to set.
+ */
+static void swrap_msghdr_add_cmsghdr(struct msghdr *msg,
+                                    int level,
+                                    int type,
+                                    const void *data,
+                                    size_t len)
+{
+       size_t cmlen = CMSG_LEN(len);
+       size_t cmspace = CMSG_SPACE(len);
+       uint8_t cmbuf[cmspace];
+       void *cast_ptr = (void *)cmbuf;
+       struct cmsghdr *cm = (struct cmsghdr *)cast_ptr;
+       uint8_t *p;
+
+       memset(cmbuf, 0, cmspace);
+
+       if (msg->msg_controllen < cmlen) {
+               cmlen = msg->msg_controllen;
+               msg->msg_flags |= MSG_CTRUNC;
+       }
+
+       if (msg->msg_controllen < cmspace) {
+               cmspace = msg->msg_controllen;
+       }
+
+       /*
+        * We copy the full input data into an intermediate cmsghdr first
+        * in order to more easily cope with truncation.
+        */
+       cm->cmsg_len = cmlen;
+       cm->cmsg_level = level;
+       cm->cmsg_type = type;
+       memcpy(CMSG_DATA(cm), data, len);
+
+       /*
+        * We now copy the possibly truncated buffer.
+        * We copy cmlen bytes, but consume cmspace bytes,
+        * leaving the possible padding uninitialiazed.
+        */
+       p = (uint8_t *)msg->msg_control;
+       memcpy(p, cm, cmlen);
+       p += cmspace;
+       msg->msg_control = p;
+       msg->msg_controllen -= cmspace;
+
+       return;
+}
+
+static int swrap_msghdr_add_pktinfo(struct socket_info *si,
+                                   struct msghdr *msg)
+{
+       /* Add packet info */
+       switch (si->pktinfo) {
+#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)
+               struct in_pktinfo pkt;
+#elif defined(IP_RECVDSTADDR)
+               struct in_addr pkt;
+#endif
+
+               if (si->bindname.sa_socklen == sizeof(struct sockaddr_in)) {
+                       sin = &si->bindname.sa.in;
+               } else {
+                       if (si->myname.sa_socklen != sizeof(struct sockaddr_in)) {
+                               return 0;
+                       }
+                       sin = &si->myname.sa.in;
+               }
+
+               ZERO_STRUCT(pkt);
+
+#if defined(HAVE_STRUCT_IN_PKTINFO)
+               pkt.ipi_ifindex = socket_wrapper_default_iface();
+               pkt.ipi_addr.s_addr = sin->sin_addr.s_addr;
+#elif defined(IP_RECVDSTADDR)
+               pkt = sin->sin_addr;
+#endif
+
+               swrap_msghdr_add_cmsghdr(msg, IPPROTO_IP, IP_PKTINFO,
+                                        &pkt, sizeof(pkt));
+
+               break;
+       }
+#endif /* IP_PKTINFO */
+#if defined(HAVE_IPV6)
+       case AF_INET6: {
+#if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO)
+               struct sockaddr_in6 *sin6;
+               struct in6_pktinfo pkt6;
+
+               if (si->bindname.sa_socklen == sizeof(struct sockaddr_in6)) {
+                       sin6 = &si->bindname.sa.in6;
+               } else {
+                       if (si->myname.sa_socklen != sizeof(struct sockaddr_in6)) {
+                               return 0;
+                       }
+                       sin6 = &si->myname.sa.in6;
+               }
+
+               ZERO_STRUCT(pkt6);
+
+               pkt6.ipi6_ifindex = socket_wrapper_default_iface();
+               pkt6.ipi6_addr = sin6->sin6_addr;
+
+               swrap_msghdr_add_cmsghdr(msg, IPPROTO_IPV6, IPV6_PKTINFO,
+                                       &pkt6, sizeof(pkt6));
+#endif /* HAVE_STRUCT_IN6_PKTINFO */
+
+               break;
+       }
+#endif /* IPV6_PKTINFO */
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
+static int swrap_msghdr_add_socket_info(struct socket_info *si,
+                                       struct msghdr *omsg)
+{
+       int rc = 0;
+
+       if (si->pktinfo > 0) {
+               rc = swrap_msghdr_add_pktinfo(si, omsg);
+       }
+
+       return rc;
+}
+
+static int swrap_sendmsg_copy_cmsg(struct cmsghdr *cmsg,
+                                  uint8_t **cm_data,
+                                  size_t *cm_data_space);
+static int swrap_sendmsg_filter_cmsg_socket(struct cmsghdr *cmsg,
+                                           uint8_t **cm_data,
+                                           size_t *cm_data_space);
+
+static int swrap_sendmsg_filter_cmsghdr(struct msghdr *msg,
+                                       uint8_t **cm_data,
+                                       size_t *cm_data_space) {
+       struct cmsghdr *cmsg;
+       int rc = -1;
+
+       /* Nothing to do */
+       if (msg->msg_controllen == 0 || msg->msg_control == NULL) {
+               return 0;
+       }
+
+       for (cmsg = CMSG_FIRSTHDR(msg);
+            cmsg != NULL;
+            cmsg = CMSG_NXTHDR(msg, cmsg)) {
+               switch (cmsg->cmsg_level) {
+               case IPPROTO_IP:
+                       rc = swrap_sendmsg_filter_cmsg_socket(cmsg,
+                                                             cm_data,
+                                                             cm_data_space);
+                       break;
+               default:
+                       rc = swrap_sendmsg_copy_cmsg(cmsg,
+                                                    cm_data,
+                                                    cm_data_space);
+                       break;
+               }
+       }
+
+       return rc;
+}
+
+static int swrap_sendmsg_copy_cmsg(struct cmsghdr *cmsg,
+                                  uint8_t **cm_data,
+                                  size_t *cm_data_space)
+{
+       size_t cmspace;
+       uint8_t *p;
+
+       cmspace =
+               (*cm_data_space) +
+               CMSG_SPACE(cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)));
+
+       p = realloc((*cm_data), cmspace);
+       if (p == NULL) {
+               return -1;
+       }
+       (*cm_data) = p;
+
+       p = (*cm_data) + (*cm_data_space);
+       *cm_data_space = cmspace;
+
+       memcpy(p, cmsg, cmsg->cmsg_len);
+
+       return 0;
+}
+
+static int swrap_sendmsg_filter_cmsg_pktinfo(struct cmsghdr *cmsg,
+                                           uint8_t **cm_data,
+                                           size_t *cm_data_space);
+
+
+static int swrap_sendmsg_filter_cmsg_socket(struct cmsghdr *cmsg,
+                                           uint8_t **cm_data,
+                                           size_t *cm_data_space)
+{
+       int rc = -1;
+
+       switch(cmsg->cmsg_type) {
+#ifdef IP_PKTINFO
+       case IP_PKTINFO:
+               rc = swrap_sendmsg_filter_cmsg_pktinfo(cmsg,
+                                                      cm_data,
+                                                      cm_data_space);
+               break;
+#endif
+#ifdef IPV6_PKTINFO
+       case IPV6_PKTINFO:
+               rc = swrap_sendmsg_filter_cmsg_pktinfo(cmsg,
+                                                      cm_data,
+                                                      cm_data_space);
+               break;
+#endif
+       default:
+               break;
+       }
+
+       return rc;
+}
+
+static int swrap_sendmsg_filter_cmsg_pktinfo(struct cmsghdr *cmsg,
+                                            uint8_t **cm_data,
+                                            size_t *cm_data_space)
+{
+       (void)cmsg; /* unused */
+       (void)cm_data; /* unused */
+       (void)cm_data_space; /* unused */
+
+       /*
+        * Passing a IP pktinfo to a unix socket might be rejected by the
+        * Kernel, at least on FreeBSD. So skip this cmsg.
+        */
+       return 0;
+}
+#endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
+
 static ssize_t swrap_sendmsg_before(int fd,
                                    struct socket_info *si,
                                    struct msghdr *msg,
@@ -2966,8 +3767,12 @@ static ssize_t swrap_sendmsg_before(int fd,
                        break;
                }
 
-               ret = sockaddr_convert_to_un(si, si->peername, si->peername_len,
-                                            tmp_un, 0, NULL);
+               ret = sockaddr_convert_to_un(si,
+                                            &si->peername.sa.s,
+                                            si->peername.sa_socklen,
+                                            tmp_un,
+                                            0,
+                                            NULL);
                if (ret == -1) return -1;
 
                ret = libc_connect(fd,
@@ -2990,6 +3795,28 @@ static ssize_t swrap_sendmsg_before(int fd,
                return -1;
        }
 
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+       if (msg->msg_controllen > 0 && msg->msg_control != NULL) {
+               uint8_t *cmbuf = NULL;
+               size_t cmlen = 0;
+
+               ret = swrap_sendmsg_filter_cmsghdr(msg, &cmbuf, &cmlen);
+               if (ret < 0) {
+                       free(cmbuf);
+                       return -1;
+               }
+
+               if (cmlen == 0) {
+                       msg->msg_controllen = 0;
+                       msg->msg_control = NULL;
+               } else if (cmlen < msg->msg_controllen && cmbuf != NULL) {
+                       memcpy(msg->msg_control, cmbuf, cmlen);
+                       msg->msg_controllen = cmlen;
+               }
+               free(cmbuf);
+       }
+#endif
+
        return 0;
 }
 
@@ -3047,22 +3874,22 @@ static void swrap_sendmsg_after(int fd,
        switch (si->type) {
        case SOCK_STREAM:
                if (ret == -1) {
-                       swrap_dump_packet(si, NULL, SWRAP_SEND, buf, len);
-                       swrap_dump_packet(si, NULL, SWRAP_SEND_RST, NULL, 0);
+                       swrap_pcap_dump_packet(si, NULL, SWRAP_SEND, buf, len);
+                       swrap_pcap_dump_packet(si, NULL, SWRAP_SEND_RST, NULL, 0);
                } else {
-                       swrap_dump_packet(si, NULL, SWRAP_SEND, buf, len);
+                       swrap_pcap_dump_packet(si, NULL, SWRAP_SEND, buf, len);
                }
                break;
 
        case SOCK_DGRAM:
                if (si->connected) {
-                       to = si->peername;
+                       to = &si->peername.sa.s;
                }
                if (ret == -1) {
-                       swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
-                       swrap_dump_packet(si, to, SWRAP_SENDTO_UNREACH, buf, len);
+                       swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+                       swrap_pcap_dump_packet(si, to, SWRAP_SENDTO_UNREACH, buf, len);
                } else {
-                       swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+                       swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
                }
                break;
        }
@@ -3155,10 +3982,11 @@ static int swrap_recvmsg_after(int fd,
 {
        int saved_errno = errno;
        size_t i;
-       uint8_t *buf;
+       uint8_t *buf = NULL;
        off_t ofs = 0;
        size_t avail = 0;
        size_t remain;
+       int rc;
 
        /* to give better errors */
        if (ret == -1) {
@@ -3175,8 +4003,8 @@ static int swrap_recvmsg_after(int fd,
        }
 
        if (avail == 0) {
-               errno = saved_errno;
-               return 0;
+               rc = 0;
+               goto done;
        }
 
        if (ret == -1) {
@@ -3187,7 +4015,7 @@ static int swrap_recvmsg_after(int fd,
 
        /* we capture it as one single packet */
        buf = (uint8_t *)malloc(remain);
-       if (!buf) {
+       if (buf == NULL) {
                /* we just not capture the packet */
                errno = saved_errno;
                return -1;
@@ -3205,11 +4033,11 @@ static int swrap_recvmsg_after(int fd,
        switch (si->type) {
        case SOCK_STREAM:
                if (ret == -1 && saved_errno != EAGAIN && saved_errno != ENOBUFS) {
-                       swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
+                       swrap_pcap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
                } else if (ret == 0) { /* END OF FILE */
-                       swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
+                       swrap_pcap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
                } else if (ret > 0) {
-                       swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
+                       swrap_pcap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
                }
                break;
 
@@ -3219,8 +4047,6 @@ static int swrap_recvmsg_after(int fd,
                }
 
                if (un_addr != NULL) {
-                       int rc;
-
                        rc = sockaddr_convert_from_un(si,
                                                      un_addr,
                                                      un_addrlen,
@@ -3228,16 +4054,16 @@ static int swrap_recvmsg_after(int fd,
                                                      msg->msg_name,
                                                      &msg->msg_namelen);
                        if (rc == -1) {
-                               return -1;
+                               goto done;
                        }
 
-                       swrap_dump_packet(si,
+                       swrap_pcap_dump_packet(si,
                                          msg->msg_name,
                                          SWRAP_RECVFROM,
                                          buf,
                                          ret);
                } else {
-                       swrap_dump_packet(si,
+                       swrap_pcap_dump_packet(si,
                                          msg->msg_name,
                                          SWRAP_RECV,
                                          buf,
@@ -3247,9 +4073,23 @@ static int swrap_recvmsg_after(int fd,
                break;
        }
 
+       rc = 0;
+done:
        free(buf);
        errno = saved_errno;
-       return 0;
+
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+       if (rc == 0 &&
+           msg->msg_controllen > 0 &&
+           msg->msg_control != NULL) {
+               rc = swrap_msghdr_add_socket_info(si, msg);
+               if (rc < 0) {
+                       return -1;
+               }
+       }
+#endif
+
+       return rc;
 }
 
 /****************************************************************************
@@ -3259,12 +4099,14 @@ static int swrap_recvmsg_after(int fd,
 static ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags,
                              struct sockaddr *from, socklen_t *fromlen)
 {
-       struct sockaddr_un from_addr;
-       socklen_t from_addrlen = sizeof(from_addr);
+       struct swrap_address from_addr = {
+               .sa_socklen = sizeof(struct sockaddr_un),
+       };
        ssize_t ret;
        struct socket_info *si = find_socket_info(s);
-       struct sockaddr_storage ss;
-       socklen_t ss_len = sizeof(ss);
+       struct swrap_address saddr = {
+               .sa_socklen = sizeof(struct sockaddr_storage),
+       };
        struct msghdr msg;
        struct iovec tmp;
        int tret;
@@ -3286,8 +4128,8 @@ static ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags,
                msg.msg_name = from;   /* optional address */
                msg.msg_namelen = *fromlen; /* size of address */
        } else {
-               msg.msg_name = (struct sockaddr *)(void *)&ss; /* optional address */
-               msg.msg_namelen = ss_len; /* size of address */
+               msg.msg_name = &saddr.sa.s; /* optional address */
+               msg.msg_namelen = saddr.sa_socklen; /* size of address */
        }
        msg.msg_iov = &tmp;            /* scatter/gather array */
        msg.msg_iovlen = 1;            /* # elements in msg_iov */
@@ -3305,14 +4147,12 @@ static ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags,
        buf = msg.msg_iov[0].iov_base;
        len = msg.msg_iov[0].iov_len;
 
-       /* irix 6.4 forgets to null terminate the sun_path string :-( */
-       memset(&from_addr, 0, sizeof(from_addr));
        ret = libc_recvfrom(s,
                            buf,
                            len,
                            flags,
-                           (struct sockaddr *)(void *)&from_addr,
-                           &from_addrlen);
+                           &from_addr.sa.s,
+                           &from_addr.sa_socklen);
        if (ret == -1) {
                return ret;
        }
@@ -3320,8 +4160,8 @@ static ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags,
        tret = swrap_recvmsg_after(s,
                                   si,
                                   &msg,
-                                  &from_addr,
-                                  from_addrlen,
+                                  &from_addr.sa.un,
+                                  from_addr.sa_socklen,
                                   ret);
        if (tret != 0) {
                return tret;
@@ -3354,7 +4194,9 @@ static ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags,
 {
        struct msghdr msg;
        struct iovec tmp;
-       struct sockaddr_un un_addr;
+       struct swrap_address un_addr = {
+               .sa_socklen = sizeof(struct sockaddr_un),
+       };
        const struct sockaddr_un *to_un = NULL;
        ssize_t ret;
        int rc;
@@ -3379,7 +4221,14 @@ static ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags,
        msg.msg_flags = 0;             /* flags on received message */
 #endif
 
-       rc = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, &to_un, &to, &bcast);
+       rc = swrap_sendmsg_before(s,
+                                 si,
+                                 &msg,
+                                 &tmp,
+                                 &un_addr.sa.un,
+                                 &to_un,
+                                 &to,
+                                 &bcast);
        if (rc < 0) {
                return -1;
        }
@@ -3396,20 +4245,22 @@ static ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags,
                type = SOCKET_TYPE_CHAR_UDP;
 
                for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
-                       snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
+                       snprintf(un_addr.sa.un.sun_path,
+                                sizeof(un_addr.sa.un.sun_path),
+                                "%s/"SOCKET_FORMAT,
                                 socket_wrapper_dir(), type, iface, prt);
-                       if (stat(un_addr.sun_path, &st) != 0) continue;
+                       if (stat(un_addr.sa.un.sun_path, &st) != 0) continue;
 
                        /* ignore the any errors in broadcast sends */
                        libc_sendto(s,
                                    buf,
                                    len,
                                    flags,
-                                   (struct sockaddr *)(void *)&un_addr,
-                                   sizeof(un_addr));
+                                   &un_addr.sa.s,
+                                   un_addr.sa_socklen);
                }
 
-               swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+               swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
 
                return len;
        }
@@ -3440,8 +4291,9 @@ static ssize_t swrap_recv(int s, void *buf, size_t len, int flags)
 {
        struct socket_info *si;
        struct msghdr msg;
-       struct sockaddr_storage ss;
-       socklen_t ss_len = sizeof(ss);
+       struct swrap_address saddr = {
+               .sa_socklen = sizeof(struct sockaddr_storage),
+       };
        struct iovec tmp;
        ssize_t ret;
        int tret;
@@ -3455,8 +4307,8 @@ static ssize_t swrap_recv(int s, void *buf, size_t len, int flags)
        tmp.iov_len = len;
 
        ZERO_STRUCT(msg);
-       msg.msg_name = (struct sockaddr *)(void *)&ss; /* optional address */
-       msg.msg_namelen = ss_len;      /* size of address */
+       msg.msg_name = &saddr.sa.s;    /* optional address */
+       msg.msg_namelen = saddr.sa_socklen; /* size of address */
        msg.msg_iov = &tmp;            /* scatter/gather array */
        msg.msg_iovlen = 1;            /* # elements in msg_iov */
 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
@@ -3497,8 +4349,9 @@ static ssize_t swrap_read(int s, void *buf, size_t len)
        struct socket_info *si;
        struct msghdr msg;
        struct iovec tmp;
-       struct sockaddr_storage ss;
-       socklen_t ss_len = sizeof(ss);
+       struct swrap_address saddr = {
+               .sa_socklen = sizeof(struct sockaddr_storage),
+       };
        ssize_t ret;
        int tret;
 
@@ -3511,8 +4364,8 @@ static ssize_t swrap_read(int s, void *buf, size_t len)
        tmp.iov_len = len;
 
        ZERO_STRUCT(msg);
-       msg.msg_name = (struct sockaddr *)(void *)&ss; /* optional address */
-       msg.msg_namelen = ss_len;      /* size of address */
+       msg.msg_name = &saddr.sa.ss;   /* optional address */
+       msg.msg_namelen = saddr.sa_socklen; /* size of address */
        msg.msg_iov = &tmp;            /* scatter/gather array */
        msg.msg_iovlen = 1;            /* # elements in msg_iov */
 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
@@ -3604,11 +4457,16 @@ ssize_t send(int s, const void *buf, size_t len, int flags)
 
 static ssize_t swrap_recvmsg(int s, struct msghdr *omsg, int flags)
 {
-       struct sockaddr_un from_addr;
-       socklen_t from_addrlen = sizeof(from_addr);
+       struct swrap_address from_addr = {
+               .sa_socklen = sizeof(struct sockaddr_un),
+       };
        struct socket_info *si;
        struct msghdr msg;
        struct iovec tmp;
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+       size_t msg_ctrllen_filled;
+       size_t msg_ctrllen_left;
+#endif
 
        ssize_t ret;
        int rc;
@@ -3622,11 +4480,14 @@ static ssize_t swrap_recvmsg(int s, struct msghdr *omsg, int flags)
        tmp.iov_len = 0;
 
        ZERO_STRUCT(msg);
-       msg.msg_name = (struct sockaddr *)&from_addr; /* optional address */
-       msg.msg_namelen = from_addrlen;            /* size of address */
+       msg.msg_name = &from_addr.sa;              /* optional address */
+       msg.msg_namelen = from_addr.sa_socklen;    /* size of address */
        msg.msg_iov = omsg->msg_iov;               /* scatter/gather array */
        msg.msg_iovlen = omsg->msg_iovlen;         /* # elements in msg_iov */
 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+       msg_ctrllen_filled = 0;
+       msg_ctrllen_left = omsg->msg_controllen;
+
        msg.msg_control = omsg->msg_control;       /* ancillary data, see below */
        msg.msg_controllen = omsg->msg_controllen; /* ancillary data buffer len */
        msg.msg_flags = omsg->msg_flags;           /* flags on received message */
@@ -3639,11 +4500,50 @@ static ssize_t swrap_recvmsg(int s, struct msghdr *omsg, int flags)
 
        ret = libc_recvmsg(s, &msg, flags);
 
-       rc = swrap_recvmsg_after(s, si, omsg, &from_addr, from_addrlen, ret);
+       msg.msg_name = omsg->msg_name;
+       msg.msg_namelen = omsg->msg_namelen;
+
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+       msg_ctrllen_filled += msg.msg_controllen;
+       msg_ctrllen_left -= msg.msg_controllen;
+
+       if (omsg->msg_control != NULL) {
+               uint8_t *p;
+
+               p = omsg->msg_control;
+               p += msg_ctrllen_filled;
+
+               msg.msg_control = p;
+               msg.msg_controllen = msg_ctrllen_left;
+       } else {
+               msg.msg_control = NULL;
+               msg.msg_controllen = 0;
+       }
+#endif
+
+       rc = swrap_recvmsg_after(s,
+                                si,
+                                &msg,
+                                &from_addr.sa.un,
+                                from_addr.sa_socklen,
+                                ret);
        if (rc != 0) {
                return rc;
        }
 
+#ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
+       if (omsg->msg_control != NULL) {
+               /* msg.msg_controllen = space left */
+               msg_ctrllen_left = msg.msg_controllen;
+               msg_ctrllen_filled = omsg->msg_controllen - msg_ctrllen_left;
+       }
+
+       /* Update the original message length */
+       omsg->msg_controllen = msg_ctrllen_filled;
+       omsg->msg_flags = msg.msg_flags;
+#endif
+       omsg->msg_iovlen = msg.msg_iovlen;
+
        return ret;
 }
 
@@ -3683,8 +4583,15 @@ static ssize_t swrap_sendmsg(int s, const struct msghdr *omsg, int flags)
        msg.msg_iov = omsg->msg_iov;               /* scatter/gather array */
        msg.msg_iovlen = omsg->msg_iovlen;         /* # elements in msg_iov */
 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
-       msg.msg_control = omsg->msg_control;       /* ancillary data, see below */
-       msg.msg_controllen = omsg->msg_controllen; /* ancillary data buffer len */
+       if (msg.msg_controllen > 0 && msg.msg_control != NULL) {
+               /* omsg is a const so use a local buffer for modifications */
+               uint8_t cmbuf[omsg->msg_controllen];
+
+               memcpy(cmbuf, omsg->msg_control, omsg->msg_controllen);
+
+               msg.msg_control = cmbuf;       /* ancillary data, see below */
+               msg.msg_controllen = omsg->msg_controllen; /* ancillary data buffer len */
+       }
        msg.msg_flags = omsg->msg_flags;           /* flags on received message */
 #endif
 
@@ -3740,7 +4647,7 @@ static ssize_t swrap_sendmsg(int s, const struct msghdr *omsg, int flags)
                        libc_sendmsg(s, &msg, flags);
                }
 
-               swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+               swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
                free(buf);
 
                return len;
@@ -3767,8 +4674,9 @@ static ssize_t swrap_readv(int s, const struct iovec *vector, int count)
        struct socket_info *si;
        struct msghdr msg;
        struct iovec tmp;
-       struct sockaddr_storage ss;
-       socklen_t ss_len = sizeof(ss);
+       struct swrap_address saddr = {
+               .sa_socklen = sizeof(struct sockaddr_storage)
+       };
        ssize_t ret;
        int rc;
 
@@ -3781,8 +4689,8 @@ static ssize_t swrap_readv(int s, const struct iovec *vector, int count)
        tmp.iov_len = 0;
 
        ZERO_STRUCT(msg);
-       msg.msg_name = (struct sockaddr *)(void *)&ss; /* optional address */
-       msg.msg_namelen = ss_len;      /* size of address */
+       msg.msg_name = &saddr.sa.s; /* optional address */
+       msg.msg_namelen = saddr.sa_socklen;      /* size of address */
        msg.msg_iov = discard_const_p(struct iovec, vector); /* scatter/gather array */
        msg.msg_iovlen = count;        /* # elements in msg_iov */
 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
@@ -3894,22 +4802,19 @@ static int swrap_close(int fd)
 
        SWRAP_DLIST_REMOVE(sockets, si);
 
-       if (si->myname && si->peername) {
-               swrap_dump_packet(si, NULL, SWRAP_CLOSE_SEND, NULL, 0);
+       if (si->myname.sa_socklen > 0 && si->peername.sa_socklen > 0) {
+               swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_SEND, NULL, 0);
        }
 
        ret = libc_close(fd);
 
-       if (si->myname && si->peername) {
-               swrap_dump_packet(si, NULL, SWRAP_CLOSE_RECV, NULL, 0);
-               swrap_dump_packet(si, NULL, SWRAP_CLOSE_ACK, NULL, 0);
+       if (si->myname.sa_socklen > 0 && si->peername.sa_socklen > 0) {
+               swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_RECV, NULL, 0);
+               swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_ACK, NULL, 0);
        }
 
-       if (si->myname) free(si->myname);
-       if (si->peername) free(si->peername);
-       if (si->tmp_path) {
-               unlink(si->tmp_path);
-               free(si->tmp_path);
+       if (si->un_addr.sun_path[0] != '\0') {
+               unlink(si->un_addr.sun_path);
        }
        free(si);