-/*
- Socket wrapper library. Passes all socket communication over
- unix domain sockets if the environment variable SOCKET_WRAPPER_DIR
+/*
+ * Copyright (C) Jelmer Vernooij 2005,2008 <jelmer@samba.org>
+ * Copyright (C) Stefan Metzmacher 2006 <metze@samba.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ Socket wrapper library. Passes all socket communication over
+ unix domain sockets if the environment variable SOCKET_WRAPPER_DIR
is set.
- Copyright (C) Jelmer Vernooij 2005
- Copyright (C) Stefan Metzmacher 2006
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef _SAMBA_BUILD_
#define SOCKET_WRAPPER_NOT_REPLACE
-#include "includes.h"
+#include "lib/replace/replace.h"
#include "system/network.h"
#include "system/filesys.h"
-
-#ifndef _DLINKLIST_H
-#include "lib/util/dlinklist.h"
-#endif
-
-#ifdef malloc
-#undef malloc
-#endif
-#ifdef calloc
-#undef calloc
-#endif
-#ifdef strdup
-#undef strdup
-#endif
+#include "system/time.h"
#else /* _SAMBA_BUILD_ */
#include <sys/types.h>
+#include <sys/time.h>
#include <sys/stat.h>
#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/filio.h>
#include <errno.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
+#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
+#include <stdint.h>
-#error "dlinklist.h missing"
+#endif
+#ifndef _PUBLIC_
+#define _PUBLIC_
#endif
+#define SWRAP_DLIST_ADD(list,item) do { \
+ if (!(list)) { \
+ (item)->prev = NULL; \
+ (item)->next = NULL; \
+ (list) = (item); \
+ } else { \
+ (item)->prev = NULL; \
+ (item)->next = (list); \
+ (list)->prev = (item); \
+ (list) = (item); \
+ } \
+} while (0)
+
+#define SWRAP_DLIST_REMOVE(list,item) do { \
+ if ((list) == (item)) { \
+ (list) = (item)->next; \
+ if (list) { \
+ (list)->prev = NULL; \
+ } \
+ } else { \
+ if ((item)->prev) { \
+ (item)->prev->next = (item)->next; \
+ } \
+ if ((item)->next) { \
+ (item)->next->prev = (item)->prev; \
+ } \
+ } \
+ (item)->prev = NULL; \
+ (item)->next = NULL; \
+} while (0)
+
/* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support
* for now */
#define REWRITE_CALLS
#define SOCKET_FORMAT "%c%02X%04X"
#define SOCKET_TYPE_CHAR_TCP 'T'
#define SOCKET_TYPE_CHAR_UDP 'U'
+#define SOCKET_TYPE_CHAR_TCP_V6 'X'
+#define SOCKET_TYPE_CHAR_UDP_V6 'Y'
#define MAX_WRAPPED_INTERFACES 16
+#define SW_IPV6_ADDRESS 1
+
static struct sockaddr *sockaddr_dup(const void *data, socklen_t len)
{
struct sockaddr *ret = (struct sockaddr *)malloc(len);
return ret;
}
+static void set_port(int family, int prt, struct sockaddr *addr)
+{
+ switch (family) {
+ case AF_INET:
+ ((struct sockaddr_in *)addr)->sin_port = htons(prt);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ ((struct sockaddr_in6 *)addr)->sin6_port = htons(prt);
+ break;
+#endif
+ }
+}
+
+static size_t socket_length(int family)
+{
+ switch (family) {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+#endif
+ }
+ return 0;
+}
+
+
+
struct socket_info
{
int fd;
static struct socket_info *sockets;
-
-static const char *socket_wrapper_dir(void)
+const char *socket_wrapper_dir(void)
{
const char *s = getenv("SOCKET_WRAPPER_DIR");
if (s == NULL) {
return s;
}
-static unsigned int socket_wrapper_default_iface(void)
+unsigned int socket_wrapper_default_iface(void)
{
const char *s = getenv("SOCKET_WRAPPER_DEFAULT_IFACE");
if (s) {
return 1;/* 127.0.0.1 */
}
-static int convert_un_in(const struct sockaddr_un *un, struct sockaddr_in *in, socklen_t *len)
+static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, socklen_t *len)
{
unsigned int iface;
unsigned int prt;
const char *p;
char type;
- if ((*len) < sizeof(struct sockaddr_in)) {
- return 0;
- }
-
p = strrchr(un->sun_path, '/');
if (p) p++; else p = un->sun_path;
return -1;
}
- if (type != SOCKET_TYPE_CHAR_TCP && type != SOCKET_TYPE_CHAR_UDP) {
+ if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) {
errno = EINVAL;
return -1;
}
- if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) {
+ if (prt > 0xFFFF) {
errno = EINVAL;
return -1;
}
- if (prt > 0xFFFF) {
+ switch(type) {
+ case SOCKET_TYPE_CHAR_TCP:
+ case SOCKET_TYPE_CHAR_UDP: {
+ struct sockaddr_in *in2 = (struct sockaddr_in *)in;
+
+ if ((*len) < sizeof(*in2)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(in2, 0, sizeof(*in2));
+ in2->sin_family = AF_INET;
+ in2->sin_addr.s_addr = htonl((127<<24) | iface);
+ in2->sin_port = htons(prt);
+
+ *len = sizeof(*in2);
+ break;
+ }
+#ifdef HAVE_IPV6
+ case SOCKET_TYPE_CHAR_TCP_V6:
+ case SOCKET_TYPE_CHAR_UDP_V6: {
+ struct sockaddr_in6 *in2 = (struct sockaddr_in6 *)in;
+
+ if ((*len) < sizeof(*in2)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ memset(in2, 0, sizeof(*in2));
+ in2->sin6_family = AF_INET6;
+ in2->sin6_addr.s6_addr[0] = SW_IPV6_ADDRESS;
+ in2->sin6_port = htons(prt);
+
+ *len = sizeof(*in2);
+ break;
+ }
+#endif
+ default:
errno = EINVAL;
return -1;
}
- in->sin_family = AF_INET;
- in->sin_addr.s_addr = htonl((127<<24) | iface);
- in->sin_port = htons(prt);
-
- *len = sizeof(struct sockaddr_in);
return 0;
}
-static int convert_in_un_remote(struct socket_info *si, const struct sockaddr_in *in, struct sockaddr_un *un,
+static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un,
int *bcast)
{
- char u_type = '\0';
- char b_type = '\0';
- char a_type = '\0';
char type = '\0';
- unsigned int addr= ntohl(in->sin_addr.s_addr);
- unsigned int prt = ntohs(in->sin_port);
+ unsigned int prt;
unsigned int iface;
int is_bcast = 0;
if (bcast) *bcast = 0;
- if (prt == 0) {
- errno = EINVAL;
- return -1;
- }
+ switch (si->family) {
+ case AF_INET: {
+ const struct sockaddr_in *in =
+ (const struct sockaddr_in *)inaddr;
+ unsigned int addr = ntohl(in->sin_addr.s_addr);
+ char u_type = '\0';
+ char b_type = '\0';
+ char a_type = '\0';
- switch (si->type) {
- case SOCK_STREAM:
- u_type = SOCKET_TYPE_CHAR_TCP;
- break;
- case SOCK_DGRAM:
- u_type = SOCKET_TYPE_CHAR_UDP;
- a_type = SOCKET_TYPE_CHAR_UDP;
- b_type = SOCKET_TYPE_CHAR_UDP;
+ switch (si->type) {
+ case SOCK_STREAM:
+ u_type = SOCKET_TYPE_CHAR_TCP;
+ break;
+ case SOCK_DGRAM:
+ u_type = SOCKET_TYPE_CHAR_UDP;
+ a_type = SOCKET_TYPE_CHAR_UDP;
+ b_type = SOCKET_TYPE_CHAR_UDP;
+ break;
+ }
+
+ prt = ntohs(in->sin_port);
+ if (a_type && addr == 0xFFFFFFFF) {
+ /* 255.255.255.255 only udp */
+ is_bcast = 2;
+ type = a_type;
+ iface = socket_wrapper_default_iface();
+ } else if (b_type && addr == 0x7FFFFFFF) {
+ /* 127.255.255.255 only udp */
+ is_bcast = 1;
+ type = b_type;
+ iface = socket_wrapper_default_iface();
+ } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
+ /* 127.0.0.X */
+ is_bcast = 0;
+ type = u_type;
+ iface = (addr & 0x000000FF);
+ } else {
+ errno = ENETUNREACH;
+ return -1;
+ }
+ if (bcast) *bcast = is_bcast;
break;
}
+#ifdef HAVE_IPV6
+ case AF_INET6: {
+ const struct sockaddr_in6 *in =
+ (const struct sockaddr_in6 *)inaddr;
- if (a_type && addr == 0xFFFFFFFF) {
- /* 255.255.255.255 only udp */
- is_bcast = 2;
- type = a_type;
- iface = socket_wrapper_default_iface();
- } else if (b_type && addr == 0x7FFFFFFF) {
- /* 127.255.255.255 only udp */
- is_bcast = 1;
- type = b_type;
- iface = socket_wrapper_default_iface();
- } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
- /* 127.0.0.X */
- is_bcast = 0;
- type = u_type;
- iface = (addr & 0x000000FF);
- } else {
+ switch (si->type) {
+ case SOCK_STREAM:
+ type = SOCKET_TYPE_CHAR_TCP_V6;
+ break;
+ case SOCK_DGRAM:
+ type = SOCKET_TYPE_CHAR_UDP_V6;
+ break;
+ }
+
+ /* XXX no multicast/broadcast */
+
+ prt = ntohs(in->sin6_port);
+ iface = SW_IPV6_ADDRESS;
+
+ break;
+ }
+#endif
+ default:
errno = ENETUNREACH;
return -1;
}
- if (bcast) *bcast = is_bcast;
+ if (prt == 0) {
+ errno = EINVAL;
+ return -1;
+ }
if (is_bcast) {
snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL",
return 0;
}
-static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr_in *in, struct sockaddr_un *un,
+static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un,
int *bcast)
{
- char u_type = '\0';
- char d_type = '\0';
- char b_type = '\0';
- char a_type = '\0';
char type = '\0';
- unsigned int addr= ntohl(in->sin_addr.s_addr);
- unsigned int prt = ntohs(in->sin_port);
+ unsigned int prt;
unsigned int iface;
struct stat st;
int is_bcast = 0;
if (bcast) *bcast = 0;
- switch (si->type) {
- case SOCK_STREAM:
- u_type = SOCKET_TYPE_CHAR_TCP;
- d_type = SOCKET_TYPE_CHAR_TCP;
- break;
- case SOCK_DGRAM:
- u_type = SOCKET_TYPE_CHAR_UDP;
- d_type = SOCKET_TYPE_CHAR_UDP;
- a_type = SOCKET_TYPE_CHAR_UDP;
- b_type = SOCKET_TYPE_CHAR_UDP;
+ switch (si->family) {
+ case AF_INET: {
+ const struct sockaddr_in *in =
+ (const struct sockaddr_in *)inaddr;
+ unsigned int addr = ntohl(in->sin_addr.s_addr);
+ char u_type = '\0';
+ char d_type = '\0';
+ char b_type = '\0';
+ char a_type = '\0';
+
+ prt = ntohs(in->sin_port);
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ u_type = SOCKET_TYPE_CHAR_TCP;
+ d_type = SOCKET_TYPE_CHAR_TCP;
+ break;
+ case SOCK_DGRAM:
+ u_type = SOCKET_TYPE_CHAR_UDP;
+ d_type = SOCKET_TYPE_CHAR_UDP;
+ a_type = SOCKET_TYPE_CHAR_UDP;
+ b_type = SOCKET_TYPE_CHAR_UDP;
+ break;
+ }
+
+ if (addr == 0) {
+ /* 0.0.0.0 */
+ is_bcast = 0;
+ type = d_type;
+ iface = socket_wrapper_default_iface();
+ } else if (a_type && addr == 0xFFFFFFFF) {
+ /* 255.255.255.255 only udp */
+ is_bcast = 2;
+ type = a_type;
+ iface = socket_wrapper_default_iface();
+ } else if (b_type && addr == 0x7FFFFFFF) {
+ /* 127.255.255.255 only udp */
+ is_bcast = 1;
+ type = b_type;
+ iface = socket_wrapper_default_iface();
+ } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
+ /* 127.0.0.X */
+ is_bcast = 0;
+ type = u_type;
+ iface = (addr & 0x000000FF);
+ } else {
+ errno = EADDRNOTAVAIL;
+ return -1;
+ }
break;
}
+#ifdef HAVE_IPV6
+ case AF_INET6: {
+ const struct sockaddr_in6 *in =
+ (const struct sockaddr_in6 *)inaddr;
- if (addr == 0) {
- /* 0.0.0.0 */
- is_bcast = 0;
- type = d_type;
- iface = socket_wrapper_default_iface();
- } else if (a_type && addr == 0xFFFFFFFF) {
- /* 255.255.255.255 only udp */
- is_bcast = 2;
- type = a_type;
- iface = socket_wrapper_default_iface();
- } else if (b_type && addr == 0x7FFFFFFF) {
- /* 127.255.255.255 only udp */
- is_bcast = 1;
- type = b_type;
- iface = socket_wrapper_default_iface();
- } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
- /* 127.0.0.X */
- is_bcast = 0;
- type = u_type;
- iface = (addr & 0x000000FF);
- } else {
- errno = EADDRNOTAVAIL;
+ switch (si->type) {
+ case SOCK_STREAM:
+ type = SOCKET_TYPE_CHAR_TCP_V6;
+ break;
+ case SOCK_DGRAM:
+ type = SOCKET_TYPE_CHAR_UDP_V6;
+ break;
+ }
+
+ /* XXX no multicast/broadcast */
+
+ prt = ntohs(in->sin6_port);
+ iface = SW_IPV6_ADDRESS;
+
+ break;
+ }
+#endif
+ default:
+ errno = ENETUNREACH;
return -1;
}
+
if (bcast) *bcast = is_bcast;
if (prt == 0) {
socket_wrapper_dir(), type, iface, prt);
if (stat(un->sun_path, &st) == 0) continue;
- ((struct sockaddr_in *)si->myname)->sin_port = htons(prt);
- return 0;
+ set_port(si->family, prt, si->myname);
+ break;
+ }
+ if (prt == 10000) {
+ errno = ENFILE;
+ return -1;
}
- errno = ENFILE;
- return -1;
}
snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
switch (in_addr->sa_family) {
case AF_INET:
+#ifdef HAVE_IPV6
+ case AF_INET6:
+#endif
switch (si->type) {
case SOCK_STREAM:
case SOCK_DGRAM:
return -1;
}
if (alloc_sock) {
- return convert_in_un_alloc(si, (const struct sockaddr_in *)in_addr, out_addr, bcast);
+ return convert_in_un_alloc(si, in_addr, out_addr, bcast);
} else {
- return convert_in_un_remote(si, (const struct sockaddr_in *)in_addr, out_addr, bcast);
+ return convert_in_un_remote(si, in_addr, out_addr, bcast);
}
default:
break;
socklen_t un_addrlen,
int family,
struct sockaddr *out_addr,
- socklen_t *_out_addrlen)
+ socklen_t *out_addrlen)
{
- socklen_t out_addrlen;
-
- if (out_addr == NULL || _out_addrlen == NULL)
+ if (out_addr == NULL || out_addrlen == NULL)
return 0;
if (un_addrlen == 0) {
- *_out_addrlen = 0;
+ *out_addrlen = 0;
return 0;
}
- out_addrlen = *_out_addrlen;
- if (out_addrlen > un_addrlen) {
- out_addrlen = un_addrlen;
- }
-
switch (family) {
case AF_INET:
+#ifdef HAVE_IPV6
+ case AF_INET6:
+#endif
switch (si->type) {
case SOCK_STREAM:
case SOCK_DGRAM:
errno = ESOCKTNOSUPPORT;
return -1;
}
- return convert_un_in(in_addr, (struct sockaddr_in *)out_addr, _out_addrlen);
+ return convert_un_in(in_addr, out_addr, out_addrlen);
default:
break;
}
};
struct swrap_file_hdr {
- unsigned long magic;
- unsigned short version_major;
- unsigned short version_minor;
- long timezone;
- unsigned long sigfigs;
- unsigned long frame_max_len;
+ uint32_t magic;
+ uint16_t version_major;
+ uint16_t version_minor;
+ int32_t timezone;
+ uint32_t sigfigs;
+ uint32_t frame_max_len;
#define SWRAP_FRAME_LENGTH_MAX 0xFFFF
- unsigned long link_type;
+ uint32_t link_type;
};
#define SWRAP_FILE_HDR_SIZE 24
struct swrap_packet {
struct {
- unsigned long seconds;
- unsigned long micro_seconds;
- unsigned long recorded_length;
- unsigned long full_length;
+ uint32_t seconds;
+ uint32_t micro_seconds;
+ uint32_t recorded_length;
+ uint32_t full_length;
} frame;
#define SWRAP_PACKET__FRAME_SIZE 16
struct {
struct {
- unsigned char ver_hdrlen;
- unsigned char tos;
- unsigned short packet_length;
- unsigned short identification;
- unsigned char flags;
- unsigned char fragment;
- unsigned char ttl;
- unsigned char protocol;
- unsigned short hdr_checksum;
- unsigned long src_addr;
- unsigned long dest_addr;
+ 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 {
- unsigned short source_port;
- unsigned short dest_port;
- unsigned long seq_num;
- unsigned long ack_num;
- unsigned char hdr_length;
- unsigned char control;
- unsigned short window;
- unsigned short checksum;
- unsigned short urg;
+ 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 {
- unsigned short source_port;
- unsigned short dest_port;
- unsigned short length;
- unsigned short checksum;
+ uint16_t source_port;
+ uint16_t dest_port;
+ uint16_t length;
+ uint16_t checksum;
} udp;
#define SWRAP_PACKET__IP_P_UDP_SIZE 8
struct {
- unsigned char type;
- unsigned char code;
- unsigned short checksum;
- unsigned long unused;
+ uint8_t type;
+ uint8_t code;
+ uint16_t checksum;
+ uint32_t unused;
} icmp;
#define SWRAP_PACKET__IP_P_ICMP_SIZE 8
} p;
{
static int initialized = 0;
static const char *s = NULL;
- static const struct swrap_file_hdr h;
- static const struct swrap_packet p;
+ static const struct swrap_file_hdr h = { 0, };
+ static const struct swrap_packet p = { { 0, }, { { 0, }, { { 0, } } } };
if (initialized == 1) {
return s;
int socket_type,
const unsigned char *payload,
size_t payload_len,
- unsigned long tcp_seq,
+ unsigned long tcp_seqno,
unsigned long tcp_ack,
unsigned char tcp_ctl,
int unreachable,
wire_hdr_len = sizeof(packet->ip.hdr) + sizeof(packet->ip.p.udp);
wire_len = wire_hdr_len + payload_len;
break;
+
+ default:
+ return NULL;
}
if (unreachable) {
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.seq_num = htonl(tcp_seqno);
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;
return fd;
}
-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 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)
{
const struct sockaddr_in *src_addr;
const struct sockaddr_in *dest_addr;
- const char *file_name;
- unsigned long tcp_seq = 0;
+ unsigned long tcp_seqno = 0;
unsigned long tcp_ack = 0;
unsigned char tcp_ctl = 0;
int unreachable = 0;
- struct timeval tv;
- struct swrap_packet *packet;
- size_t packet_len = 0;
- int fd;
- file_name = socket_wrapper_pcap_file();
- if (!file_name) {
- return;
- }
+ struct timeval tv;
- if (si->family != AF_INET) {
- return;
+ switch (si->family) {
+ case AF_INET:
+ break;
+ default:
+ return NULL;
}
switch (type) {
case SWRAP_CONNECT_SEND:
- if (si->type != SOCK_STREAM) return;
+ if (si->type != SOCK_STREAM) return NULL;
src_addr = (const struct sockaddr_in *)si->myname;
dest_addr = (const struct sockaddr_in *)addr;
- tcp_seq = si->io.pck_snd;
+ tcp_seqno = si->io.pck_snd;
tcp_ack = si->io.pck_rcv;
tcp_ctl = 0x02; /* SYN */
break;
case SWRAP_CONNECT_RECV:
- if (si->type != SOCK_STREAM) return;
+ if (si->type != SOCK_STREAM) return NULL;
dest_addr = (const struct sockaddr_in *)si->myname;
src_addr = (const struct sockaddr_in *)addr;
- tcp_seq = si->io.pck_rcv;
+ tcp_seqno = si->io.pck_rcv;
tcp_ack = si->io.pck_snd;
tcp_ctl = 0x12; /** SYN,ACK */
break;
case SWRAP_CONNECT_UNREACH:
- if (si->type != SOCK_STREAM) return;
+ if (si->type != SOCK_STREAM) return NULL;
dest_addr = (const struct sockaddr_in *)si->myname;
src_addr = (const struct sockaddr_in *)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;
break;
case SWRAP_CONNECT_ACK:
- if (si->type != SOCK_STREAM) return;
+ if (si->type != SOCK_STREAM) return NULL;
src_addr = (const struct sockaddr_in *)si->myname;
dest_addr = (const struct sockaddr_in *)addr;
- tcp_seq = si->io.pck_snd;
+ tcp_seqno = si->io.pck_snd;
tcp_ack = si->io.pck_rcv;
tcp_ctl = 0x10; /* ACK */
break;
case SWRAP_ACCEPT_SEND:
- if (si->type != SOCK_STREAM) return;
+ if (si->type != SOCK_STREAM) return NULL;
dest_addr = (const struct sockaddr_in *)si->myname;
src_addr = (const struct sockaddr_in *)addr;
- tcp_seq = si->io.pck_rcv;
+ tcp_seqno = si->io.pck_rcv;
tcp_ack = si->io.pck_snd;
tcp_ctl = 0x02; /* SYN */
break;
case SWRAP_ACCEPT_RECV:
- if (si->type != SOCK_STREAM) return;
+ if (si->type != SOCK_STREAM) return NULL;
src_addr = (const struct sockaddr_in *)si->myname;
dest_addr = (const struct sockaddr_in *)addr;
- tcp_seq = si->io.pck_snd;
+ tcp_seqno = si->io.pck_snd;
tcp_ack = si->io.pck_rcv;
tcp_ctl = 0x12; /* SYN,ACK */
break;
case SWRAP_ACCEPT_ACK:
- if (si->type != SOCK_STREAM) return;
+ if (si->type != SOCK_STREAM) return NULL;
dest_addr = (const struct sockaddr_in *)si->myname;
src_addr = (const struct sockaddr_in *)addr;
- tcp_seq = si->io.pck_rcv;
+ tcp_seqno = si->io.pck_rcv;
tcp_ack = si->io.pck_snd;
tcp_ctl = 0x10; /* ACK */
src_addr = (const struct sockaddr_in *)si->myname;
dest_addr = (const struct sockaddr_in *)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 */
src_addr = (const struct sockaddr_in *)si->peername;
if (si->type == SOCK_DGRAM) {
- swrap_dump_packet(si, si->peername,
+ return swrap_marshall_packet(si, si->peername,
SWRAP_SENDTO_UNREACH,
- buf, len);
- return;
+ 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 */
src_addr = (const struct sockaddr_in *)si->peername;
if (si->type == SOCK_DGRAM) {
- return;
+ 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 */
dest_addr = (const struct sockaddr_in *)si->myname;
src_addr = (const struct sockaddr_in *)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 */
src_addr = (const struct sockaddr_in *)si->peername;
if (si->type == SOCK_DGRAM) {
- return;
+ 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_CLOSE_SEND:
- if (si->type != SOCK_STREAM) return;
+ if (si->type != SOCK_STREAM) return NULL;
src_addr = (const struct sockaddr_in *)si->myname;
dest_addr = (const struct sockaddr_in *)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 */
break;
case SWRAP_CLOSE_RECV:
- if (si->type != SOCK_STREAM) return;
+ if (si->type != SOCK_STREAM) return NULL;
dest_addr = (const struct sockaddr_in *)si->myname;
src_addr = (const struct sockaddr_in *)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 */
break;
case SWRAP_CLOSE_ACK:
- if (si->type != SOCK_STREAM) return;
+ if (si->type != SOCK_STREAM) return NULL;
src_addr = (const struct sockaddr_in *)si->myname;
dest_addr = (const struct sockaddr_in *)si->peername;
- tcp_seq = si->io.pck_snd;
+ tcp_seqno = si->io.pck_snd;
tcp_ack = si->io.pck_rcv;
tcp_ctl = 0x10; /* ACK */
break;
default:
- return;
+ return NULL;
}
swrapGetTimeOfDay(&tv);
- packet = swrap_packet_init(&tv, src_addr, dest_addr, si->type,
+ 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);
+ 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)
+{
+ const char *file_name;
+ struct swrap_packet *packet;
+ size_t packet_len = 0;
+ int fd;
+
+ file_name = socket_wrapper_pcap_file();
+ if (!file_name) {
+ return;
+ }
+
+ packet = swrap_marshall_packet(si, addr, type, buf, len, &packet_len);
if (!packet) {
return;
}
switch (family) {
case AF_INET:
+#ifdef HAVE_IPV6
+ case AF_INET6:
+#endif
break;
case AF_UNIX:
return real_socket(family, type, protocol);
switch (protocol) {
case 0:
break;
+ case 6:
+ if (type == SOCK_STREAM) {
+ break;
+ }
+ /*fall through*/
+ case 17:
+ if (type == SOCK_DGRAM) {
+ break;
+ }
+ /*fall through*/
default:
errno = EPROTONOSUPPORT;
return -1;
si->protocol = protocol;
si->fd = fd;
- DLIST_ADD(sockets, si);
+ SWRAP_DLIST_ADD(sockets, si);
return si->fd;
}
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 = sizeof(my_addr);
+ struct sockaddr *my_addr;
+ socklen_t my_addrlen, len;
int ret;
parent_si = find_socket_info(s);
return real_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) {
+ 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));
- memset(&my_addr, 0, sizeof(my_addr));
ret = real_accept(s, (struct sockaddr *)&un_addr, &un_addrlen);
- if (ret == -1) return ret;
+ if (ret == -1) {
+ free(my_addr);
+ return ret;
+ }
fd = ret;
+ len = my_addrlen;
ret = sockaddr_convert_from_un(parent_si, &un_addr, un_addrlen,
- parent_si->family, addr, addrlen);
+ parent_si->family, my_addr, &len);
if (ret == -1) {
+ free(my_addr);
close(fd);
return ret;
}
child_si->bound = 1;
child_si->is_server = 1;
+ child_si->peername_len = len;
+ child_si->peername = sockaddr_dup(my_addr, len);
+
+ if (addr != NULL && addrlen != NULL) {
+ *addrlen = len;
+ if (*addrlen >= len)
+ memcpy(addr, my_addr, len);
+ *addrlen = 0;
+ }
+
ret = real_getsockname(fd, (struct sockaddr *)&un_my_addr, &un_my_addrlen);
if (ret == -1) {
free(child_si);
return ret;
}
+ len = my_addrlen;
ret = sockaddr_convert_from_un(child_si, &un_my_addr, un_my_addrlen,
- child_si->family, &my_addr, &my_addrlen);
+ child_si->family, my_addr, &len);
if (ret == -1) {
free(child_si);
+ free(my_addr);
close(fd);
return ret;
}
- child_si->myname_len = my_addrlen;
- child_si->myname = sockaddr_dup(&my_addr, my_addrlen);
-
- child_si->peername_len = *addrlen;
- child_si->peername = sockaddr_dup(addr, *addrlen);
+ child_si->myname_len = len;
+ child_si->myname = sockaddr_dup(my_addr, len);
+ free(my_addr);
- DLIST_ADD(sockets, child_si);
+ SWRAP_DLIST_ADD(sockets, child_si);
swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0);
swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_RECV, NULL, 0);
static int swrap_auto_bind(struct socket_info *si)
{
struct sockaddr_un un_addr;
- struct sockaddr_in in;
int i;
char type;
int ret;
un_addr.sun_family = AF_UNIX;
- switch (si->type) {
- case SOCK_STREAM:
- type = SOCKET_TYPE_CHAR_TCP;
+ switch (si->family) {
+ case AF_INET: {
+ struct sockaddr_in in;
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ type = SOCKET_TYPE_CHAR_TCP;
+ break;
+ case SOCK_DGRAM:
+ type = SOCKET_TYPE_CHAR_UDP;
+ break;
+ default:
+ errno = ESOCKTNOSUPPORT;
+ return -1;
+ }
+
+ memset(&in, 0, sizeof(in));
+ in.sin_family = AF_INET;
+ 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);
break;
- case SOCK_DGRAM:
- type = SOCKET_TYPE_CHAR_UDP;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6: {
+ struct sockaddr_in6 in6;
+
+ switch (si->type) {
+ case SOCK_STREAM:
+ type = SOCKET_TYPE_CHAR_TCP_V6;
+ break;
+ case SOCK_DGRAM:
+ type = SOCKET_TYPE_CHAR_UDP_V6;
+ break;
+ default:
+ errno = ESOCKTNOSUPPORT;
+ return -1;
+ }
+
+ memset(&in6, 0, sizeof(in6));
+ in6.sin6_family = AF_INET6;
+ in6.sin6_addr.s6_addr[0] = SW_IPV6_ADDRESS;
+ si->myname_len = sizeof(in6);
+ si->myname = sockaddr_dup(&in6, si->myname_len);
break;
+ }
+#endif
default:
errno = ESOCKTNOSUPPORT;
return -1;
return -1;
}
- memset(&in, 0, sizeof(in));
- in.sin_family = AF_INET;
- in.sin_port = htons(port);
- 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);
+ set_port(si->family, port, si->myname);
+
return 0;
}
if (ret == -1) return -1;
}
+ if (si->family != serv_addr->sa_family) {
+ errno = EINVAL;
+ return -1;
+ }
+
ret = sockaddr_convert_to_un(si, (const struct sockaddr *)serv_addr, addrlen, &un_addr, 0, NULL);
if (ret == -1) return -1;
return real_recvfrom(s, buf, len, flags, from, fromlen);
}
+ len = MIN(len, 1500);
+
/* irix 6.4 forgets to null terminate the sun_path string :-( */
memset(&un_addr, 0, sizeof(un_addr));
ret = real_recvfrom(s, buf, len, flags, (struct sockaddr *)&un_addr, &un_addrlen);
return real_sendto(s, buf, len, flags, to, tolen);
}
- if (si->bound == 0) {
- ret = swrap_auto_bind(si);
- if (ret == -1) return -1;
- }
-
- ret = sockaddr_convert_to_un(si, to, tolen, &un_addr, 0, &bcast);
- if (ret == -1) return -1;
-
- if (bcast) {
- struct stat st;
- unsigned int iface;
- unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
- char type;
-
- type = SOCKET_TYPE_CHAR_UDP;
+ len = MIN(len, 1500);
- for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
- snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
- socket_wrapper_dir(), type, iface, prt);
- if (stat(un_addr.sun_path, &st) != 0) continue;
-
- /* ignore the any errors in broadcast sends */
- real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
+ switch (si->type) {
+ case SOCK_STREAM:
+ ret = real_send(s, buf, len, flags);
+ break;
+ case SOCK_DGRAM:
+ if (si->bound == 0) {
+ ret = swrap_auto_bind(si);
+ if (ret == -1) return -1;
}
-
- swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
-
- return len;
+
+ ret = sockaddr_convert_to_un(si, to, tolen, &un_addr, 0, &bcast);
+ if (ret == -1) return -1;
+
+ if (bcast) {
+ struct stat st;
+ unsigned int iface;
+ unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
+ char type;
+
+ 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,
+ socket_wrapper_dir(), type, iface, prt);
+ if (stat(un_addr.sun_path, &st) != 0) continue;
+
+ /* ignore the any errors in broadcast sends */
+ real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
+ }
+
+ swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
+
+ return len;
+ }
+
+ ret = real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
+ break;
+ default:
+ ret = -1;
+ errno = EHOSTUNREACH;
+ break;
}
-
- ret = real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
-
+
/* to give better errors */
if (ret == -1 && errno == ENOENT) {
errno = EHOSTUNREACH;
return real_recv(s, buf, len, flags);
}
+ 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);
return real_send(s, buf, len, flags);
}
+ len = MIN(len, 1500);
+
ret = real_send(s, buf, len, flags);
if (ret == -1) {
return real_close(fd);
}
- DLIST_REMOVE(sockets, si);
+ SWRAP_DLIST_REMOVE(sockets, si);
if (si->myname && si->peername) {
swrap_dump_packet(si, NULL, SWRAP_CLOSE_SEND, NULL, 0);