s4:auth Move struct auth_usersupplied_info to a common location
[samba.git] / lib / socket_wrapper / socket_wrapper.c
index e8d27adc37fd8487a128c675aff582e009cc11c7..9d732ee65299d7e18d7e9222c11776f1e7329eab 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) Jelmer Vernooij 2005,2008 <jelmer@samba.org>
- * Copyright (C) Stefan Metzmacher 2006 <metze@samba.org>
+ * Copyright (C) Stefan Metzmacher 2006-2009 <metze@samba.org>
  *
  * All rights reserved.
  * 
 #define real_setsockopt setsockopt
 #define real_recvfrom recvfrom
 #define real_sendto sendto
+#define real_sendmsg sendmsg
 #define real_ioctl ioctl
 #define real_recv recv
+#define real_read read
 #define real_send send
+#define real_readv readv
+#define real_writev writev
 #define real_socket socket
 #define real_close close
 #endif
 
 #define MAX_WRAPPED_INTERFACES 16
 
-#define SW_IPV6_ADDRESS 1
+#ifdef HAVE_IPV6
+/*
+ * FD00::5357:5FXX
+ */
+static const struct in6_addr *swrap_ipv6(void)
+{
+       static struct in6_addr v;
+       static int initialized;
+       int ret;
+
+       if (initialized) {
+               return &v;
+       }
+       initialized = 1;
+
+       ret = inet_pton(AF_INET6, "FD00::5357:5F00", &v);
+       if (ret <= 0) {
+               abort();
+       }
+
+       return &v;
+}
+#endif
 
 static struct sockaddr *sockaddr_dup(const void *data, socklen_t len)
 {
@@ -193,6 +219,8 @@ struct socket_info
        int bound;
        int bcast;
        int is_server;
+       int connected;
+       int defer_connect;
 
        char *path;
        char *tmp_path;
@@ -295,7 +323,8 @@ static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, sock
 
                memset(in2, 0, sizeof(*in2));
                in2->sin6_family = AF_INET6;
-               in2->sin6_addr.s6_addr[0] = SW_IPV6_ADDRESS;
+               in2->sin6_addr = *swrap_ipv6();
+               in2->sin6_addr.s6_addr[15] = iface;
                in2->sin6_port = htons(prt);
 
                *len = sizeof(*in2);
@@ -320,7 +349,7 @@ static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *i
 
        if (bcast) *bcast = 0;
 
-       switch (si->family) {
+       switch (inaddr->sa_family) {
        case AF_INET: {
                const struct sockaddr_in *in = 
                    (const struct sockaddr_in *)inaddr;
@@ -367,6 +396,7 @@ static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *i
        case AF_INET6: {
                const struct sockaddr_in6 *in = 
                    (const struct sockaddr_in6 *)inaddr;
+               struct in6_addr cmp;
 
                switch (si->type) {
                case SOCK_STREAM:
@@ -380,8 +410,16 @@ static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *i
                /* XXX no multicast/broadcast */
 
                prt = ntohs(in->sin6_port);
-               iface = SW_IPV6_ADDRESS;
-               
+
+               cmp = in->sin6_addr;
+               cmp.s6_addr[15] = 0;
+               if (IN6_ARE_ADDR_EQUAL(swrap_ipv6(), &cmp)) {
+                       iface = in->sin6_addr.s6_addr[15];
+               } else {
+                       errno = ENETUNREACH;
+                       return -1;
+               }
+
                break;
        }
 #endif
@@ -474,6 +512,7 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
        case AF_INET6: {
                const struct sockaddr_in6 *in = 
                    (const struct sockaddr_in6 *)inaddr;
+               struct in6_addr cmp;
 
                switch (si->type) {
                case SOCK_STREAM:
@@ -487,13 +526,23 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
                /* XXX no multicast/broadcast */
 
                prt = ntohs(in->sin6_port);
-               iface = SW_IPV6_ADDRESS;
-               
+
+               cmp = in->sin6_addr;
+               cmp.s6_addr[15] = 0;
+               if (IN6_IS_ADDR_UNSPECIFIED(&in->sin6_addr)) {
+                       iface = socket_wrapper_default_iface();
+               } else if (IN6_ARE_ADDR_EQUAL(swrap_ipv6(), &cmp)) {
+                       iface = in->sin6_addr.s6_addr[15];
+               } else {
+                       errno = EADDRNOTAVAIL;
+                       return -1;
+               }
+
                break;
        }
 #endif
        default:
-               errno = ENETUNREACH;
+               errno = EADDRNOTAVAIL;
                return -1;
        }
 
@@ -621,7 +670,7 @@ enum swrap_packet_type {
        SWRAP_SEND_RST,
        SWRAP_CLOSE_SEND,
        SWRAP_CLOSE_RECV,
-       SWRAP_CLOSE_ACK
+       SWRAP_CLOSE_ACK,
 };
 
 struct swrap_file_hdr {
@@ -636,69 +685,93 @@ struct swrap_file_hdr {
 };
 #define SWRAP_FILE_HDR_SIZE 24
 
-struct swrap_packet {
+struct swrap_packet_frame {
+       uint32_t seconds;
+       uint32_t micro_seconds;
+       uint32_t recorded_length;
+       uint32_t full_length;
+};
+#define SWRAP_PACKET_FRAME_SIZE 16
+
+union swrap_packet_ip {
+       struct {
+               uint8_t         ver_hdrlen;
+               uint8_t         tos;
+               uint16_t        packet_length;
+               uint16_t        identification;
+               uint8_t         flags;
+               uint8_t         fragment;
+               uint8_t         ttl;
+               uint8_t         protocol;
+               uint16_t        hdr_checksum;
+               uint32_t        src_addr;
+               uint32_t        dest_addr;
+       } v4;
+#define SWRAP_PACKET_IP_V4_SIZE 20
        struct {
-               uint32_t seconds;
-               uint32_t micro_seconds;
-               uint32_t recorded_length;
-               uint32_t full_length;
-       } frame;
-#define SWRAP_PACKET__FRAME_SIZE 16
+               uint8_t         ver_prio;
+               uint8_t         flow_label_high;
+               uint16_t        flow_label_low;
+               uint16_t        payload_length;
+               uint8_t         next_header;
+               uint8_t         hop_limit;
+               uint8_t         src_addr[16];
+               uint8_t         dest_addr[16];
+       } v6;
+#define SWRAP_PACKET_IP_V6_SIZE 40
+};
+#define SWRAP_PACKET_IP_SIZE 40
 
+union swrap_packet_payload {
+       struct {
+               uint16_t        source_port;
+               uint16_t        dest_port;
+               uint32_t        seq_num;
+               uint32_t        ack_num;
+               uint8_t         hdr_length;
+               uint8_t         control;
+               uint16_t        window;
+               uint16_t        checksum;
+               uint16_t        urg;
+       } tcp;
+#define SWRAP_PACKET_PAYLOAD_TCP_SIZE 20
        struct {
-               struct {
-                       uint8_t         ver_hdrlen;
-                       uint8_t         tos;
-                       uint16_t        packet_length;
-                       uint16_t        identification;
-                       uint8_t         flags;
-                       uint8_t         fragment;
-                       uint8_t         ttl;
-                       uint8_t         protocol;
-                       uint16_t        hdr_checksum;
-                       uint32_t        src_addr;
-                       uint32_t        dest_addr;
-               } hdr;
-#define SWRAP_PACKET__IP_HDR_SIZE 20
-
-               union {
-                       struct {
-                               uint16_t        source_port;
-                               uint16_t        dest_port;
-                               uint32_t        seq_num;
-                               uint32_t        ack_num;
-                               uint8_t         hdr_length;
-                               uint8_t         control;
-                               uint16_t        window;
-                               uint16_t        checksum;
-                               uint16_t        urg;
-                       } tcp;
-#define SWRAP_PACKET__IP_P_TCP_SIZE 20
-                       struct {
-                               uint16_t        source_port;
-                               uint16_t        dest_port;
-                               uint16_t        length;
-                               uint16_t        checksum;
-                       } udp;
-#define SWRAP_PACKET__IP_P_UDP_SIZE 8
-                       struct {
-                               uint8_t         type;
-                               uint8_t         code;
-                               uint16_t        checksum;
-                               uint32_t        unused;
-                       } icmp;
-#define SWRAP_PACKET__IP_P_ICMP_SIZE 8
-               } p;
-       } ip;
+               uint16_t        source_port;
+               uint16_t        dest_port;
+               uint16_t        length;
+               uint16_t        checksum;
+       } udp;
+#define SWRAP_PACKET_PAYLOAD_UDP_SIZE 8
+       struct {
+               uint8_t         type;
+               uint8_t         code;
+               uint16_t        checksum;
+               uint32_t        unused;
+       } icmp4;
+#define SWRAP_PACKET_PAYLOAD_ICMP4_SIZE 8
+       struct {
+               uint8_t         type;
+               uint8_t         code;
+               uint16_t        checksum;
+               uint32_t        unused;
+       } icmp6;
+#define SWRAP_PACKET_PAYLOAD_ICMP6_SIZE 8
 };
-#define SWRAP_PACKET_SIZE 56
+#define SWRAP_PACKET_PAYLOAD_SIZE 20
+
+#define SWRAP_PACKET_MIN_ALLOC \
+       (SWRAP_PACKET_FRAME_SIZE + \
+        SWRAP_PACKET_IP_SIZE + \
+        SWRAP_PACKET_PAYLOAD_SIZE)
 
 static const char *socket_wrapper_pcap_file(void)
 {
        static int initialized = 0;
        static const char *s = NULL;
-       static const struct swrap_file_hdr h = { 0, };
-       static const struct swrap_packet p = { { 0, }, { { 0, }, { { 0, } } } };
+       static const struct swrap_file_hdr h;
+       static const struct swrap_packet_frame f;
+       static const union swrap_packet_ip i;
+       static const union swrap_packet_payload p;
 
        if (initialized == 1) {
                return s;
@@ -715,22 +788,31 @@ static const char *socket_wrapper_pcap_file(void)
        if (sizeof(h) != SWRAP_FILE_HDR_SIZE) {
                return NULL;
        }
-       if (sizeof(p) != SWRAP_PACKET_SIZE) {
+       if (sizeof(f) != SWRAP_PACKET_FRAME_SIZE) {
+               return NULL;
+       }
+       if (sizeof(i) != SWRAP_PACKET_IP_SIZE) {
+               return NULL;
+       }
+       if (sizeof(i.v4) != SWRAP_PACKET_IP_V4_SIZE) {
+               return NULL;
+       }
+       if (sizeof(i.v6) != SWRAP_PACKET_IP_V6_SIZE) {
                return NULL;
        }
-       if (sizeof(p.frame) != SWRAP_PACKET__FRAME_SIZE) {
+       if (sizeof(p) != SWRAP_PACKET_PAYLOAD_SIZE) {
                return NULL;
        }
-       if (sizeof(p.ip.hdr) != SWRAP_PACKET__IP_HDR_SIZE) {
+       if (sizeof(p.tcp) != SWRAP_PACKET_PAYLOAD_TCP_SIZE) {
                return NULL;
        }
-       if (sizeof(p.ip.p.tcp) != SWRAP_PACKET__IP_P_TCP_SIZE) {
+       if (sizeof(p.udp) != SWRAP_PACKET_PAYLOAD_UDP_SIZE) {
                return NULL;
        }
-       if (sizeof(p.ip.p.udp) != SWRAP_PACKET__IP_P_UDP_SIZE) {
+       if (sizeof(p.icmp4) != SWRAP_PACKET_PAYLOAD_ICMP4_SIZE) {
                return NULL;
        }
-       if (sizeof(p.ip.p.icmp) != SWRAP_PACKET__IP_P_ICMP_SIZE) {
+       if (sizeof(p.icmp6) != SWRAP_PACKET_PAYLOAD_ICMP6_SIZE) {
                return NULL;
        }
 
@@ -744,41 +826,72 @@ static const char *socket_wrapper_pcap_file(void)
        return s;
 }
 
-static struct swrap_packet *swrap_packet_init(struct timeval *tval,
-                                             const struct sockaddr_in *src_addr,
-                                             const struct sockaddr_in *dest_addr,
-                                             int socket_type,
-                                             const unsigned char *payload,
-                                             size_t payload_len,
-                                             unsigned long tcp_seq,
-                                             unsigned long tcp_ack,
-                                             unsigned char tcp_ctl,
-                                             int unreachable,
-                                             size_t *_packet_len)
+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)
 {
-       struct swrap_packet *ret;
-       struct swrap_packet *packet;
+       uint8_t *base;
+       uint8_t *buf;
+       struct swrap_packet_frame *frame;
+       union swrap_packet_ip *ip;
+       union swrap_packet_payload *pay;
        size_t packet_len;
        size_t alloc_len;
-       size_t nonwire_len = sizeof(packet->frame);
+       size_t nonwire_len = sizeof(*frame);
        size_t wire_hdr_len = 0;
        size_t wire_len = 0;
+       size_t ip_hdr_len = 0;
        size_t icmp_hdr_len = 0;
        size_t icmp_truncate_len = 0;
-       unsigned char protocol = 0, icmp_protocol = 0;
-       unsigned short src_port = src_addr->sin_port;
-       unsigned short dest_port = dest_addr->sin_port;
+       uint8_t protocol = 0, icmp_protocol = 0;
+       const struct sockaddr_in *src_in = NULL;
+       const struct sockaddr_in *dest_in = NULL;
+#ifdef HAVE_IPV6
+       const struct sockaddr_in6 *src_in6 = NULL;
+       const struct sockaddr_in6 *dest_in6 = NULL;
+#endif
+       uint16_t src_port;
+       uint16_t dest_port;
+
+       switch (src->sa_family) {
+       case AF_INET:
+               src_in = (const struct sockaddr_in *)src;
+               dest_in = (const struct sockaddr_in *)dest;
+               src_port = src_in->sin_port;
+               dest_port = dest_in->sin_port;
+               ip_hdr_len = sizeof(ip->v4);
+               break;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               src_in6 = (const struct sockaddr_in6 *)src;
+               dest_in6 = (const struct sockaddr_in6 *)dest;
+               src_port = src_in6->sin6_port;
+               dest_port = dest_in6->sin6_port;
+               ip_hdr_len = sizeof(ip->v6);
+               break;
+#endif
+       default:
+               return NULL;
+       }
 
        switch (socket_type) {
        case SOCK_STREAM:
                protocol = 0x06; /* TCP */
-               wire_hdr_len = sizeof(packet->ip.hdr) + sizeof(packet->ip.p.tcp);
+               wire_hdr_len = ip_hdr_len + sizeof(pay->tcp);
                wire_len = wire_hdr_len + payload_len;
                break;
 
        case SOCK_DGRAM:
                protocol = 0x11; /* UDP */
-               wire_hdr_len = sizeof(packet->ip.hdr) + sizeof(packet->ip.p.udp);
+               wire_hdr_len = ip_hdr_len + sizeof(pay->udp);
                wire_len = wire_hdr_len + payload_len;
                break;
 
@@ -788,98 +901,160 @@ static struct swrap_packet *swrap_packet_init(struct timeval *tval,
 
        if (unreachable) {
                icmp_protocol = protocol;
-               protocol = 0x01; /* ICMP */
+               switch (src->sa_family) {
+               case AF_INET:
+                       protocol = 0x01; /* ICMPv4 */
+                       icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp4);
+                       break;
+#ifdef HAVE_IPV6
+               case AF_INET6:
+                       protocol = 0x3A; /* ICMPv6 */
+                       icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp6);
+                       break;
+#endif
+               }
                if (wire_len > 64 ) {
                        icmp_truncate_len = wire_len - 64;
                }
-               icmp_hdr_len = sizeof(packet->ip.hdr) + sizeof(packet->ip.p.icmp);
                wire_hdr_len += icmp_hdr_len;
                wire_len += icmp_hdr_len;
        }
 
        packet_len = nonwire_len + wire_len;
        alloc_len = packet_len;
-       if (alloc_len < sizeof(struct swrap_packet)) {
-               alloc_len = sizeof(struct swrap_packet);
-       }
-       ret = (struct swrap_packet *)malloc(alloc_len);
-       if (!ret) return NULL;
-
-       packet = ret;
-
-       packet->frame.seconds           = tval->tv_sec;
-       packet->frame.micro_seconds     = tval->tv_usec;
-       packet->frame.recorded_length   = wire_len - icmp_truncate_len;
-       packet->frame.full_length       = wire_len - icmp_truncate_len;
-
-       packet->ip.hdr.ver_hdrlen       = 0x45; /* version 4 and 5 * 32 bit words */
-       packet->ip.hdr.tos              = 0x00;
-       packet->ip.hdr.packet_length    = htons(wire_len - icmp_truncate_len);
-       packet->ip.hdr.identification   = htons(0xFFFF);
-       packet->ip.hdr.flags            = 0x40; /* BIT 1 set - means don't fraqment */
-       packet->ip.hdr.fragment         = htons(0x0000);
-       packet->ip.hdr.ttl              = 0xFF;
-       packet->ip.hdr.protocol         = protocol;
-       packet->ip.hdr.hdr_checksum     = htons(0x0000);
-       packet->ip.hdr.src_addr         = src_addr->sin_addr.s_addr;
-       packet->ip.hdr.dest_addr        = dest_addr->sin_addr.s_addr;
+       if (alloc_len < SWRAP_PACKET_MIN_ALLOC) {
+               alloc_len = SWRAP_PACKET_MIN_ALLOC;
+       }
+
+       base = (uint8_t *)malloc(alloc_len);
+       if (!base) return NULL;
+
+       buf = base;
+
+       frame = (struct swrap_packet_frame *)buf;
+       frame->seconds          = tval->tv_sec;
+       frame->micro_seconds    = tval->tv_usec;
+       frame->recorded_length  = wire_len - icmp_truncate_len;
+       frame->full_length      = wire_len - icmp_truncate_len;
+       buf += SWRAP_PACKET_FRAME_SIZE;
+
+       ip = (union swrap_packet_ip *)buf;
+       switch (src->sa_family) {
+       case AF_INET:
+               ip->v4.ver_hdrlen       = 0x45; /* version 4 and 5 * 32 bit words */
+               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.fragment         = htons(0x0000);
+               ip->v4.ttl              = 0xFF;
+               ip->v4.protocol         = protocol;
+               ip->v4.hdr_checksum     = htons(0x0000);
+               ip->v4.src_addr         = src_in->sin_addr.s_addr;
+               ip->v4.dest_addr        = dest_in->sin_addr.s_addr;
+               buf += SWRAP_PACKET_IP_V4_SIZE;
+               break;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               ip->v6.ver_prio         = 0x60; /* version 4 and 5 * 32 bit words */
+               ip->v6.flow_label_high  = 0x00;
+               ip->v6.flow_label_low   = 0x0000;
+               ip->v6.payload_length   = htons(wire_len - icmp_truncate_len);//TODO
+               ip->v6.next_header      = protocol;
+               memcpy(ip->v6.src_addr, src_in6->sin6_addr.s6_addr, 16);
+               memcpy(ip->v6.dest_addr, dest_in6->sin6_addr.s6_addr, 16);
+               buf += SWRAP_PACKET_IP_V6_SIZE;
+               break;
+#endif
+       }
 
        if (unreachable) {
-               packet->ip.p.icmp.type          = 0x03; /* destination unreachable */
-               packet->ip.p.icmp.code          = 0x01; /* host unreachable */
-               packet->ip.p.icmp.checksum      = htons(0x0000);
-               packet->ip.p.icmp.unused        = htonl(0x00000000);
-
-               /* set the ip header in the ICMP payload */
-               packet = (struct swrap_packet *)(((unsigned char *)ret) + icmp_hdr_len);
-               packet->ip.hdr.ver_hdrlen       = 0x45; /* version 4 and 5 * 32 bit words */
-               packet->ip.hdr.tos              = 0x00;
-               packet->ip.hdr.packet_length    = htons(wire_len - icmp_hdr_len);
-               packet->ip.hdr.identification   = htons(0xFFFF);
-               packet->ip.hdr.flags            = 0x40; /* BIT 1 set - means don't fraqment */
-               packet->ip.hdr.fragment         = htons(0x0000);
-               packet->ip.hdr.ttl              = 0xFF;
-               packet->ip.hdr.protocol         = icmp_protocol;
-               packet->ip.hdr.hdr_checksum     = htons(0x0000);
-               packet->ip.hdr.src_addr         = dest_addr->sin_addr.s_addr;
-               packet->ip.hdr.dest_addr        = src_addr->sin_addr.s_addr;
-
-               src_port = dest_addr->sin_port;
-               dest_port = src_addr->sin_port;
+               pay = (union swrap_packet_payload *)buf;
+               switch (src->sa_family) {
+               case AF_INET:
+                       pay->icmp4.type         = 0x03; /* destination unreachable */
+                       pay->icmp4.code         = 0x01; /* host unreachable */
+                       pay->icmp4.checksum     = htons(0x0000);
+                       pay->icmp4.unused       = htonl(0x00000000);
+                       buf += SWRAP_PACKET_PAYLOAD_ICMP4_SIZE;
+
+                       /* set the ip header in the ICMP payload */
+                       ip = (union swrap_packet_ip *)buf;
+                       ip->v4.ver_hdrlen       = 0x45; /* version 4 and 5 * 32 bit words */
+                       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.fragment         = htons(0x0000);
+                       ip->v4.ttl              = 0xFF;
+                       ip->v4.protocol         = icmp_protocol;
+                       ip->v4.hdr_checksum     = htons(0x0000);
+                       ip->v4.src_addr         = dest_in->sin_addr.s_addr;
+                       ip->v4.dest_addr        = src_in->sin_addr.s_addr;
+                       buf += SWRAP_PACKET_IP_V4_SIZE;
+
+                       src_port = dest_in->sin_port;
+                       dest_port = src_in->sin_port;
+                       break;
+#ifdef HAVE_IPV6
+               case AF_INET6:
+                       pay->icmp6.type         = 0x01; /* destination unreachable */
+                       pay->icmp6.code         = 0x03; /* address unreachable */
+                       pay->icmp6.checksum     = htons(0x0000);
+                       pay->icmp6.unused       = htonl(0x00000000);
+                       buf += SWRAP_PACKET_PAYLOAD_ICMP6_SIZE;
+
+                       /* set the ip header in the ICMP payload */
+                       ip = (union swrap_packet_ip *)buf;
+                       ip->v6.ver_prio         = 0x60; /* version 4 and 5 * 32 bit words */
+                       ip->v6.flow_label_high  = 0x00;
+                       ip->v6.flow_label_low   = 0x0000;
+                       ip->v6.payload_length   = htons(wire_len - icmp_truncate_len);//TODO
+                       ip->v6.next_header      = protocol;
+                       memcpy(ip->v6.src_addr, dest_in6->sin6_addr.s6_addr, 16);
+                       memcpy(ip->v6.dest_addr, src_in6->sin6_addr.s6_addr, 16);
+                       buf += SWRAP_PACKET_IP_V6_SIZE;
+
+                       src_port = dest_in6->sin6_port;
+                       dest_port = src_in6->sin6_port;
+                       break;
+#endif
+               }
        }
 
+       pay = (union swrap_packet_payload *)buf;
+
        switch (socket_type) {
        case SOCK_STREAM:
-               packet->ip.p.tcp.source_port    = src_port;
-               packet->ip.p.tcp.dest_port      = dest_port;
-               packet->ip.p.tcp.seq_num        = htonl(tcp_seq);
-               packet->ip.p.tcp.ack_num        = htonl(tcp_ack);
-               packet->ip.p.tcp.hdr_length     = 0x50; /* 5 * 32 bit words */
-               packet->ip.p.tcp.control        = tcp_ctl;
-               packet->ip.p.tcp.window         = htons(0x7FFF);
-               packet->ip.p.tcp.checksum       = htons(0x0000);
-               packet->ip.p.tcp.urg            = htons(0x0000);
+               pay->tcp.source_port    = src_port;
+               pay->tcp.dest_port      = dest_port;
+               pay->tcp.seq_num        = htonl(tcp_seqno);
+               pay->tcp.ack_num        = htonl(tcp_ack);
+               pay->tcp.hdr_length     = 0x50; /* 5 * 32 bit words */
+               pay->tcp.control        = tcp_ctl;
+               pay->tcp.window         = htons(0x7FFF);
+               pay->tcp.checksum       = htons(0x0000);
+               pay->tcp.urg            = htons(0x0000);
+               buf += SWRAP_PACKET_PAYLOAD_TCP_SIZE;
 
                break;
 
        case SOCK_DGRAM:
-               packet->ip.p.udp.source_port    = src_addr->sin_port;
-               packet->ip.p.udp.dest_port      = dest_addr->sin_port;
-               packet->ip.p.udp.length         = htons(8 + payload_len);
-               packet->ip.p.udp.checksum       = htons(0x0000);
+               pay->udp.source_port    = src_port;
+               pay->udp.dest_port      = dest_port;
+               pay->udp.length         = htons(8 + payload_len);
+               pay->udp.checksum       = htons(0x0000);
+               buf += SWRAP_PACKET_PAYLOAD_UDP_SIZE;
 
                break;
        }
 
        if (payload && payload_len > 0) {
-               unsigned char *p = (unsigned char *)ret;
-               p += nonwire_len;
-               p += wire_hdr_len;
-               memcpy(p, payload, payload_len);
+               memcpy(buf, payload, payload_len);
        }
 
        *_packet_len = packet_len - icmp_truncate_len;
-       return ret;
+       return base;
 }
 
 static int swrap_get_pcap_fd(const char *fname)
@@ -899,7 +1074,10 @@ static int swrap_get_pcap_fd(const char *fname)
                file_hdr.frame_max_len  = SWRAP_FRAME_LENGTH_MAX;
                file_hdr.link_type      = 0x0065; /* 101 RAW IP */
 
-               write(fd, &file_hdr, sizeof(file_hdr));
+               if (write(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) {
+                       close(fd);
+                       fd = -1;
+               }
                return fd;
        }
 
@@ -908,15 +1086,15 @@ static int swrap_get_pcap_fd(const char *fname)
        return fd;
 }
 
-static struct swrap_packet *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_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_in *src_addr;
-       const struct sockaddr_in *dest_addr;
-       unsigned long tcp_seq = 0;
+       const struct sockaddr *src_addr;
+       const struct sockaddr *dest_addr;
+       unsigned long tcp_seqno = 0;
        unsigned long tcp_ack = 0;
        unsigned char tcp_ctl = 0;
        int unreachable = 0;
@@ -926,6 +1104,10 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
        switch (si->family) {
        case AF_INET:
                break;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               break;
+#endif
        default:
                return NULL;
        }
@@ -934,10 +1116,10 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_CONNECT_SEND:
                if (si->type != SOCK_STREAM) return NULL;
 
-               src_addr = (const struct sockaddr_in *)si->myname;
-               dest_addr = (const struct sockaddr_in *)addr;
+               src_addr = si->myname;
+               dest_addr = addr;
 
-               tcp_seq = si->io.pck_snd;
+               tcp_seqno = si->io.pck_snd;
                tcp_ack = si->io.pck_rcv;
                tcp_ctl = 0x02; /* SYN */
 
@@ -948,10 +1130,10 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_CONNECT_RECV:
                if (si->type != SOCK_STREAM) return NULL;
 
-               dest_addr = (const struct sockaddr_in *)si->myname;
-               src_addr = (const struct sockaddr_in *)addr;
+               dest_addr = si->myname;
+               src_addr = addr;
 
-               tcp_seq = si->io.pck_rcv;
+               tcp_seqno = si->io.pck_rcv;
                tcp_ack = si->io.pck_snd;
                tcp_ctl = 0x12; /** SYN,ACK */
 
@@ -962,11 +1144,11 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_CONNECT_UNREACH:
                if (si->type != SOCK_STREAM) return NULL;
 
-               dest_addr = (const struct sockaddr_in *)si->myname;
-               src_addr = (const struct sockaddr_in *)addr;
+               dest_addr = si->myname;
+               src_addr = addr;
 
                /* Unreachable: resend the data of SWRAP_CONNECT_SEND */
-               tcp_seq = si->io.pck_snd - 1;
+               tcp_seqno = si->io.pck_snd - 1;
                tcp_ack = si->io.pck_rcv;
                tcp_ctl = 0x02; /* SYN */
                unreachable = 1;
@@ -976,10 +1158,10 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_CONNECT_ACK:
                if (si->type != SOCK_STREAM) return NULL;
 
-               src_addr = (const struct sockaddr_in *)si->myname;
-               dest_addr = (const struct sockaddr_in *)addr;
+               src_addr = si->myname;
+               dest_addr = addr;
 
-               tcp_seq = si->io.pck_snd;
+               tcp_seqno = si->io.pck_snd;
                tcp_ack = si->io.pck_rcv;
                tcp_ctl = 0x10; /* ACK */
 
@@ -988,10 +1170,10 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_ACCEPT_SEND:
                if (si->type != SOCK_STREAM) return NULL;
 
-               dest_addr = (const struct sockaddr_in *)si->myname;
-               src_addr = (const struct sockaddr_in *)addr;
+               dest_addr = si->myname;
+               src_addr = addr;
 
-               tcp_seq = si->io.pck_rcv;
+               tcp_seqno = si->io.pck_rcv;
                tcp_ack = si->io.pck_snd;
                tcp_ctl = 0x02; /* SYN */
 
@@ -1002,10 +1184,10 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_ACCEPT_RECV:
                if (si->type != SOCK_STREAM) return NULL;
 
-               src_addr = (const struct sockaddr_in *)si->myname;
-               dest_addr = (const struct sockaddr_in *)addr;
+               src_addr = si->myname;
+               dest_addr = addr;
 
-               tcp_seq = si->io.pck_snd;
+               tcp_seqno = si->io.pck_snd;
                tcp_ack = si->io.pck_rcv;
                tcp_ctl = 0x12; /* SYN,ACK */
 
@@ -1016,20 +1198,20 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_ACCEPT_ACK:
                if (si->type != SOCK_STREAM) return NULL;
 
-               dest_addr = (const struct sockaddr_in *)si->myname;
-               src_addr = (const struct sockaddr_in *)addr;
+               dest_addr = si->myname;
+               src_addr = addr;
 
-               tcp_seq = si->io.pck_rcv;
+               tcp_seqno = si->io.pck_rcv;
                tcp_ack = si->io.pck_snd;
                tcp_ctl = 0x10; /* ACK */
 
                break;
 
        case SWRAP_SEND:
-               src_addr = (const struct sockaddr_in *)si->myname;
-               dest_addr = (const struct sockaddr_in *)si->peername;
+               src_addr = si->myname;
+               dest_addr = si->peername;
 
-               tcp_seq = si->io.pck_snd;
+               tcp_seqno = si->io.pck_snd;
                tcp_ack = si->io.pck_rcv;
                tcp_ctl = 0x18; /* PSH,ACK */
 
@@ -1038,8 +1220,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
                break;
 
        case SWRAP_SEND_RST:
-               dest_addr = (const struct sockaddr_in *)si->myname;
-               src_addr = (const struct sockaddr_in *)si->peername;
+               dest_addr = si->myname;
+               src_addr = si->peername;
 
                if (si->type == SOCK_DGRAM) {
                        return swrap_marshall_packet(si, si->peername,
@@ -1047,31 +1229,31 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
                                          buf, len, packet_len);
                }
 
-               tcp_seq = si->io.pck_rcv;
+               tcp_seqno = si->io.pck_rcv;
                tcp_ack = si->io.pck_snd;
                tcp_ctl = 0x14; /** RST,ACK */
 
                break;
 
        case SWRAP_PENDING_RST:
-               dest_addr = (const struct sockaddr_in *)si->myname;
-               src_addr = (const struct sockaddr_in *)si->peername;
+               dest_addr = si->myname;
+               src_addr = si->peername;
 
                if (si->type == SOCK_DGRAM) {
                        return NULL;
                }
 
-               tcp_seq = si->io.pck_rcv;
+               tcp_seqno = si->io.pck_rcv;
                tcp_ack = si->io.pck_snd;
                tcp_ctl = 0x14; /* RST,ACK */
 
                break;
 
        case SWRAP_RECV:
-               dest_addr = (const struct sockaddr_in *)si->myname;
-               src_addr = (const struct sockaddr_in *)si->peername;
+               dest_addr = si->myname;
+               src_addr = si->peername;
 
-               tcp_seq = si->io.pck_rcv;
+               tcp_seqno = si->io.pck_rcv;
                tcp_ack = si->io.pck_snd;
                tcp_ctl = 0x18; /* PSH,ACK */
 
@@ -1080,38 +1262,38 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
                break;
 
        case SWRAP_RECV_RST:
-               dest_addr = (const struct sockaddr_in *)si->myname;
-               src_addr = (const struct sockaddr_in *)si->peername;
+               dest_addr = si->myname;
+               src_addr = si->peername;
 
                if (si->type == SOCK_DGRAM) {
                        return NULL;
                }
 
-               tcp_seq = si->io.pck_rcv;
+               tcp_seqno = si->io.pck_rcv;
                tcp_ack = si->io.pck_snd;
                tcp_ctl = 0x14; /* RST,ACK */
 
                break;
 
        case SWRAP_SENDTO:
-               src_addr = (const struct sockaddr_in *)si->myname;
-               dest_addr = (const struct sockaddr_in *)addr;
+               src_addr = si->myname;
+               dest_addr = addr;
 
                si->io.pck_snd += len;
 
                break;
 
        case SWRAP_SENDTO_UNREACH:
-               dest_addr = (const struct sockaddr_in *)si->myname;
-               src_addr = (const struct sockaddr_in *)addr;
+               dest_addr = si->myname;
+               src_addr = addr;
 
                unreachable = 1;
 
                break;
 
        case SWRAP_RECVFROM:
-               dest_addr = (const struct sockaddr_in *)si->myname;
-               src_addr = (const struct sockaddr_in *)addr;
+               dest_addr = si->myname;
+               src_addr = addr;
 
                si->io.pck_rcv += len;
 
@@ -1120,10 +1302,10 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_CLOSE_SEND:
                if (si->type != SOCK_STREAM) return NULL;
 
-               src_addr = (const struct sockaddr_in *)si->myname;
-               dest_addr = (const struct sockaddr_in *)si->peername;
+               src_addr = si->myname;
+               dest_addr = si->peername;
 
-               tcp_seq = si->io.pck_snd;
+               tcp_seqno = si->io.pck_snd;
                tcp_ack = si->io.pck_rcv;
                tcp_ctl = 0x11; /* FIN, ACK */
 
@@ -1134,10 +1316,10 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_CLOSE_RECV:
                if (si->type != SOCK_STREAM) return NULL;
 
-               dest_addr = (const struct sockaddr_in *)si->myname;
-               src_addr = (const struct sockaddr_in *)si->peername;
+               dest_addr = si->myname;
+               src_addr = si->peername;
 
-               tcp_seq = si->io.pck_rcv;
+               tcp_seqno = si->io.pck_rcv;
                tcp_ack = si->io.pck_snd;
                tcp_ctl = 0x11; /* FIN,ACK */
 
@@ -1148,10 +1330,10 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
        case SWRAP_CLOSE_ACK:
                if (si->type != SOCK_STREAM) return NULL;
 
-               src_addr = (const struct sockaddr_in *)si->myname;
-               dest_addr = (const struct sockaddr_in *)si->peername;
+               src_addr = si->myname;
+               dest_addr = si->peername;
 
-               tcp_seq = si->io.pck_snd;
+               tcp_seqno = si->io.pck_snd;
                tcp_ack = si->io.pck_rcv;
                tcp_ctl = 0x10; /* ACK */
 
@@ -1163,18 +1345,18 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
        swrapGetTimeOfDay(&tv);
 
        return swrap_packet_init(&tv, src_addr, dest_addr, si->type,
-                                  (const unsigned char *)buf, len,
-                                  tcp_seq, tcp_ack, tcp_ctl, unreachable,
-                                  packet_len);
+                                (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_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;
-       struct swrap_packet *packet;
+       uint8_t *packet;
        size_t packet_len = 0;
        int fd;
 
@@ -1190,7 +1372,10 @@ static void swrap_dump_packet(struct socket_info *si,
 
        fd = swrap_get_pcap_fd(file_name);
        if (fd != -1) {
-               write(fd, packet, packet_len);
+               if (write(fd, packet, packet_len) != packet_len) {
+                       free(packet);
+                       return;
+               }
        }
 
        free(packet);
@@ -1200,6 +1385,13 @@ _PUBLIC_ int swrap_socket(int family, int type, int protocol)
 {
        struct socket_info *si;
        int fd;
+       int real_type = type;
+#ifdef SOCK_CLOEXEC
+       real_type &= ~SOCK_CLOEXEC;
+#endif
+#ifdef SOCK_NONBLOCK
+       real_type &= ~SOCK_NONBLOCK;
+#endif
 
        if (!socket_wrapper_dir()) {
                return real_socket(family, type, protocol);
@@ -1218,7 +1410,7 @@ _PUBLIC_ int swrap_socket(int family, int type, int protocol)
                return -1;
        }
 
-       switch (type) {
+       switch (real_type) {
        case SOCK_STREAM:
                break;
        case SOCK_DGRAM:
@@ -1232,12 +1424,12 @@ _PUBLIC_ int swrap_socket(int family, int type, int protocol)
        case 0:
                break;
        case 6:
-               if (type == SOCK_STREAM) {
+               if (real_type == SOCK_STREAM) {
                        break;
                }
                /*fall through*/
        case 17:
-               if (type == SOCK_DGRAM) {
+               if (real_type == SOCK_DGRAM) {
                        break;
                }
                /*fall through*/
@@ -1246,6 +1438,8 @@ _PUBLIC_ int swrap_socket(int family, int type, int protocol)
                return -1;
        }
 
+       /* We must call real_socket with type, from the caller, not the version we removed
+          SOCK_CLOEXEC and SOCK_NONBLOCK from */
        fd = real_socket(AF_UNIX, type, 0);
 
        if (fd == -1) return -1;
@@ -1253,7 +1447,10 @@ _PUBLIC_ int swrap_socket(int family, int type, int protocol)
        si = (struct socket_info *)calloc(1, sizeof(struct socket_info));
 
        si->family = family;
-       si->type = type;
+
+       /* however, the rest of the socket_wrapper code expects just
+        * the type, not the flags */
+       si->type = real_type;
        si->protocol = protocol;
        si->fd = fd;
 
@@ -1323,6 +1520,7 @@ _PUBLIC_ int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
        child_si->protocol = parent_si->protocol;
        child_si->bound = 1;
        child_si->is_server = 1;
+       child_si->connected = 1;
 
        child_si->peername_len = len;
        child_si->peername = sockaddr_dup(my_addr, len);
@@ -1370,8 +1568,10 @@ 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
-   assign it here */
-static int swrap_auto_bind(struct socket_info *si)
+   assign it here.
+   Note: this might change the family from ipv6 to ipv4
+*/
+static int swrap_auto_bind(struct socket_info *si, int family)
 {
        struct sockaddr_un un_addr;
        int i;
@@ -1389,7 +1589,7 @@ static int swrap_auto_bind(struct socket_info *si)
 
        un_addr.sun_family = AF_UNIX;
 
-       switch (si->family) {
+       switch (family) {
        case AF_INET: {
                struct sockaddr_in in;
 
@@ -1418,6 +1618,11 @@ static int swrap_auto_bind(struct socket_info *si)
        case AF_INET6: {
                struct sockaddr_in6 in6;
 
+               if (si->family != family) {
+                       errno = ENETUNREACH;
+                       return -1;
+               }
+
                switch (si->type) {
                case SOCK_STREAM:
                        type = SOCKET_TYPE_CHAR_TCP_V6;
@@ -1426,13 +1631,14 @@ static int swrap_auto_bind(struct socket_info *si)
                        type = SOCKET_TYPE_CHAR_UDP_V6;
                        break;
                default:
-                   errno = ESOCKTNOSUPPORT;
-                   return -1;
+                       errno = ESOCKTNOSUPPORT;
+                       return -1;
                }
 
                memset(&in6, 0, sizeof(in6));
                in6.sin6_family = AF_INET6;
-               in6.sin6_addr.s6_addr[0] = SW_IPV6_ADDRESS;
+               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);
                break;
@@ -1467,6 +1673,7 @@ static int swrap_auto_bind(struct socket_info *si)
                return -1;
        }
 
+       si->family = family;
        set_port(si->family, port, si->myname);
 
        return 0;
@@ -1484,7 +1691,7 @@ _PUBLIC_ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t ad
        }
 
        if (si->bound == 0) {
-               ret = swrap_auto_bind(si);
+               ret = swrap_auto_bind(si, serv_addr->sa_family);
                if (ret == -1) return -1;
        }
 
@@ -1496,10 +1703,15 @@ _PUBLIC_ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t ad
        ret = sockaddr_convert_to_un(si, (const struct sockaddr *)serv_addr, addrlen, &un_addr, 0, NULL);
        if (ret == -1) return -1;
 
-       swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0);
+       if (si->type == SOCK_DGRAM) {
+               si->defer_connect = 1;
+               ret = 0;
+       } else {
+               swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0);
 
-       ret = real_connect(s, (struct sockaddr *)&un_addr, 
-                          sizeof(struct sockaddr_un));
+               ret = real_connect(s, (struct sockaddr *)&un_addr,
+                                  sizeof(struct sockaddr_un));
+       }
 
        /* to give better errors */
        if (ret == -1 && errno == ENOENT) {
@@ -1509,6 +1721,7 @@ _PUBLIC_ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t ad
        if (ret == 0) {
                si->peername_len = addrlen;
                si->peername = sockaddr_dup(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);
@@ -1626,6 +1839,10 @@ _PUBLIC_ int swrap_setsockopt(int s, int  level,  int  optname,  const  void  *o
        switch (si->family) {
        case AF_INET:
                return 0;
+#ifdef HAVE_IPV6
+       case AF_INET6:
+               return 0;
+#endif
        default:
                errno = ENOPROTOOPT;
                return -1;
@@ -1638,12 +1855,24 @@ _PUBLIC_ ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct
        socklen_t un_addrlen = sizeof(un_addr);
        int ret;
        struct socket_info *si = find_socket_info(s);
+       struct sockaddr_storage ss;
+       socklen_t ss_len = sizeof(ss);
 
        if (!si) {
                return real_recvfrom(s, buf, len, flags, from, fromlen);
        }
 
-       len = MIN(len, 1500);
+       if (!from) {
+               from = (struct sockaddr *)&ss;
+               fromlen = &ss_len;
+       }
+
+       if (si->type == SOCK_STREAM) {
+               /* cut down to 1500 byte packets for stream sockets,
+                * which makes it easier to format PCAP capture files
+                * (as the caller will simply continue from here) */
+               len = MIN(len, 1500);
+       }
 
        /* irix 6.4 forgets to null terminate the sun_path string :-( */
        memset(&un_addr, 0, sizeof(un_addr));
@@ -1673,15 +1902,28 @@ _PUBLIC_ ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, con
                return real_sendto(s, buf, len, flags, to, tolen);
        }
 
-       len = MIN(len, 1500);
+       if (si->connected) {
+               if (to) {
+                       errno = EISCONN;
+                       return -1;
+               }
+
+               to = si->peername;
+               tolen = si->peername_len;
+       }
 
        switch (si->type) {
        case SOCK_STREAM:
+               /* cut down to 1500 byte packets for stream sockets,
+                * which makes it easier to format PCAP capture files
+                * (as the caller will simply continue from here) */
+               len = MIN(len, 1500);
+       
                ret = real_send(s, buf, len, flags);
                break;
        case SOCK_DGRAM:
                if (si->bound == 0) {
-                       ret = swrap_auto_bind(si);
+                       ret = swrap_auto_bind(si, si->family);
                        if (ret == -1) return -1;
                }
                
@@ -1709,7 +1951,22 @@ _PUBLIC_ ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, con
                        
                        return len;
                }
-               
+
+               if (si->defer_connect) {
+                       ret = real_connect(s, (struct sockaddr *)&un_addr,
+                                          sizeof(un_addr));
+
+                       /* to give better errors */
+                       if (ret == -1 && errno == ENOENT) {
+                               errno = EHOSTUNREACH;
+                       }
+
+                       if (ret == -1) {
+                               return ret;
+                       }
+                       si->defer_connect = 0;
+               }
+
                ret = real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
                break;
        default:
@@ -1768,14 +2025,47 @@ _PUBLIC_ ssize_t swrap_recv(int s, void *buf, size_t len, int flags)
                return real_recv(s, buf, len, flags);
        }
 
-       len = MIN(len, 1500);
+       if (si->type == SOCK_STREAM) {
+               /* cut down to 1500 byte packets for stream sockets,
+                * which makes it easier to format PCAP capture files
+                * (as the caller will simply continue from here) */
+               len = MIN(len, 1500);
+       }
 
        ret = real_recv(s, buf, len, flags);
        if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
                swrap_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);
-       } else {
+       } else if (ret > 0) {
+               swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
+       }
+
+       return ret;
+}
+
+_PUBLIC_ ssize_t swrap_read(int s, void *buf, size_t len)
+{
+       int ret;
+       struct socket_info *si = find_socket_info(s);
+
+       if (!si) {
+               return real_read(s, buf, len);
+       }
+
+       if (si->type == SOCK_STREAM) {
+               /* cut down to 1500 byte packets for stream sockets,
+                * which makes it easier to format PCAP capture files
+                * (as the caller will simply continue from here) */
+               len = MIN(len, 1500);
+       }
+
+       ret = real_read(s, buf, len);
+       if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
+               swrap_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);
+       } else if (ret > 0) {
                swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
        }
 
@@ -1792,7 +2082,39 @@ _PUBLIC_ ssize_t swrap_send(int s, const void *buf, size_t len, int flags)
                return real_send(s, buf, len, flags);
        }
 
-       len = MIN(len, 1500);
+       if (si->type == SOCK_STREAM) {
+               /* cut down to 1500 byte packets for stream sockets,
+                * which makes it easier to format PCAP capture files
+                * (as the caller will simply continue from here) */
+               len = MIN(len, 1500);
+       }
+
+       if (si->defer_connect) {
+               struct sockaddr_un un_addr;
+               int bcast = 0;
+
+               if (si->bound == 0) {
+                       ret = swrap_auto_bind(si, si->family);
+                       if (ret == -1) return -1;
+               }
+
+               ret = sockaddr_convert_to_un(si, si->peername, si->peername_len,
+                                            &un_addr, 0, &bcast);
+               if (ret == -1) return -1;
+
+               ret = real_connect(s, (struct sockaddr *)&un_addr,
+                                  sizeof(un_addr));
+
+               /* to give better errors */
+               if (ret == -1 && errno == ENOENT) {
+                       errno = EHOSTUNREACH;
+               }
+
+               if (ret == -1) {
+                       return ret;
+               }
+               si->defer_connect = 0;
+       }
 
        ret = real_send(s, buf, len, flags);
 
@@ -1806,6 +2128,208 @@ _PUBLIC_ ssize_t swrap_send(int s, const void *buf, size_t len, int flags)
        return ret;
 }
 
+_PUBLIC_ ssize_t swrap_sendmsg(int s, const struct msghdr *msg, int flags)
+{
+       int ret;
+       uint8_t *buf;
+       off_t ofs = 0;
+       size_t i;
+       size_t remain;
+       
+       struct socket_info *si = find_socket_info(s);
+
+       if (!si) {
+               return real_sendmsg(s, msg, flags);
+       }
+
+       if (si->defer_connect) {
+               struct sockaddr_un un_addr;
+               int bcast = 0;
+
+               if (si->bound == 0) {
+                       ret = swrap_auto_bind(si, si->family);
+                       if (ret == -1) return -1;
+               }
+
+               ret = sockaddr_convert_to_un(si, si->peername, si->peername_len,
+                                            &un_addr, 0, &bcast);
+               if (ret == -1) return -1;
+
+               ret = real_connect(s, (struct sockaddr *)&un_addr,
+                                  sizeof(un_addr));
+
+               /* to give better errors */
+               if (ret == -1 && errno == ENOENT) {
+                       errno = EHOSTUNREACH;
+               }
+
+               if (ret == -1) {
+                       return ret;
+               }
+               si->defer_connect = 0;
+       }
+
+       ret = real_sendmsg(s, msg, flags);
+       remain = ret;
+               
+       /* we capture it as one single packet */
+       buf = (uint8_t *)malloc(ret);
+       if (!buf) {
+               /* we just not capture the packet */
+               errno = 0;
+               return ret;
+       }
+       
+       for (i=0; i < msg->msg_iovlen; i++) {
+               size_t this_time = MIN(remain, msg->msg_iov[i].iov_len);
+               memcpy(buf + ofs,
+                      msg->msg_iov[i].iov_base,
+                      this_time);
+               ofs += this_time;
+               remain -= this_time;
+       }
+       
+       swrap_dump_packet(si, NULL, SWRAP_SEND, buf, ret);
+       free(buf);
+       if (ret == -1) {
+               swrap_dump_packet(si, NULL, SWRAP_SEND_RST, NULL, 0);
+       }
+
+       return ret;
+}
+
+int swrap_readv(int s, const struct iovec *vector, size_t count)
+{
+       int ret;
+       struct socket_info *si = find_socket_info(s);
+       struct iovec v;
+
+       if (!si) {
+               return real_readv(s, vector, count);
+       }
+
+       if (si->type == SOCK_STREAM && count > 0) {
+               /* cut down to 1500 byte packets for stream sockets,
+                * which makes it easier to format PCAP capture files
+                * (as the caller will simply continue from here) */
+               size_t i, len = 0;
+               
+               for (i=0; i < count; i++) {
+                       size_t nlen;
+                       nlen = len + vector[i].iov_len;
+                       if (nlen > 1500) {
+                               break;
+                       }
+               }
+               count = i;
+               if (count == 0) {
+                       v = vector[0];
+                       v.iov_len = MIN(v.iov_len, 1500);
+                       vector = &v;
+                       count = 1;
+               }
+       }
+
+       ret = real_readv(s, vector, count);
+       if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
+               swrap_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);
+       } else if (ret > 0) {
+               uint8_t *buf;
+               off_t ofs = 0;
+               size_t i;
+               size_t remain = ret;
+
+               /* we capture it as one single packet */
+               buf = (uint8_t *)malloc(ret);
+               if (!buf) {
+                       /* we just not capture the packet */
+                       errno = 0;
+                       return ret;
+               }
+
+               for (i=0; i < count; i++) {
+                       size_t this_time = MIN(remain, vector[i].iov_len);
+                       memcpy(buf + ofs,
+                              vector[i].iov_base,
+                              this_time);
+                       ofs += this_time;
+                       remain -= this_time;
+               }
+
+               swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
+               free(buf);
+       }
+
+       return ret;
+}
+
+int swrap_writev(int s, const struct iovec *vector, size_t count)
+{
+       int ret;
+       struct socket_info *si = find_socket_info(s);
+       struct iovec v;
+
+       if (!si) {
+               return real_writev(s, vector, count);
+       }
+
+       if (si->type == SOCK_STREAM && count > 0) {
+               /* cut down to 1500 byte packets for stream sockets,
+                * which makes it easier to format PCAP capture files
+                * (as the caller will simply continue from here) */
+               size_t i, len = 0;
+
+               for (i=0; i < count; i++) {
+                       size_t nlen;
+                       nlen = len + vector[i].iov_len;
+                       if (nlen > 1500) {
+                               break;
+                       }
+               }
+               count = i;
+               if (count == 0) {
+                       v = vector[0];
+                       v.iov_len = MIN(v.iov_len, 1500);
+                       vector = &v;
+                       count = 1;
+               }
+       }
+
+       ret = real_writev(s, vector, count);
+       if (ret == -1) {
+               swrap_dump_packet(si, NULL, SWRAP_SEND_RST, NULL, 0);
+       } else {
+               uint8_t *buf;
+               off_t ofs = 0;
+               size_t i;
+               size_t remain = ret;
+
+               /* we capture it as one single packet */
+               buf = (uint8_t *)malloc(ret);
+               if (!buf) {
+                       /* we just not capture the packet */
+                       errno = 0;
+                       return ret;
+               }
+
+               for (i=0; i < count; i++) {
+                       size_t this_time = MIN(remain, vector[i].iov_len);
+                       memcpy(buf + ofs,
+                              vector[i].iov_base,
+                              this_time);
+                       ofs += this_time;
+                       remain -= this_time;
+               }
+
+               swrap_dump_packet(si, NULL, SWRAP_SEND, buf, ret);
+               free(buf);
+       }
+
+       return ret;
+}
+
 _PUBLIC_ int swrap_close(int fd)
 {
        struct socket_info *si = find_socket_info(fd);