📄 socket_wrapper.c
字号:
/* * Copyright (C) Jelmer Vernooij 2005 <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.*/#ifdef _SAMBA_BUILD_#define SOCKET_WRAPPER_NOT_REPLACE#include "includes.h"#include "system/network.h"#include "system/filesys.h"#ifdef malloc#undef malloc#endif#ifdef calloc#undef calloc#endif#ifdef strdup#undef strdup#endif#else /* _SAMBA_BUILD_ */#include <sys/types.h>#include <sys/stat.h>#include <sys/socket.h>#include <sys/ioctl.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>#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 #ifdef REWRITE_CALLS#define real_accept accept#define real_connect connect#define real_bind bind#define real_listen listen#define real_getpeername getpeername#define real_getsockname getsockname#define real_getsockopt getsockopt#define real_setsockopt setsockopt#define real_recvfrom recvfrom#define real_sendto sendto#define real_ioctl ioctl#define real_recv recv#define real_send send#define real_socket socket#define real_close close#endif#ifdef HAVE_GETTIMEOFDAY_TZ#define swrapGetTimeOfDay(tval) gettimeofday(tval,NULL)#else#define swrapGetTimeOfDay(tval) gettimeofday(tval)#endif/* we need to use a very terse format here as IRIX 6.4 silently truncates names to 16 chars, so if we use a longer name then we can't tell which port a packet came from with recvfrom() with this format we have 8 chars left for the directory name*/#define SOCKET_FORMAT "%c%02X%04X"#define SOCKET_TYPE_CHAR_TCP 'T'#define SOCKET_TYPE_CHAR_UDP 'U'#define MAX_WRAPPED_INTERFACES 16static struct sockaddr *sockaddr_dup(const void *data, socklen_t len){ struct sockaddr *ret = (struct sockaddr *)malloc(len); memcpy(ret, data, len); return ret;}struct socket_info{ int fd; int family; int type; int protocol; int bound; int bcast; int is_server; char *path; char *tmp_path; struct sockaddr *myname; socklen_t myname_len; struct sockaddr *peername; socklen_t peername_len; struct { unsigned long pck_snd; unsigned long pck_rcv; } io; struct socket_info *prev, *next;};static struct socket_info *sockets;static const char *socket_wrapper_dir(void){ const char *s = getenv("SOCKET_WRAPPER_DIR"); if (s == NULL) { return NULL; } if (strncmp(s, "./", 2) == 0) { s += 2; } return s;}static unsigned int socket_wrapper_default_iface(void){ const char *s = getenv("SOCKET_WRAPPER_DEFAULT_IFACE"); if (s) { unsigned int iface; if (sscanf(s, "%u", &iface) == 1) { if (iface >= 1 && iface <= MAX_WRAPPED_INTERFACES) { return iface; } } } return 1;/* 127.0.0.1 */}static int convert_un_in(const struct sockaddr_un *un, struct sockaddr_in *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; if (sscanf(p, SOCKET_FORMAT, &type, &iface, &prt) != 3) { errno = EINVAL; return -1; } if (type != SOCKET_TYPE_CHAR_TCP && type != SOCKET_TYPE_CHAR_UDP) { errno = EINVAL; return -1; } if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) { errno = EINVAL; return -1; } if (prt > 0xFFFF) { 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, 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 iface; int is_bcast = 0; if (bcast) *bcast = 0; if (prt == 0) { errno = EINVAL; return -1; } 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; } 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; if (is_bcast) { snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL", socket_wrapper_dir()); /* the caller need to do more processing */ return 0; } snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, socket_wrapper_dir(), type, iface, prt); return 0;}static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr_in *in, 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 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; 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; } if (bcast) *bcast = is_bcast; if (prt == 0) { /* handle auto-allocation of ephemeral ports */ for (prt = 5001; prt < 10000; prt++) { snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 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; } errno = ENFILE; return -1; } snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, socket_wrapper_dir(), type, iface, prt); return 0;}static struct socket_info *find_socket_info(int fd){ struct socket_info *i; for (i = sockets; i; i = i->next) { if (i->fd == fd) return i; } return NULL;}static int sockaddr_convert_to_un(struct socket_info *si, const struct sockaddr *in_addr, socklen_t in_len, struct sockaddr_un *out_addr, int alloc_sock, int *bcast){ if (!out_addr) return 0; out_addr->sun_family = AF_UNIX; switch (in_addr->sa_family) { case AF_INET: switch (si->type) { case SOCK_STREAM: case SOCK_DGRAM: break; default: errno = ESOCKTNOSUPPORT; return -1; } if (alloc_sock) { return convert_in_un_alloc(si, (const struct sockaddr_in *)in_addr, out_addr, bcast); } else { return convert_in_un_remote(si, (const struct sockaddr_in *)in_addr, out_addr, bcast); } default: break; } errno = EAFNOSUPPORT; return -1;}static int sockaddr_convert_from_un(const struct socket_info *si, const struct sockaddr_un *in_addr, socklen_t un_addrlen, int family, struct sockaddr *out_addr, socklen_t *_out_addrlen){ socklen_t out_addrlen; if (out_addr == NULL || _out_addrlen == NULL) return 0; if (un_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: switch (si->type) { case SOCK_STREAM: case SOCK_DGRAM: break; default: errno = ESOCKTNOSUPPORT; return -1; } return convert_un_in(in_addr, (struct sockaddr_in *)out_addr, _out_addrlen); default: break; } errno = EAFNOSUPPORT; return -1;}enum swrap_packet_type { SWRAP_CONNECT_SEND, SWRAP_CONNECT_UNREACH, SWRAP_CONNECT_RECV, SWRAP_CONNECT_ACK, SWRAP_ACCEPT_SEND, SWRAP_ACCEPT_RECV, SWRAP_ACCEPT_ACK, SWRAP_RECVFROM, SWRAP_SENDTO, SWRAP_SENDTO_UNREACH, SWRAP_PENDING_RST, SWRAP_RECV, SWRAP_RECV_RST, SWRAP_SEND, SWRAP_SEND_RST, SWRAP_CLOSE_SEND, SWRAP_CLOSE_RECV, SWRAP_CLOSE_ACK};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;#define SWRAP_FRAME_LENGTH_MAX 0xFFFF unsigned long link_type;};#define SWRAP_FILE_HDR_SIZE 24struct swrap_packet { struct { unsigned long seconds; unsigned long micro_seconds; unsigned long recorded_length; unsigned long 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -