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
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "system/network.h"
26 #include "system/filesys.h"
28 #include <sys/types.h>
30 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <netinet/tcp.h>
40 #include "lib/util/dlinklist.h"
42 /* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support
47 #define real_accept accept
48 #define real_connect connect
49 #define real_bind bind
50 #define real_getpeername getpeername
51 #define real_getsockname getsockname
52 #define real_getsockopt getsockopt
53 #define real_setsockopt setsockopt
54 #define real_recvfrom recvfrom
55 #define real_sendto sendto
56 #define real_recv recv
57 #define real_send send
58 #define real_socket socket
59 #define real_close close
62 /* we need to use a very terse format here as IRIX 6.4 silently
63 truncates names to 16 chars, so if we use a longer name then we
64 can't tell which port a packet came from with recvfrom()
66 with this format we have 8 chars left for the directory name
68 #define SOCKET_FORMAT "%c%02X%04X"
69 #define SOCKET_TYPE_CHAR_TCP 'T'
70 #define SOCKET_TYPE_CHAR_UDP 'U'
72 static struct sockaddr
*sockaddr_dup(const void *data
, socklen_t len
)
74 struct sockaddr
*ret
= (struct sockaddr
*)malloc(len
);
75 memcpy(ret
, data
, len
);
92 struct sockaddr
*myname
;
95 struct sockaddr
*peername
;
96 socklen_t peername_len
;
98 struct socket_info
*prev
, *next
;
101 static struct socket_info
*sockets
= NULL
;
104 static const char *socket_wrapper_dir(void)
106 const char *s
= getenv("SOCKET_WRAPPER_DIR");
110 if (strncmp(s
, "./", 2) == 0) {
116 static const char *socket_wrapper_dump_dir(void)
118 const char *s
= getenv("SOCKET_WRAPPER_DUMP_DIR");
120 if (!socket_wrapper_dir()) {
127 if (strncmp(s
, "./", 2) == 0) {
133 static unsigned int socket_wrapper_default_iface(void)
135 const char *s
= getenv("SOCKET_WRAPPER_DEFAULT_IFACE");
138 if (sscanf(s
, "%u", &iface
) == 1) {
139 if (iface
>= 1 && iface
<= 0xFF) {
145 return 1;/* 127.0.0.1 */
148 static int convert_un_in(const struct sockaddr_un
*un
, struct sockaddr_in
*in
, socklen_t
*len
)
155 if ((*len
) < sizeof(struct sockaddr_in
)) {
159 p
= strrchr(un
->sun_path
, '/');
160 if (p
) p
++; else p
= un
->sun_path
;
162 if (sscanf(p
, SOCKET_FORMAT
, &type
, &iface
, &prt
) != 3) {
167 if (type
!= SOCKET_TYPE_CHAR_TCP
&& type
!= SOCKET_TYPE_CHAR_UDP
) {
172 if (iface
== 0 || iface
> 0xFF) {
182 in
->sin_family
= AF_INET
;
183 in
->sin_addr
.s_addr
= htonl((127<<24) | iface
);
184 in
->sin_port
= htons(prt
);
186 *len
= sizeof(struct sockaddr_in
);
190 static int convert_in_un_remote(struct socket_info
*si
, const struct sockaddr_in
*in
, struct sockaddr_un
*un
,
197 unsigned int addr
= ntohl(in
->sin_addr
.s_addr
);
198 unsigned int prt
= ntohs(in
->sin_port
);
202 if (bcast
) *bcast
= 0;
211 u_type
= SOCKET_TYPE_CHAR_TCP
;
214 u_type
= SOCKET_TYPE_CHAR_UDP
;
215 a_type
= SOCKET_TYPE_CHAR_UDP
;
216 b_type
= SOCKET_TYPE_CHAR_UDP
;
220 if (a_type
&& addr
== 0xFFFFFFFF) {
221 /* 255.255.255.255 only udp */
224 iface
= socket_wrapper_default_iface();
225 } else if (b_type
&& addr
== 0x7FFFFFFF) {
226 /* 127.255.255.255 only udp */
229 iface
= socket_wrapper_default_iface();
230 } else if ((addr
& 0xFFFFFF00) == 0x7F000000) {
234 iface
= (addr
& 0x000000FF);
240 if (bcast
) *bcast
= is_bcast
;
243 snprintf(un
->sun_path
, sizeof(un
->sun_path
), "%s/EINVAL",
244 socket_wrapper_dir());
245 /* the caller need to do more processing */
249 snprintf(un
->sun_path
, sizeof(un
->sun_path
), "%s/"SOCKET_FORMAT
,
250 socket_wrapper_dir(), type
, iface
, prt
);
255 static int convert_in_un_alloc(struct socket_info
*si
, const struct sockaddr_in
*in
, struct sockaddr_un
*un
,
263 unsigned int addr
= ntohl(in
->sin_addr
.s_addr
);
264 unsigned int prt
= ntohs(in
->sin_port
);
269 if (bcast
) *bcast
= 0;
273 u_type
= SOCKET_TYPE_CHAR_TCP
;
274 d_type
= SOCKET_TYPE_CHAR_TCP
;
277 u_type
= SOCKET_TYPE_CHAR_UDP
;
278 d_type
= SOCKET_TYPE_CHAR_UDP
;
279 a_type
= SOCKET_TYPE_CHAR_UDP
;
280 b_type
= SOCKET_TYPE_CHAR_UDP
;
288 iface
= socket_wrapper_default_iface();
289 } else if (a_type
&& addr
== 0xFFFFFFFF) {
290 /* 255.255.255.255 only udp */
293 iface
= socket_wrapper_default_iface();
294 } else if (b_type
&& addr
== 0x7FFFFFFF) {
295 /* 127.255.255.255 only udp */
298 iface
= socket_wrapper_default_iface();
299 } else if ((addr
& 0xFFFFFF00) == 0x7F000000) {
303 iface
= (addr
& 0x000000FF);
305 errno
= EADDRNOTAVAIL
;
309 if (bcast
) *bcast
= is_bcast
;
312 /* handle auto-allocation of ephemeral ports */
313 for (prt
= 5001; prt
< 10000; prt
++) {
314 snprintf(un
->sun_path
, sizeof(un
->sun_path
), "%s/"SOCKET_FORMAT
,
315 socket_wrapper_dir(), type
, iface
, prt
);
316 if (stat(un
->sun_path
, &st
) == 0) continue;
318 ((struct sockaddr_in
*)si
->myname
)->sin_port
= htons(prt
);
325 snprintf(un
->sun_path
, sizeof(un
->sun_path
), "%s/"SOCKET_FORMAT
,
326 socket_wrapper_dir(), type
, iface
, prt
);
330 static struct socket_info
*find_socket_info(int fd
)
332 struct socket_info
*i
;
333 for (i
= sockets
; i
; i
= i
->next
) {
341 static int sockaddr_convert_to_un(struct socket_info
*si
, const struct sockaddr
*in_addr
, socklen_t in_len
,
342 struct sockaddr_un
*out_addr
, int alloc_sock
, int *bcast
)
347 out_addr
->sun_family
= AF_UNIX
;
349 switch (in_addr
->sa_family
) {
356 errno
= ESOCKTNOSUPPORT
;
360 return convert_in_un_alloc(si
, (const struct sockaddr_in
*)in_addr
, out_addr
, bcast
);
362 return convert_in_un_remote(si
, (const struct sockaddr_in
*)in_addr
, out_addr
, bcast
);
368 errno
= EAFNOSUPPORT
;
372 static int sockaddr_convert_from_un(const struct socket_info
*si
,
373 const struct sockaddr_un
*in_addr
,
374 socklen_t un_addrlen
,
376 struct sockaddr
*out_addr
,
377 socklen_t
*_out_addrlen
)
379 socklen_t out_addrlen
;
381 if (out_addr
== NULL
|| _out_addrlen
== NULL
)
384 if (un_addrlen
== 0) {
389 out_addrlen
= *_out_addrlen
;
390 if (out_addrlen
> un_addrlen
) {
391 out_addrlen
= un_addrlen
;
401 errno
= ESOCKTNOSUPPORT
;
404 return convert_un_in(in_addr
, (struct sockaddr_in
*)out_addr
, _out_addrlen
);
409 errno
= EAFNOSUPPORT
;
413 enum swrap_packet_type
{
423 static void swrap_dump_packet(struct socket_info
*si
, const struct sockaddr
*addr
,
424 enum swrap_packet_type type
,
425 const void *buf
, size_t len
, ssize_t ret
)
427 if (!socket_wrapper_dump_dir()) {
433 _PUBLIC_
int swrap_socket(int family
, int type
, int protocol
)
435 struct socket_info
*si
;
438 if (!socket_wrapper_dir()) {
439 return real_socket(family
, type
, protocol
);
446 return real_socket(family
, type
, protocol
);
448 errno
= EAFNOSUPPORT
;
452 fd
= real_socket(AF_UNIX
, type
, 0);
454 if (fd
== -1) return -1;
456 si
= calloc(1, sizeof(struct socket_info
));
460 si
->protocol
= protocol
;
463 DLIST_ADD(sockets
, si
);
468 _PUBLIC_
int swrap_accept(int s
, struct sockaddr
*addr
, socklen_t
*addrlen
)
470 struct socket_info
*parent_si
, *child_si
;
472 struct sockaddr_un un_addr
;
473 socklen_t un_addrlen
= sizeof(un_addr
);
474 struct sockaddr_un un_my_addr
;
475 socklen_t un_my_addrlen
= sizeof(un_my_addr
);
476 struct sockaddr my_addr
;
477 socklen_t my_addrlen
= sizeof(my_addr
);
480 parent_si
= find_socket_info(s
);
482 return real_accept(s
, addr
, addrlen
);
485 memset(&un_addr
, 0, sizeof(un_addr
));
486 memset(&un_my_addr
, 0, sizeof(un_my_addr
));
487 memset(&my_addr
, 0, sizeof(my_addr
));
489 ret
= real_accept(s
, (struct sockaddr
*)&un_addr
, &un_addrlen
);
490 if (ret
== -1) return ret
;
494 ret
= sockaddr_convert_from_un(parent_si
, &un_addr
, un_addrlen
,
495 parent_si
->family
, addr
, addrlen
);
496 if (ret
== -1) return ret
;
498 child_si
= malloc(sizeof(struct socket_info
));
499 memset(child_si
, 0, sizeof(*child_si
));
502 child_si
->family
= parent_si
->family
;
503 child_si
->type
= parent_si
->type
;
504 child_si
->protocol
= parent_si
->protocol
;
507 ret
= real_getsockname(fd
, (struct sockaddr
*)&un_my_addr
, &un_my_addrlen
);
508 if (ret
== -1) return ret
;
510 ret
= sockaddr_convert_from_un(child_si
, &un_my_addr
, un_my_addrlen
,
511 child_si
->family
, &my_addr
, &my_addrlen
);
512 if (ret
== -1) return ret
;
514 child_si
->myname_len
= my_addrlen
;
515 child_si
->myname
= sockaddr_dup(&my_addr
, my_addrlen
);
517 child_si
->peername_len
= *addrlen
;
518 child_si
->peername
= sockaddr_dup(addr
, *addrlen
);
520 DLIST_ADD(sockets
, child_si
);
522 swrap_dump_packet(child_si
, addr
, SWRAP_ACCEPT
, NULL
, 0, 0);
527 /* using sendto() or connect() on an unbound socket would give the
528 recipient no way to reply, as unlike UDP and TCP, a unix domain
529 socket can't auto-assign emphemeral port numbers, so we need to
531 static int swrap_auto_bind(struct socket_info
*si
)
533 struct sockaddr_un un_addr
;
534 struct sockaddr_in in
;
540 un_addr
.sun_family
= AF_UNIX
;
544 type
= SOCKET_TYPE_CHAR_TCP
;
547 type
= SOCKET_TYPE_CHAR_UDP
;
550 errno
= ESOCKTNOSUPPORT
;
554 for (i
=0;i
<1000;i
++) {
555 snprintf(un_addr
.sun_path
, sizeof(un_addr
.sun_path
),
556 "%s/"SOCKET_FORMAT
, socket_wrapper_dir(),
557 type
, socket_wrapper_default_iface(), i
+ 10000);
558 if (stat(un_addr
.sun_path
, &st
) == 0) continue;
560 ret
= real_bind(si
->fd
, (struct sockaddr
*)&un_addr
, sizeof(un_addr
));
561 if (ret
== -1) return ret
;
563 si
->tmp_path
= strdup(un_addr
.sun_path
);
572 memset(&in
, 0, sizeof(in
));
573 in
.sin_family
= AF_INET
;
574 in
.sin_port
= htons(i
);
575 in
.sin_addr
.s_addr
= htonl(127<<24 | socket_wrapper_default_iface());
577 si
->myname_len
= sizeof(in
);
578 si
->myname
= sockaddr_dup(&in
, si
->myname_len
);
584 _PUBLIC_
int swrap_connect(int s
, const struct sockaddr
*serv_addr
, socklen_t addrlen
)
587 struct sockaddr_un un_addr
;
588 struct socket_info
*si
= find_socket_info(s
);
591 return real_connect(s
, serv_addr
, addrlen
);
594 if (si
->bound
== 0) {
595 ret
= swrap_auto_bind(si
);
596 if (ret
== -1) return -1;
599 ret
= sockaddr_convert_to_un(si
, (const struct sockaddr
*)serv_addr
, addrlen
, &un_addr
, 0, NULL
);
600 if (ret
== -1) return -1;
602 ret
= real_connect(s
, (struct sockaddr
*)&un_addr
,
603 sizeof(struct sockaddr_un
));
605 /* to give better errors */
606 if (ret
== -1 && errno
== ENOENT
) {
607 errno
= EHOSTUNREACH
;
611 si
->peername_len
= addrlen
;
612 si
->peername
= sockaddr_dup(serv_addr
, addrlen
);
615 swrap_dump_packet(si
, serv_addr
, SWRAP_CONNECT
, NULL
, 0, ret
);
620 _PUBLIC_
int swrap_bind(int s
, const struct sockaddr
*myaddr
, socklen_t addrlen
)
623 struct sockaddr_un un_addr
;
624 struct socket_info
*si
= find_socket_info(s
);
627 return real_bind(s
, myaddr
, addrlen
);
630 si
->myname_len
= addrlen
;
631 si
->myname
= sockaddr_dup(myaddr
, addrlen
);
633 ret
= sockaddr_convert_to_un(si
, (const struct sockaddr
*)myaddr
, addrlen
, &un_addr
, 1, &si
->bcast
);
634 if (ret
== -1) return -1;
636 unlink(un_addr
.sun_path
);
638 ret
= real_bind(s
, (struct sockaddr
*)&un_addr
,
639 sizeof(struct sockaddr_un
));
648 _PUBLIC_
int swrap_getpeername(int s
, struct sockaddr
*name
, socklen_t
*addrlen
)
650 struct socket_info
*si
= find_socket_info(s
);
653 return real_getpeername(s
, name
, addrlen
);
662 memcpy(name
, si
->peername
, si
->peername_len
);
663 *addrlen
= si
->peername_len
;
668 _PUBLIC_
int swrap_getsockname(int s
, struct sockaddr
*name
, socklen_t
*addrlen
)
670 struct socket_info
*si
= find_socket_info(s
);
673 return real_getsockname(s
, name
, addrlen
);
676 memcpy(name
, si
->myname
, si
->myname_len
);
677 *addrlen
= si
->myname_len
;
682 _PUBLIC_
int swrap_getsockopt(int s
, int level
, int optname
, void *optval
, socklen_t
*optlen
)
684 struct socket_info
*si
= find_socket_info(s
);
687 return real_getsockopt(s
, level
, optname
, optval
, optlen
);
690 if (level
== SOL_SOCKET
) {
691 return real_getsockopt(s
, level
, optname
, optval
, optlen
);
698 _PUBLIC_
int swrap_setsockopt(int s
, int level
, int optname
, const void *optval
, socklen_t optlen
)
700 struct socket_info
*si
= find_socket_info(s
);
703 return real_setsockopt(s
, level
, optname
, optval
, optlen
);
706 if (level
== SOL_SOCKET
) {
707 return real_setsockopt(s
, level
, optname
, optval
, optlen
);
710 switch (si
->family
) {
719 _PUBLIC_ ssize_t
swrap_recvfrom(int s
, void *buf
, size_t len
, int flags
, struct sockaddr
*from
, socklen_t
*fromlen
)
721 struct sockaddr_un un_addr
;
722 socklen_t un_addrlen
= sizeof(un_addr
);
724 struct socket_info
*si
= find_socket_info(s
);
727 return real_recvfrom(s
, buf
, len
, flags
, from
, fromlen
);
730 /* irix 6.4 forgets to null terminate the sun_path string :-( */
731 memset(&un_addr
, 0, sizeof(un_addr
));
732 ret
= real_recvfrom(s
, buf
, len
, flags
, (struct sockaddr
*)&un_addr
, &un_addrlen
);
736 if (sockaddr_convert_from_un(si
, &un_addr
, un_addrlen
,
737 si
->family
, from
, fromlen
) == -1) {
741 swrap_dump_packet(si
, from
, SWRAP_RECVFROM
, buf
, len
, ret
);
747 _PUBLIC_ ssize_t
swrap_sendto(int s
, const void *buf
, size_t len
, int flags
, const struct sockaddr
*to
, socklen_t tolen
)
749 struct sockaddr_un un_addr
;
751 struct socket_info
*si
= find_socket_info(s
);
755 return real_sendto(s
, buf
, len
, flags
, to
, tolen
);
758 if (si
->bound
== 0) {
759 ret
= swrap_auto_bind(si
);
760 if (ret
== -1) return -1;
763 ret
= sockaddr_convert_to_un(si
, to
, tolen
, &un_addr
, 0, &bcast
);
764 if (ret
== -1) return -1;
769 unsigned int prt
= ntohs(((const struct sockaddr_in
*)to
)->sin_port
);
772 type
= SOCKET_TYPE_CHAR_UDP
;
774 for(iface
=0; iface
<= 0xFF; iface
++) {
775 snprintf(un_addr
.sun_path
, sizeof(un_addr
.sun_path
), "%s/"SOCKET_FORMAT
,
776 socket_wrapper_dir(), type
, iface
, prt
);
777 if (stat(un_addr
.sun_path
, &st
) != 0) continue;
779 /* ignore the any errors in broadcast sends */
780 real_sendto(s
, buf
, len
, flags
, (struct sockaddr
*)&un_addr
, sizeof(un_addr
));
783 swrap_dump_packet(si
, to
, SWRAP_SENDTO
, buf
, len
, len
);
788 ret
= real_sendto(s
, buf
, len
, flags
, (struct sockaddr
*)&un_addr
, sizeof(un_addr
));
790 /* to give better errors */
791 if (ret
== -1 && errno
== ENOENT
) {
792 errno
= EHOSTUNREACH
;
795 swrap_dump_packet(si
, to
, SWRAP_SENDTO
, buf
, len
, ret
);
800 _PUBLIC_ ssize_t
swrap_recv(int s
, void *buf
, size_t len
, int flags
)
803 struct socket_info
*si
= find_socket_info(s
);
806 return real_recv(s
, buf
, len
, flags
);
809 ret
= real_recv(s
, buf
, len
, flags
);
813 swrap_dump_packet(si
, NULL
, SWRAP_RECV
, buf
, len
, ret
);
819 _PUBLIC_ ssize_t
swrap_send(int s
, const void *buf
, size_t len
, int flags
)
822 struct socket_info
*si
= find_socket_info(s
);
825 return real_send(s
, buf
, len
, flags
);
828 ret
= real_send(s
, buf
, len
, flags
);
832 swrap_dump_packet(si
, NULL
, SWRAP_SEND
, buf
, len
, ret
);
837 _PUBLIC_
int swrap_close(int fd
)
839 struct socket_info
*si
= find_socket_info(fd
);
842 DLIST_REMOVE(sockets
, si
);
844 swrap_dump_packet(si
, NULL
, SWRAP_CLOSE
, NULL
, 0, 0);
850 unlink(si
->tmp_path
);
856 return real_close(fd
);