/*
* 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_ioctl ioctl
#define real_recv recv
#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)
{
int bound;
int bcast;
int is_server;
+ int connected;
+ int defer_connect;
char *path;
char *tmp_path;
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);
case AF_INET6: {
const struct sockaddr_in6 *in =
(const struct sockaddr_in6 *)inaddr;
+ struct in6_addr cmp;
switch (si->type) {
case SOCK_STREAM:
/* 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
case AF_INET6: {
const struct sockaddr_in6 *in =
(const struct sockaddr_in6 *)inaddr;
+ struct in6_addr cmp;
switch (si->type) {
case SOCK_STREAM:
/* 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;
}
uint32_t dest_addr;
} v4;
#define SWRAP_PACKET_IP_V4_SIZE 20
+ struct {
+ 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 20
+#define SWRAP_PACKET_IP_SIZE 40
union swrap_packet_payload {
struct {
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_PAYLOAD_SIZE 20
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) != SWRAP_PACKET_PAYLOAD_SIZE) {
return NULL;
}
if (sizeof(p.icmp4) != SWRAP_PACKET_PAYLOAD_ICMP4_SIZE) {
return NULL;
}
+ if (sizeof(p.icmp6) != SWRAP_PACKET_PAYLOAD_ICMP6_SIZE) {
+ return NULL;
+ }
s = getenv("SOCKET_WRAPPER_PCAP_FILE");
if (s == NULL) {
}
static uint8_t *swrap_packet_init(struct timeval *tval,
- const struct sockaddr_in *src_addr,
- const struct sockaddr_in *dest_addr,
+ const struct sockaddr *src,
+ const struct sockaddr *dest,
int socket_type,
- const unsigned char *payload,
+ const uint8_t *payload,
size_t payload_len,
unsigned long tcp_seqno,
unsigned long tcp_ack,
size_t nonwire_len = sizeof(*frame);
size_t wire_hdr_len = 0;
size_t wire_len = 0;
- size_t ip_hdr_len = sizeof(ip->v4);
+ size_t ip_hdr_len = 0;
size_t icmp_hdr_len = 0;
size_t icmp_truncate_len = 0;
uint8_t protocol = 0, icmp_protocol = 0;
- uint16_t src_port = src_addr->sin_port;
- uint16_t dest_port = dest_addr->sin_port;
+ 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:
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 = ip_hdr_len + sizeof(pay->icmp4);
wire_hdr_len += icmp_hdr_len;
wire_len += icmp_hdr_len;
}
buf += SWRAP_PACKET_FRAME_SIZE;
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_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_addr->sin_addr.s_addr;
- ip->v4.dest_addr = dest_addr->sin_addr.s_addr;
- buf += SWRAP_PACKET_IP_V4_SIZE;
-
- if (unreachable) {
- pay = (union swrap_packet_payload *)buf;
- 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;
+ 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_hdr_len);
+ 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 = icmp_protocol;
+ ip->v4.protocol = protocol;
ip->v4.hdr_checksum = htons(0x0000);
- ip->v4.src_addr = dest_addr->sin_addr.s_addr;
- ip->v4.dest_addr = src_addr->sin_addr.s_addr;
+ 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
+ }
- src_port = dest_addr->sin_port;
- dest_port = src_addr->sin_port;
+ if (unreachable) {
+ 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;
break;
case SOCK_DGRAM:
- pay->udp.source_port = src_addr->sin_port;
- pay->udp.dest_port = dest_addr->sin_port;
+ 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;
const void *buf, size_t len,
size_t *packet_len)
{
- const struct sockaddr_in *src_addr;
- const struct sockaddr_in *dest_addr;
+ 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;
switch (si->family) {
case AF_INET:
break;
+ case AF_INET6:
+ break;
default:
return NULL;
}
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_seqno = si->io.pck_snd;
tcp_ack = si->io.pck_rcv;
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_seqno = si->io.pck_rcv;
tcp_ack = si->io.pck_snd;
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_seqno = si->io.pck_snd - 1;
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_seqno = si->io.pck_snd;
tcp_ack = si->io.pck_rcv;
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_seqno = si->io.pck_rcv;
tcp_ack = si->io.pck_snd;
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_seqno = si->io.pck_snd;
tcp_ack = si->io.pck_rcv;
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_seqno = si->io.pck_rcv;
tcp_ack = si->io.pck_snd;
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_seqno = si->io.pck_snd;
tcp_ack = si->io.pck_rcv;
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,
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;
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_seqno = si->io.pck_rcv;
tcp_ack = si->io.pck_snd;
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;
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;
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_seqno = si->io.pck_snd;
tcp_ack = si->io.pck_rcv;
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_seqno = si->io.pck_rcv;
tcp_ack = si->io.pck_snd;
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_seqno = si->io.pck_snd;
tcp_ack = si->io.pck_rcv;
swrapGetTimeOfDay(&tv);
return swrap_packet_init(&tv, src_addr, dest_addr, si->type,
- (const unsigned char *)buf, len,
- tcp_seqno, 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,
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);
/* 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;
un_addr.sun_family = AF_UNIX;
- switch (si->family) {
+ switch (family) {
case AF_INET: {
struct sockaddr_in in;
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;
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;
return -1;
}
+ si->family = family;
set_port(si->family, port, si->myname);
return 0;
}
if (si->bound == 0) {
- ret = swrap_auto_bind(si);
+ ret = swrap_auto_bind(si, serv_addr->sa_family);
if (ret == -1) return -1;
}
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) {
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);
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);
}
+ if (!from) {
+ from = (struct sockaddr *)&ss;
+ fromlen = &ss_len;
+ }
+
len = MIN(len, 1500);
/* irix 6.4 forgets to null terminate the sun_path string :-( */
return real_sendto(s, buf, len, flags, to, tolen);
}
+ if (si->connected) {
+ if (to) {
+ errno = EISCONN;
+ return -1;
+ }
+
+ to = si->peername;
+ tolen = si->peername_len;
+ }
+
len = MIN(len, 1500);
switch (si->type) {
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;
}
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:
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);
if (ret == -1) {
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);
+ }
+
+ /* we read 1500 bytes as maximum */
+ if (count > 0) {
+ 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;
+
+ /* 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++) {
+ memcpy(buf + ofs,
+ vector[i].iov_base,
+ vector[i].iov_len);
+ ofs += vector[i].iov_len;
+ }
+
+ 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);
+ }
+
+ /* we write 1500 bytes as maximum */
+ if (count > 0) {
+ 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;
+
+ /* 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++) {
+ memcpy(buf + ofs,
+ vector[i].iov_base,
+ vector[i].iov_len);
+ ofs += vector[i].iov_len;
+ }
+
+ 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);