2 Socket wrapper library. Passes all socket communication over
3 unix domain sockets if the environment variable SOCKET_WRAPPER_DIR
5 Copyright (C) Jelmer Vernooij 2005
6 Copyright (C) Stefan Metzmacher 2006
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #define SOCKET_WRAPPER_NOT_REPLACE
27 #include "system/network.h"
28 #include "system/filesys.h"
31 #include "lib/util/dlinklist.h"
44 #else /* _SAMBA_BUILD_ */
46 #include <sys/types.h>
48 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <netinet/tcp.h>
58 #error "dlinklist.h missing"
62 /* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support
67 #define real_accept accept
68 #define real_connect connect
69 #define real_bind bind
70 #define real_getpeername getpeername
71 #define real_getsockname getsockname
72 #define real_getsockopt getsockopt
73 #define real_setsockopt setsockopt
74 #define real_recvfrom recvfrom
75 #define real_sendto sendto
76 #define real_recv recv
77 #define real_send send
78 #define real_socket socket
79 #define real_close close
82 /* we need to use a very terse format here as IRIX 6.4 silently
83 truncates names to 16 chars, so if we use a longer name then we
84 can't tell which port a packet came from with recvfrom()
86 with this format we have 8 chars left for the directory name
88 #define SOCKET_FORMAT "%c%02X%04X"
89 #define SOCKET_TYPE_CHAR_TCP 'T'
90 #define SOCKET_TYPE_CHAR_UDP 'U'
92 static struct sockaddr *sockaddr_dup(const void *data, socklen_t len)
94 struct sockaddr *ret = (struct sockaddr *)malloc(len);
95 memcpy(ret, data, len);
112 struct sockaddr *myname;
113 socklen_t myname_len;
115 struct sockaddr *peername;
116 socklen_t peername_len;
118 struct socket_info *prev, *next;
121 static struct socket_info *sockets;
124 static const char *socket_wrapper_dir(void)
126 const char *s = getenv("SOCKET_WRAPPER_DIR");
130 if (strncmp(s, "./", 2) == 0) {
136 static const char *socket_wrapper_dump_dir(void)
138 const char *s = getenv("SOCKET_WRAPPER_DUMP_DIR");
140 if (!socket_wrapper_dir()) {
147 if (strncmp(s, "./", 2) == 0) {
153 static unsigned int socket_wrapper_default_iface(void)
155 const char *s = getenv("SOCKET_WRAPPER_DEFAULT_IFACE");
158 if (sscanf(s, "%u", &iface) == 1) {
159 if (iface >= 1 && iface <= 0xFF) {
165 return 1;/* 127.0.0.1 */
168 static int convert_un_in(const struct sockaddr_un *un, struct sockaddr_in *in, socklen_t *len)
175 if ((*len) < sizeof(struct sockaddr_in)) {
179 p = strrchr(un->sun_path, '/');
180 if (p) p++; else p = un->sun_path;
182 if (sscanf(p, SOCKET_FORMAT, &type, &iface, &prt) != 3) {
187 if (type != SOCKET_TYPE_CHAR_TCP && type != SOCKET_TYPE_CHAR_UDP) {
192 if (iface == 0 || iface > 0xFF) {
202 in->sin_family = AF_INET;
203 in->sin_addr.s_addr = htonl((127<<24) | iface);
204 in->sin_port = htons(prt);
206 *len = sizeof(struct sockaddr_in);
210 static int convert_in_un_remote(struct socket_info *si, const struct sockaddr_in *in, struct sockaddr_un *un,
217 unsigned int addr= ntohl(in->sin_addr.s_addr);
218 unsigned int prt = ntohs(in->sin_port);
222 if (bcast) *bcast = 0;
231 u_type = SOCKET_TYPE_CHAR_TCP;
234 u_type = SOCKET_TYPE_CHAR_UDP;
235 a_type = SOCKET_TYPE_CHAR_UDP;
236 b_type = SOCKET_TYPE_CHAR_UDP;
240 if (a_type && addr == 0xFFFFFFFF) {
241 /* 255.255.255.255 only udp */
244 iface = socket_wrapper_default_iface();
245 } else if (b_type && addr == 0x7FFFFFFF) {
246 /* 127.255.255.255 only udp */
249 iface = socket_wrapper_default_iface();
250 } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
254 iface = (addr & 0x000000FF);
260 if (bcast) *bcast = is_bcast;
263 snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL",
264 socket_wrapper_dir());
265 /* the caller need to do more processing */
269 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
270 socket_wrapper_dir(), type, iface, prt);
275 static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr_in *in, struct sockaddr_un *un,
283 unsigned int addr= ntohl(in->sin_addr.s_addr);
284 unsigned int prt = ntohs(in->sin_port);
289 if (bcast) *bcast = 0;
293 u_type = SOCKET_TYPE_CHAR_TCP;
294 d_type = SOCKET_TYPE_CHAR_TCP;
297 u_type = SOCKET_TYPE_CHAR_UDP;
298 d_type = SOCKET_TYPE_CHAR_UDP;
299 a_type = SOCKET_TYPE_CHAR_UDP;
300 b_type = SOCKET_TYPE_CHAR_UDP;
308 iface = socket_wrapper_default_iface();
309 } else if (a_type && addr == 0xFFFFFFFF) {
310 /* 255.255.255.255 only udp */
313 iface = socket_wrapper_default_iface();
314 } else if (b_type && addr == 0x7FFFFFFF) {
315 /* 127.255.255.255 only udp */
318 iface = socket_wrapper_default_iface();
319 } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
323 iface = (addr & 0x000000FF);
325 errno = EADDRNOTAVAIL;
329 if (bcast) *bcast = is_bcast;
332 /* handle auto-allocation of ephemeral ports */
333 for (prt = 5001; prt < 10000; prt++) {
334 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
335 socket_wrapper_dir(), type, iface, prt);
336 if (stat(un->sun_path, &st) == 0) continue;
338 ((struct sockaddr_in *)si->myname)->sin_port = htons(prt);
345 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
346 socket_wrapper_dir(), type, iface, prt);
350 static struct socket_info *find_socket_info(int fd)
352 struct socket_info *i;
353 for (i = sockets; i; i = i->next) {
361 static int sockaddr_convert_to_un(struct socket_info *si, const struct sockaddr *in_addr, socklen_t in_len,
362 struct sockaddr_un *out_addr, int alloc_sock, int *bcast)
367 out_addr->sun_family = AF_UNIX;
369 switch (in_addr->sa_family) {
376 errno = ESOCKTNOSUPPORT;
380 return convert_in_un_alloc(si, (const struct sockaddr_in *)in_addr, out_addr, bcast);
382 return convert_in_un_remote(si, (const struct sockaddr_in *)in_addr, out_addr, bcast);
388 errno = EAFNOSUPPORT;
392 static int sockaddr_convert_from_un(const struct socket_info *si,
393 const struct sockaddr_un *in_addr,
394 socklen_t un_addrlen,
396 struct sockaddr *out_addr,
397 socklen_t *_out_addrlen)
399 socklen_t out_addrlen;
401 if (out_addr == NULL || _out_addrlen == NULL)
404 if (un_addrlen == 0) {
409 out_addrlen = *_out_addrlen;
410 if (out_addrlen > un_addrlen) {
411 out_addrlen = un_addrlen;
421 errno = ESOCKTNOSUPPORT;
424 return convert_un_in(in_addr, (struct sockaddr_in *)out_addr, _out_addrlen);
429 errno = EAFNOSUPPORT;
433 enum swrap_packet_type {
443 static void swrap_dump_packet(struct socket_info *si, const struct sockaddr *addr,
444 enum swrap_packet_type type,
445 const void *buf, size_t len, ssize_t ret)
447 if (!socket_wrapper_dump_dir()) {
453 _PUBLIC_ int swrap_socket(int family, int type, int protocol)
455 struct socket_info *si;
458 if (!socket_wrapper_dir()) {
459 return real_socket(family, type, protocol);
466 return real_socket(family, type, protocol);
468 errno = EAFNOSUPPORT;
472 fd = real_socket(AF_UNIX, type, 0);
474 if (fd == -1) return -1;
476 si = calloc(1, sizeof(struct socket_info));
480 si->protocol = protocol;
483 DLIST_ADD(sockets, si);
488 _PUBLIC_ int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
490 struct socket_info *parent_si, *child_si;
492 struct sockaddr_un un_addr;
493 socklen_t un_addrlen = sizeof(un_addr);
494 struct sockaddr_un un_my_addr;
495 socklen_t un_my_addrlen = sizeof(un_my_addr);
496 struct sockaddr my_addr;
497 socklen_t my_addrlen = sizeof(my_addr);
500 parent_si = find_socket_info(s);
502 return real_accept(s, addr, addrlen);
505 memset(&un_addr, 0, sizeof(un_addr));
506 memset(&un_my_addr, 0, sizeof(un_my_addr));
507 memset(&my_addr, 0, sizeof(my_addr));
509 ret = real_accept(s, (struct sockaddr *)&un_addr, &un_addrlen);
510 if (ret == -1) return ret;
514 ret = sockaddr_convert_from_un(parent_si, &un_addr, un_addrlen,
515 parent_si->family, addr, addrlen);
521 child_si = malloc(sizeof(struct socket_info));
522 memset(child_si, 0, sizeof(*child_si));
525 child_si->family = parent_si->family;
526 child_si->type = parent_si->type;
527 child_si->protocol = parent_si->protocol;
530 ret = real_getsockname(fd, (struct sockaddr *)&un_my_addr, &un_my_addrlen);
537 ret = sockaddr_convert_from_un(child_si, &un_my_addr, un_my_addrlen,
538 child_si->family, &my_addr, &my_addrlen);
545 child_si->myname_len = my_addrlen;
546 child_si->myname = sockaddr_dup(&my_addr, my_addrlen);
548 child_si->peername_len = *addrlen;
549 child_si->peername = sockaddr_dup(addr, *addrlen);
551 DLIST_ADD(sockets, child_si);
553 swrap_dump_packet(child_si, addr, SWRAP_ACCEPT, NULL, 0, 0);
558 /* using sendto() or connect() on an unbound socket would give the
559 recipient no way to reply, as unlike UDP and TCP, a unix domain
560 socket can't auto-assign emphemeral port numbers, so we need to
562 static int swrap_auto_bind(struct socket_info *si)
564 struct sockaddr_un un_addr;
565 struct sockaddr_in in;
572 un_addr.sun_family = AF_UNIX;
576 type = SOCKET_TYPE_CHAR_TCP;
579 type = SOCKET_TYPE_CHAR_UDP;
582 errno = ESOCKTNOSUPPORT;
586 for (i=0;i<1000;i++) {
588 snprintf(un_addr.sun_path, sizeof(un_addr.sun_path),
589 "%s/"SOCKET_FORMAT, socket_wrapper_dir(),
590 type, socket_wrapper_default_iface(), port);
591 if (stat(un_addr.sun_path, &st) == 0) continue;
593 ret = real_bind(si->fd, (struct sockaddr *)&un_addr, sizeof(un_addr));
594 if (ret == -1) return ret;
596 si->tmp_path = strdup(un_addr.sun_path);
605 memset(&in, 0, sizeof(in));
606 in.sin_family = AF_INET;
607 in.sin_port = htons(port);
608 in.sin_addr.s_addr = htonl(127<<24 | socket_wrapper_default_iface());
610 si->myname_len = sizeof(in);
611 si->myname = sockaddr_dup(&in, si->myname_len);
617 _PUBLIC_ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen)
620 struct sockaddr_un un_addr;
621 struct socket_info *si = find_socket_info(s);
624 return real_connect(s, serv_addr, addrlen);
627 if (si->bound == 0) {
628 ret = swrap_auto_bind(si);
629 if (ret == -1) return -1;
632 ret = sockaddr_convert_to_un(si, (const struct sockaddr *)serv_addr, addrlen, &un_addr, 0, NULL);
633 if (ret == -1) return -1;
635 ret = real_connect(s, (struct sockaddr *)&un_addr,
636 sizeof(struct sockaddr_un));
638 /* to give better errors */
639 if (ret == -1 && errno == ENOENT) {
640 errno = EHOSTUNREACH;
644 si->peername_len = addrlen;
645 si->peername = sockaddr_dup(serv_addr, addrlen);
648 swrap_dump_packet(si, serv_addr, SWRAP_CONNECT, NULL, 0, ret);
653 _PUBLIC_ int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
656 struct sockaddr_un un_addr;
657 struct socket_info *si = find_socket_info(s);
660 return real_bind(s, myaddr, addrlen);
663 si->myname_len = addrlen;
664 si->myname = sockaddr_dup(myaddr, addrlen);
666 ret = sockaddr_convert_to_un(si, (const struct sockaddr *)myaddr, addrlen, &un_addr, 1, &si->bcast);
667 if (ret == -1) return -1;
669 unlink(un_addr.sun_path);
671 ret = real_bind(s, (struct sockaddr *)&un_addr,
672 sizeof(struct sockaddr_un));
681 _PUBLIC_ int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
683 struct socket_info *si = find_socket_info(s);
686 return real_getpeername(s, name, addrlen);
695 memcpy(name, si->peername, si->peername_len);
696 *addrlen = si->peername_len;
701 _PUBLIC_ int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
703 struct socket_info *si = find_socket_info(s);
706 return real_getsockname(s, name, addrlen);
709 memcpy(name, si->myname, si->myname_len);
710 *addrlen = si->myname_len;
715 _PUBLIC_ int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
717 struct socket_info *si = find_socket_info(s);
720 return real_getsockopt(s, level, optname, optval, optlen);
723 if (level == SOL_SOCKET) {
724 return real_getsockopt(s, level, optname, optval, optlen);
731 _PUBLIC_ int swrap_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
733 struct socket_info *si = find_socket_info(s);
736 return real_setsockopt(s, level, optname, optval, optlen);
739 if (level == SOL_SOCKET) {
740 return real_setsockopt(s, level, optname, optval, optlen);
743 switch (si->family) {
752 _PUBLIC_ ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
754 struct sockaddr_un un_addr;
755 socklen_t un_addrlen = sizeof(un_addr);
757 struct socket_info *si = find_socket_info(s);
760 return real_recvfrom(s, buf, len, flags, from, fromlen);
763 /* irix 6.4 forgets to null terminate the sun_path string :-( */
764 memset(&un_addr, 0, sizeof(un_addr));
765 ret = real_recvfrom(s, buf, len, flags, (struct sockaddr *)&un_addr, &un_addrlen);
769 if (sockaddr_convert_from_un(si, &un_addr, un_addrlen,
770 si->family, from, fromlen) == -1) {
774 swrap_dump_packet(si, from, SWRAP_RECVFROM, buf, len, ret);
780 _PUBLIC_ ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
782 struct sockaddr_un un_addr;
784 struct socket_info *si = find_socket_info(s);
788 return real_sendto(s, buf, len, flags, to, tolen);
791 if (si->bound == 0) {
792 ret = swrap_auto_bind(si);
793 if (ret == -1) return -1;
796 ret = sockaddr_convert_to_un(si, to, tolen, &un_addr, 0, &bcast);
797 if (ret == -1) return -1;
802 unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
805 type = SOCKET_TYPE_CHAR_UDP;
807 for(iface=0; iface <= 0xFF; iface++) {
808 snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
809 socket_wrapper_dir(), type, iface, prt);
810 if (stat(un_addr.sun_path, &st) != 0) continue;
812 /* ignore the any errors in broadcast sends */
813 real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
816 swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len, len);
821 ret = real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
823 /* to give better errors */
824 if (ret == -1 && errno == ENOENT) {
825 errno = EHOSTUNREACH;
828 swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len, ret);
833 _PUBLIC_ ssize_t swrap_recv(int s, void *buf, size_t len, int flags)
836 struct socket_info *si = find_socket_info(s);
839 return real_recv(s, buf, len, flags);
842 ret = real_recv(s, buf, len, flags);
846 swrap_dump_packet(si, NULL, SWRAP_RECV, buf, len, ret);
852 _PUBLIC_ ssize_t swrap_send(int s, const void *buf, size_t len, int flags)
855 struct socket_info *si = find_socket_info(s);
858 return real_send(s, buf, len, flags);
861 ret = real_send(s, buf, len, flags);
865 swrap_dump_packet(si, NULL, SWRAP_SEND, buf, len, ret);
870 _PUBLIC_ int swrap_close(int fd)
872 struct socket_info *si = find_socket_info(fd);
875 DLIST_REMOVE(sockets, si);
877 swrap_dump_packet(si, NULL, SWRAP_CLOSE, NULL, 0, 0);
883 unlink(si->tmp_path);
889 return real_close(fd);