swrap: Wrap fopen to detect stale file descriptors.
[Samba.git] / lib / socket_wrapper / socket_wrapper.c
blob574f5ba71af359eca03df16d6d5bd2746f0ba6bc
1 /*
2 * Copyright (C) Jelmer Vernooij 2005,2008 <jelmer@samba.org>
3 * Copyright (C) Stefan Metzmacher 2006-2009 <metze@samba.org>
4 * Copyright (C) Andreas Schneider 2013 <asn@samba.org>
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the author nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
38 Socket wrapper library. Passes all socket communication over
39 unix domain sockets if the environment variable SOCKET_WRAPPER_DIR
40 is set.
43 #include "config.h"
45 #include <sys/types.h>
46 #include <sys/time.h>
47 #include <sys/stat.h>
48 #include <sys/socket.h>
49 #include <sys/ioctl.h>
50 #ifdef HAVE_SYS_FILIO_H
51 #include <sys/filio.h>
52 #endif
53 #ifdef HAVE_SYS_SIGNALFD_H
54 #include <sys/signalfd.h>
55 #endif
56 #ifdef HAVE_SYS_EVENTFD_H
57 #include <sys/eventfd.h>
58 #endif
59 #ifdef HAVE_SYS_TIMERFD_H
60 #include <sys/timerfd.h>
61 #endif
62 #include <sys/uio.h>
63 #include <errno.h>
64 #include <sys/un.h>
65 #include <netinet/in.h>
66 #include <netinet/tcp.h>
67 #include <arpa/inet.h>
68 #include <fcntl.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #include <stdio.h>
72 #include <stdint.h>
73 #include <stdarg.h>
74 #include <stdbool.h>
75 #include <unistd.h>
76 #ifdef HAVE_GNU_LIB_NAMES_H
77 #include <gnu/lib-names.h>
78 #endif
79 #ifdef HAVE_RPC_RPC_H
80 #include <rpc/rpc.h>
81 #endif
83 enum swrap_dbglvl_e {
84 SWRAP_LOG_ERROR = 0,
85 SWRAP_LOG_WARN,
86 SWRAP_LOG_DEBUG,
87 SWRAP_LOG_TRACE
90 /* GCC have printf type attribute check. */
91 #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
92 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
93 #else
94 #define PRINTF_ATTRIBUTE(a,b)
95 #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
97 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
98 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
99 #else
100 #define DESTRUCTOR_ATTRIBUTE
101 #endif
103 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
104 # define SWRAP_THREAD __thread
105 #else
106 # define SWRAP_THREAD
107 #endif
109 #ifndef MIN
110 #define MIN(a,b) ((a)<(b)?(a):(b))
111 #endif
113 #ifndef ZERO_STRUCT
114 #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
115 #endif
117 #ifndef ZERO_STRUCTP
118 #define ZERO_STRUCTP(x) do { \
119 if ((x) != NULL) \
120 memset((char *)(x), 0, sizeof(*(x))); \
121 } while(0)
122 #endif
124 #ifndef discard_const
125 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
126 #endif
128 #ifndef discard_const_p
129 #define discard_const_p(type, ptr) ((type *)discard_const(ptr))
130 #endif
132 #ifdef IPV6_PKTINFO
133 # ifndef IPV6_RECVPKTINFO
134 # define IPV6_RECVPKTINFO IPV6_PKTINFO
135 # endif /* IPV6_RECVPKTINFO */
136 #endif /* IPV6_PKTINFO */
139 * On BSD IP_PKTINFO has a different name because during
140 * the time when they implemented it, there was no RFC.
141 * The name for IPv6 is the same as on Linux.
143 #ifndef IP_PKTINFO
144 # ifdef IP_RECVDSTADDR
145 # define IP_PKTINFO IP_RECVDSTADDR
146 # endif
147 #endif
150 #define SWRAP_DLIST_ADD(list,item) do { \
151 if (!(list)) { \
152 (item)->prev = NULL; \
153 (item)->next = NULL; \
154 (list) = (item); \
155 } else { \
156 (item)->prev = NULL; \
157 (item)->next = (list); \
158 (list)->prev = (item); \
159 (list) = (item); \
161 } while (0)
163 #define SWRAP_DLIST_REMOVE(list,item) do { \
164 if ((list) == (item)) { \
165 (list) = (item)->next; \
166 if (list) { \
167 (list)->prev = NULL; \
169 } else { \
170 if ((item)->prev) { \
171 (item)->prev->next = (item)->next; \
173 if ((item)->next) { \
174 (item)->next->prev = (item)->prev; \
177 (item)->prev = NULL; \
178 (item)->next = NULL; \
179 } while (0)
181 #if defined(HAVE_GETTIMEOFDAY_TZ) || defined(HAVE_GETTIMEOFDAY_TZ_VOID)
182 #define swrapGetTimeOfDay(tval) gettimeofday(tval,NULL)
183 #else
184 #define swrapGetTimeOfDay(tval) gettimeofday(tval)
185 #endif
187 /* we need to use a very terse format here as IRIX 6.4 silently
188 truncates names to 16 chars, so if we use a longer name then we
189 can't tell which port a packet came from with recvfrom()
191 with this format we have 8 chars left for the directory name
193 #define SOCKET_FORMAT "%c%02X%04X"
194 #define SOCKET_TYPE_CHAR_TCP 'T'
195 #define SOCKET_TYPE_CHAR_UDP 'U'
196 #define SOCKET_TYPE_CHAR_TCP_V6 'X'
197 #define SOCKET_TYPE_CHAR_UDP_V6 'Y'
200 * Cut down to 1500 byte packets for stream sockets,
201 * which makes it easier to format PCAP capture files
202 * (as the caller will simply continue from here)
204 #define SOCKET_MAX_PACKET 1500
206 #define SOCKET_MAX_SOCKETS 1024
208 /* This limit is to avoid broadcast sendto() needing to stat too many
209 * files. It may be raised (with a performance cost) to up to 254
210 * without changing the format above */
211 #define MAX_WRAPPED_INTERFACES 40
213 struct swrap_address {
214 socklen_t sa_socklen;
215 union {
216 struct sockaddr s;
217 struct sockaddr_in in;
218 #ifdef HAVE_IPV6
219 struct sockaddr_in6 in6;
220 #endif
221 struct sockaddr_un un;
222 struct sockaddr_storage ss;
223 } sa;
226 struct socket_info_fd {
227 struct socket_info_fd *prev, *next;
228 int fd;
231 struct socket_info
233 struct socket_info_fd *fds;
235 int family;
236 int type;
237 int protocol;
238 int bound;
239 int bcast;
240 int is_server;
241 int connected;
242 int defer_connect;
243 int pktinfo;
245 /* The unix path so we can unlink it on close() */
246 struct sockaddr_un un_addr;
248 struct swrap_address bindname;
249 struct swrap_address myname;
250 struct swrap_address peername;
252 struct {
253 unsigned long pck_snd;
254 unsigned long pck_rcv;
255 } io;
257 struct socket_info *prev, *next;
261 * File descriptors are shared between threads so we should share socket
262 * information too.
264 struct socket_info *sockets;
266 /* Function prototypes */
268 bool socket_wrapper_enabled(void);
269 void swrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
271 #ifdef NDEBUG
272 # define SWRAP_LOG(...)
273 #else
275 static void swrap_log(enum swrap_dbglvl_e dbglvl, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
276 # define SWRAP_LOG(dbglvl, ...) swrap_log((dbglvl), __VA_ARGS__)
278 static void swrap_log(enum swrap_dbglvl_e dbglvl, const char *format, ...)
280 char buffer[1024];
281 va_list va;
282 const char *d;
283 unsigned int lvl = 0;
285 d = getenv("SOCKET_WRAPPER_DEBUGLEVEL");
286 if (d != NULL) {
287 lvl = atoi(d);
290 va_start(va, format);
291 vsnprintf(buffer, sizeof(buffer), format, va);
292 va_end(va);
294 if (lvl >= dbglvl) {
295 switch (dbglvl) {
296 case SWRAP_LOG_ERROR:
297 fprintf(stderr,
298 "SWRAP_ERROR(%d): %s\n",
299 (int)getpid(), buffer);
300 break;
301 case SWRAP_LOG_WARN:
302 fprintf(stderr,
303 "SWRAP_WARN(%d): %s\n",
304 (int)getpid(), buffer);
305 break;
306 case SWRAP_LOG_DEBUG:
307 fprintf(stderr,
308 "SWRAP_DEBUG(%d): %s\n",
309 (int)getpid(), buffer);
310 break;
311 case SWRAP_LOG_TRACE:
312 fprintf(stderr,
313 "SWRAP_TRACE(%d): %s\n",
314 (int)getpid(), buffer);
315 break;
319 #endif
321 /*********************************************************
322 * SWRAP LOADING LIBC FUNCTIONS
323 *********************************************************/
325 #include <dlfcn.h>
327 struct swrap_libc_fns {
328 int (*libc_accept)(int sockfd,
329 struct sockaddr *addr,
330 socklen_t *addrlen);
331 int (*libc_bind)(int sockfd,
332 const struct sockaddr *addr,
333 socklen_t addrlen);
334 int (*libc_close)(int fd);
335 int (*libc_connect)(int sockfd,
336 const struct sockaddr *addr,
337 socklen_t addrlen);
338 int (*libc_dup)(int fd);
339 int (*libc_dup2)(int oldfd, int newfd);
340 FILE *(*libc_fopen)(const char *name, const char *mode);
341 #ifdef HAVE_EVENTFD
342 int (*libc_eventfd)(int count, int flags);
343 #endif
344 int (*libc_getpeername)(int sockfd,
345 struct sockaddr *addr,
346 socklen_t *addrlen);
347 int (*libc_getsockname)(int sockfd,
348 struct sockaddr *addr,
349 socklen_t *addrlen);
350 int (*libc_getsockopt)(int sockfd,
351 int level,
352 int optname,
353 void *optval,
354 socklen_t *optlen);
355 int (*libc_ioctl)(int d, unsigned long int request, ...);
356 int (*libc_listen)(int sockfd, int backlog);
357 int (*libc_open)(const char *pathname, int flags, mode_t mode);
358 int (*libc_pipe)(int pipefd[2]);
359 int (*libc_read)(int fd, void *buf, size_t count);
360 ssize_t (*libc_readv)(int fd, const struct iovec *iov, int iovcnt);
361 int (*libc_recv)(int sockfd, void *buf, size_t len, int flags);
362 int (*libc_recvfrom)(int sockfd,
363 void *buf,
364 size_t len,
365 int flags,
366 struct sockaddr *src_addr,
367 socklen_t *addrlen);
368 int (*libc_recvmsg)(int sockfd, const struct msghdr *msg, int flags);
369 int (*libc_send)(int sockfd, const void *buf, size_t len, int flags);
370 int (*libc_sendmsg)(int sockfd, const struct msghdr *msg, int flags);
371 int (*libc_sendto)(int sockfd,
372 const void *buf,
373 size_t len,
374 int flags,
375 const struct sockaddr *dst_addr,
376 socklen_t addrlen);
377 int (*libc_setsockopt)(int sockfd,
378 int level,
379 int optname,
380 const void *optval,
381 socklen_t optlen);
382 #ifdef HAVE_SIGNALFD
383 int (*libc_signalfd)(int fd, const sigset_t *mask, int flags);
384 #endif
385 int (*libc_socket)(int domain, int type, int protocol);
386 int (*libc_socketpair)(int domain, int type, int protocol, int sv[2]);
387 #ifdef HAVE_TIMERFD_CREATE
388 int (*libc_timerfd_create)(int clockid, int flags);
389 #endif
390 ssize_t (*libc_writev)(int fd, const struct iovec *iov, int iovcnt);
393 struct swrap {
394 void *libc_handle;
395 void *libsocket_handle;
397 bool initialised;
398 bool enabled;
400 char *socket_dir;
402 struct swrap_libc_fns fns;
405 static struct swrap swrap;
407 /* prototypes */
408 static const char *socket_wrapper_dir(void);
410 #define LIBC_NAME "libc.so"
412 enum swrap_lib {
413 SWRAP_LIBC,
414 SWRAP_LIBNSL,
415 SWRAP_LIBSOCKET,
418 #ifndef NDEBUG
419 static const char *swrap_str_lib(enum swrap_lib lib)
421 switch (lib) {
422 case SWRAP_LIBC:
423 return "libc";
424 case SWRAP_LIBNSL:
425 return "libnsl";
426 case SWRAP_LIBSOCKET:
427 return "libsocket";
430 /* Compiler would warn us about unhandled enum value if we get here */
431 return "unknown";
433 #endif
435 static void *swrap_load_lib_handle(enum swrap_lib lib)
437 int flags = RTLD_LAZY;
438 void *handle = NULL;
439 int i;
441 #ifdef RTLD_DEEPBIND
442 flags |= RTLD_DEEPBIND;
443 #endif
445 switch (lib) {
446 case SWRAP_LIBNSL:
447 /* FALL TROUGH */
448 case SWRAP_LIBSOCKET:
449 #ifdef HAVE_LIBSOCKET
450 handle = swrap.libsocket_handle;
451 if (handle == NULL) {
452 for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) {
453 char soname[256] = {0};
455 snprintf(soname, sizeof(soname), "libsocket.so.%d", i);
456 handle = dlopen(soname, flags);
459 swrap.libsocket_handle = handle;
461 break;
462 #endif
463 /* FALL TROUGH */
464 case SWRAP_LIBC:
465 handle = swrap.libc_handle;
466 #ifdef LIBC_SO
467 if (handle == NULL) {
468 handle = dlopen(LIBC_SO, flags);
470 swrap.libc_handle = handle;
472 #endif
473 if (handle == NULL) {
474 for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) {
475 char soname[256] = {0};
477 snprintf(soname, sizeof(soname), "libc.so.%d", i);
478 handle = dlopen(soname, flags);
481 swrap.libc_handle = handle;
483 break;
486 if (handle == NULL) {
487 #ifdef RTLD_NEXT
488 handle = swrap.libc_handle = swrap.libsocket_handle = RTLD_NEXT;
489 #else
490 SWRAP_LOG(SWRAP_LOG_ERROR,
491 "Failed to dlopen library: %s\n",
492 dlerror());
493 exit(-1);
494 #endif
497 return handle;
500 static void *_swrap_load_lib_function(enum swrap_lib lib, const char *fn_name)
502 void *handle;
503 void *func;
505 handle = swrap_load_lib_handle(lib);
507 func = dlsym(handle, fn_name);
508 if (func == NULL) {
509 SWRAP_LOG(SWRAP_LOG_ERROR,
510 "Failed to find %s: %s\n",
511 fn_name, dlerror());
512 exit(-1);
515 SWRAP_LOG(SWRAP_LOG_TRACE,
516 "Loaded %s from %s",
517 fn_name, swrap_str_lib(lib));
518 return func;
521 #define swrap_load_lib_function(lib, fn_name) \
522 if (swrap.fns.libc_##fn_name == NULL) { \
523 *(void **) (&swrap.fns.libc_##fn_name) = \
524 _swrap_load_lib_function(lib, #fn_name); \
529 * IMPORTANT
531 * Functions especially from libc need to be loaded individually, you can't load
532 * all at once or gdb will segfault at startup. The same applies to valgrind and
533 * has probably something todo with with the linker.
534 * So we need load each function at the point it is called the first time.
536 static int libc_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
538 swrap_load_lib_function(SWRAP_LIBSOCKET, accept);
540 return swrap.fns.libc_accept(sockfd, addr, addrlen);
543 static int libc_bind(int sockfd,
544 const struct sockaddr *addr,
545 socklen_t addrlen)
547 swrap_load_lib_function(SWRAP_LIBSOCKET, bind);
549 return swrap.fns.libc_bind(sockfd, addr, addrlen);
552 static int libc_close(int fd)
554 swrap_load_lib_function(SWRAP_LIBC, close);
556 return swrap.fns.libc_close(fd);
559 static int libc_connect(int sockfd,
560 const struct sockaddr *addr,
561 socklen_t addrlen)
563 swrap_load_lib_function(SWRAP_LIBSOCKET, connect);
565 return swrap.fns.libc_connect(sockfd, addr, addrlen);
568 static int libc_dup(int fd)
570 swrap_load_lib_function(SWRAP_LIBC, dup);
572 return swrap.fns.libc_dup(fd);
575 static int libc_dup2(int oldfd, int newfd)
577 swrap_load_lib_function(SWRAP_LIBC, dup2);
579 return swrap.fns.libc_dup2(oldfd, newfd);
582 #ifdef HAVE_EVENTFD
583 static int libc_eventfd(int count, int flags)
585 swrap_load_lib_function(SWRAP_LIBC, eventfd);
587 return swrap.fns.libc_eventfd(count, flags);
589 #endif
591 static int libc_getpeername(int sockfd,
592 struct sockaddr *addr,
593 socklen_t *addrlen)
595 swrap_load_lib_function(SWRAP_LIBSOCKET, getpeername);
597 return swrap.fns.libc_getpeername(sockfd, addr, addrlen);
600 static int libc_getsockname(int sockfd,
601 struct sockaddr *addr,
602 socklen_t *addrlen)
604 swrap_load_lib_function(SWRAP_LIBSOCKET, getsockname);
606 return swrap.fns.libc_getsockname(sockfd, addr, addrlen);
609 static int libc_getsockopt(int sockfd,
610 int level,
611 int optname,
612 void *optval,
613 socklen_t *optlen)
615 swrap_load_lib_function(SWRAP_LIBSOCKET, getsockopt);
617 return swrap.fns.libc_getsockopt(sockfd, level, optname, optval, optlen);
620 static int libc_vioctl(int d, unsigned long int request, va_list ap)
622 long int args[4];
623 int rc;
624 int i;
626 swrap_load_lib_function(SWRAP_LIBC, ioctl);
628 for (i = 0; i < 4; i++) {
629 args[i] = va_arg(ap, long int);
632 rc = swrap.fns.libc_ioctl(d,
633 request,
634 args[0],
635 args[1],
636 args[2],
637 args[3]);
639 return rc;
642 static int libc_listen(int sockfd, int backlog)
644 swrap_load_lib_function(SWRAP_LIBSOCKET, listen);
646 return swrap.fns.libc_listen(sockfd, backlog);
649 static FILE *libc_fopen(const char *name, const char *mode)
651 swrap_load_lib_function(SWRAP_LIBC, fopen);
653 return swrap.fns.libc_fopen(name, mode);
656 static int libc_vopen(const char *pathname, int flags, va_list ap)
658 long int mode = 0;
659 int fd;
661 swrap_load_lib_function(SWRAP_LIBC, open);
663 mode = va_arg(ap, long int);
665 fd = swrap.fns.libc_open(pathname, flags, (mode_t)mode);
667 return fd;
670 static int libc_open(const char *pathname, int flags, ...)
672 va_list ap;
673 int fd;
675 va_start(ap, flags);
676 fd = libc_vopen(pathname, flags, ap);
677 va_end(ap);
679 return fd;
682 static int libc_pipe(int pipefd[2])
684 swrap_load_lib_function(SWRAP_LIBSOCKET, pipe);
686 return swrap.fns.libc_pipe(pipefd);
689 static int libc_read(int fd, void *buf, size_t count)
691 swrap_load_lib_function(SWRAP_LIBC, read);
693 return swrap.fns.libc_read(fd, buf, count);
696 static ssize_t libc_readv(int fd, const struct iovec *iov, int iovcnt)
698 swrap_load_lib_function(SWRAP_LIBSOCKET, readv);
700 return swrap.fns.libc_readv(fd, iov, iovcnt);
703 static int libc_recv(int sockfd, void *buf, size_t len, int flags)
705 swrap_load_lib_function(SWRAP_LIBSOCKET, recv);
707 return swrap.fns.libc_recv(sockfd, buf, len, flags);
710 static int libc_recvfrom(int sockfd,
711 void *buf,
712 size_t len,
713 int flags,
714 struct sockaddr *src_addr,
715 socklen_t *addrlen)
717 swrap_load_lib_function(SWRAP_LIBSOCKET, recvfrom);
719 return swrap.fns.libc_recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
722 static int libc_recvmsg(int sockfd, struct msghdr *msg, int flags)
724 swrap_load_lib_function(SWRAP_LIBSOCKET, recvmsg);
726 return swrap.fns.libc_recvmsg(sockfd, msg, flags);
729 static int libc_send(int sockfd, const void *buf, size_t len, int flags)
731 swrap_load_lib_function(SWRAP_LIBSOCKET, send);
733 return swrap.fns.libc_send(sockfd, buf, len, flags);
736 static int libc_sendmsg(int sockfd, const struct msghdr *msg, int flags)
738 swrap_load_lib_function(SWRAP_LIBSOCKET, sendmsg);
740 return swrap.fns.libc_sendmsg(sockfd, msg, flags);
743 static int libc_sendto(int sockfd,
744 const void *buf,
745 size_t len,
746 int flags,
747 const struct sockaddr *dst_addr,
748 socklen_t addrlen)
750 swrap_load_lib_function(SWRAP_LIBSOCKET, sendto);
752 return swrap.fns.libc_sendto(sockfd, buf, len, flags, dst_addr, addrlen);
755 static int libc_setsockopt(int sockfd,
756 int level,
757 int optname,
758 const void *optval,
759 socklen_t optlen)
761 swrap_load_lib_function(SWRAP_LIBSOCKET, setsockopt);
763 return swrap.fns.libc_setsockopt(sockfd, level, optname, optval, optlen);
766 #ifdef HAVE_SIGNALFD
767 static int libc_signalfd(int fd, const sigset_t *mask, int flags)
769 swrap_load_lib_function(SWRAP_LIBSOCKET, signalfd);
771 return swrap.fns.libc_signalfd(fd, mask, flags);
773 #endif
775 static int libc_socket(int domain, int type, int protocol)
777 swrap_load_lib_function(SWRAP_LIBSOCKET, socket);
779 return swrap.fns.libc_socket(domain, type, protocol);
782 static int libc_socketpair(int domain, int type, int protocol, int sv[2])
784 swrap_load_lib_function(SWRAP_LIBSOCKET, socketpair);
786 return swrap.fns.libc_socketpair(domain, type, protocol, sv);
789 #ifdef HAVE_TIMERFD_CREATE
790 static int libc_timerfd_create(int clockid, int flags)
792 swrap_load_lib_function(SWRAP_LIBC, timerfd_create);
794 return swrap.fns.libc_timerfd_create(clockid, flags);
796 #endif
798 static ssize_t libc_writev(int fd, const struct iovec *iov, int iovcnt)
800 swrap_load_lib_function(SWRAP_LIBSOCKET, writev);
802 return swrap.fns.libc_writev(fd, iov, iovcnt);
805 /*********************************************************
806 * SWRAP HELPER FUNCTIONS
807 *********************************************************/
809 #ifdef HAVE_IPV6
811 * FD00::5357:5FXX
813 static const struct in6_addr *swrap_ipv6(void)
815 static struct in6_addr v;
816 static int initialized;
817 int ret;
819 if (initialized) {
820 return &v;
822 initialized = 1;
824 ret = inet_pton(AF_INET6, "FD00::5357:5F00", &v);
825 if (ret <= 0) {
826 abort();
829 return &v;
831 #endif
833 static void set_port(int family, int prt, struct swrap_address *addr)
835 switch (family) {
836 case AF_INET:
837 addr->sa.in.sin_port = htons(prt);
838 break;
839 #ifdef HAVE_IPV6
840 case AF_INET6:
841 addr->sa.in6.sin6_port = htons(prt);
842 break;
843 #endif
847 static size_t socket_length(int family)
849 switch (family) {
850 case AF_INET:
851 return sizeof(struct sockaddr_in);
852 #ifdef HAVE_IPV6
853 case AF_INET6:
854 return sizeof(struct sockaddr_in6);
855 #endif
857 return 0;
860 static const char *socket_wrapper_dir(void)
862 const char *s = getenv("SOCKET_WRAPPER_DIR");
863 if (s == NULL) {
864 return NULL;
866 /* TODO use realpath(3) here, when we add support for threads */
867 if (strncmp(s, "./", 2) == 0) {
868 s += 2;
871 SWRAP_LOG(SWRAP_LOG_TRACE, "socket_wrapper_dir: %s", s);
872 return s;
875 bool socket_wrapper_enabled(void)
877 const char *s = socket_wrapper_dir();
879 return s != NULL ? true : false;
882 static unsigned int socket_wrapper_default_iface(void)
884 const char *s = getenv("SOCKET_WRAPPER_DEFAULT_IFACE");
885 if (s) {
886 unsigned int iface;
887 if (sscanf(s, "%u", &iface) == 1) {
888 if (iface >= 1 && iface <= MAX_WRAPPED_INTERFACES) {
889 return iface;
894 return 1;/* 127.0.0.1 */
897 static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, socklen_t *len)
899 unsigned int iface;
900 unsigned int prt;
901 const char *p;
902 char type;
904 p = strrchr(un->sun_path, '/');
905 if (p) p++; else p = un->sun_path;
907 if (sscanf(p, SOCKET_FORMAT, &type, &iface, &prt) != 3) {
908 errno = EINVAL;
909 return -1;
912 SWRAP_LOG(SWRAP_LOG_TRACE, "type %c iface %u port %u",
913 type, iface, prt);
915 if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) {
916 errno = EINVAL;
917 return -1;
920 if (prt > 0xFFFF) {
921 errno = EINVAL;
922 return -1;
925 switch(type) {
926 case SOCKET_TYPE_CHAR_TCP:
927 case SOCKET_TYPE_CHAR_UDP: {
928 struct sockaddr_in *in2 = (struct sockaddr_in *)(void *)in;
930 if ((*len) < sizeof(*in2)) {
931 errno = EINVAL;
932 return -1;
935 memset(in2, 0, sizeof(*in2));
936 in2->sin_family = AF_INET;
937 in2->sin_addr.s_addr = htonl((127<<24) | iface);
938 in2->sin_port = htons(prt);
940 *len = sizeof(*in2);
941 break;
943 #ifdef HAVE_IPV6
944 case SOCKET_TYPE_CHAR_TCP_V6:
945 case SOCKET_TYPE_CHAR_UDP_V6: {
946 struct sockaddr_in6 *in2 = (struct sockaddr_in6 *)(void *)in;
948 if ((*len) < sizeof(*in2)) {
949 errno = EINVAL;
950 return -1;
953 memset(in2, 0, sizeof(*in2));
954 in2->sin6_family = AF_INET6;
955 in2->sin6_addr = *swrap_ipv6();
956 in2->sin6_addr.s6_addr[15] = iface;
957 in2->sin6_port = htons(prt);
959 *len = sizeof(*in2);
960 break;
962 #endif
963 default:
964 errno = EINVAL;
965 return -1;
968 return 0;
971 static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un,
972 int *bcast)
974 char type = '\0';
975 unsigned int prt;
976 unsigned int iface;
977 int is_bcast = 0;
979 if (bcast) *bcast = 0;
981 switch (inaddr->sa_family) {
982 case AF_INET: {
983 const struct sockaddr_in *in =
984 (const struct sockaddr_in *)(const void *)inaddr;
985 unsigned int addr = ntohl(in->sin_addr.s_addr);
986 char u_type = '\0';
987 char b_type = '\0';
988 char a_type = '\0';
990 switch (si->type) {
991 case SOCK_STREAM:
992 u_type = SOCKET_TYPE_CHAR_TCP;
993 break;
994 case SOCK_DGRAM:
995 u_type = SOCKET_TYPE_CHAR_UDP;
996 a_type = SOCKET_TYPE_CHAR_UDP;
997 b_type = SOCKET_TYPE_CHAR_UDP;
998 break;
999 default:
1000 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n");
1001 errno = ESOCKTNOSUPPORT;
1002 return -1;
1005 prt = ntohs(in->sin_port);
1006 if (a_type && addr == 0xFFFFFFFF) {
1007 /* 255.255.255.255 only udp */
1008 is_bcast = 2;
1009 type = a_type;
1010 iface = socket_wrapper_default_iface();
1011 } else if (b_type && addr == 0x7FFFFFFF) {
1012 /* 127.255.255.255 only udp */
1013 is_bcast = 1;
1014 type = b_type;
1015 iface = socket_wrapper_default_iface();
1016 } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
1017 /* 127.0.0.X */
1018 is_bcast = 0;
1019 type = u_type;
1020 iface = (addr & 0x000000FF);
1021 } else {
1022 errno = ENETUNREACH;
1023 return -1;
1025 if (bcast) *bcast = is_bcast;
1026 break;
1028 #ifdef HAVE_IPV6
1029 case AF_INET6: {
1030 const struct sockaddr_in6 *in =
1031 (const struct sockaddr_in6 *)(const void *)inaddr;
1032 struct in6_addr cmp1, cmp2;
1034 switch (si->type) {
1035 case SOCK_STREAM:
1036 type = SOCKET_TYPE_CHAR_TCP_V6;
1037 break;
1038 case SOCK_DGRAM:
1039 type = SOCKET_TYPE_CHAR_UDP_V6;
1040 break;
1041 default:
1042 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n");
1043 errno = ESOCKTNOSUPPORT;
1044 return -1;
1047 /* XXX no multicast/broadcast */
1049 prt = ntohs(in->sin6_port);
1051 cmp1 = *swrap_ipv6();
1052 cmp2 = in->sin6_addr;
1053 cmp2.s6_addr[15] = 0;
1054 if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) {
1055 iface = in->sin6_addr.s6_addr[15];
1056 } else {
1057 errno = ENETUNREACH;
1058 return -1;
1061 break;
1063 #endif
1064 default:
1065 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown address family!\n");
1066 errno = ENETUNREACH;
1067 return -1;
1070 if (prt == 0) {
1071 SWRAP_LOG(SWRAP_LOG_WARN, "Port not set\n");
1072 errno = EINVAL;
1073 return -1;
1076 if (is_bcast) {
1077 snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL",
1078 socket_wrapper_dir());
1079 SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
1080 /* the caller need to do more processing */
1081 return 0;
1084 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
1085 socket_wrapper_dir(), type, iface, prt);
1086 SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
1088 return 0;
1091 static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un,
1092 int *bcast)
1094 char type = '\0';
1095 unsigned int prt;
1096 unsigned int iface;
1097 struct stat st;
1098 int is_bcast = 0;
1100 if (bcast) *bcast = 0;
1102 switch (si->family) {
1103 case AF_INET: {
1104 const struct sockaddr_in *in =
1105 (const struct sockaddr_in *)(const void *)inaddr;
1106 unsigned int addr = ntohl(in->sin_addr.s_addr);
1107 char u_type = '\0';
1108 char d_type = '\0';
1109 char b_type = '\0';
1110 char a_type = '\0';
1112 prt = ntohs(in->sin_port);
1114 switch (si->type) {
1115 case SOCK_STREAM:
1116 u_type = SOCKET_TYPE_CHAR_TCP;
1117 d_type = SOCKET_TYPE_CHAR_TCP;
1118 break;
1119 case SOCK_DGRAM:
1120 u_type = SOCKET_TYPE_CHAR_UDP;
1121 d_type = SOCKET_TYPE_CHAR_UDP;
1122 a_type = SOCKET_TYPE_CHAR_UDP;
1123 b_type = SOCKET_TYPE_CHAR_UDP;
1124 break;
1125 default:
1126 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n");
1127 errno = ESOCKTNOSUPPORT;
1128 return -1;
1131 if (addr == 0) {
1132 /* 0.0.0.0 */
1133 is_bcast = 0;
1134 type = d_type;
1135 iface = socket_wrapper_default_iface();
1136 } else if (a_type && addr == 0xFFFFFFFF) {
1137 /* 255.255.255.255 only udp */
1138 is_bcast = 2;
1139 type = a_type;
1140 iface = socket_wrapper_default_iface();
1141 } else if (b_type && addr == 0x7FFFFFFF) {
1142 /* 127.255.255.255 only udp */
1143 is_bcast = 1;
1144 type = b_type;
1145 iface = socket_wrapper_default_iface();
1146 } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
1147 /* 127.0.0.X */
1148 is_bcast = 0;
1149 type = u_type;
1150 iface = (addr & 0x000000FF);
1151 } else {
1152 errno = EADDRNOTAVAIL;
1153 return -1;
1156 /* Store the bind address for connect() */
1157 if (si->bindname.sa_socklen == 0) {
1158 struct sockaddr_in bind_in;
1159 socklen_t blen = sizeof(struct sockaddr_in);
1161 ZERO_STRUCT(bind_in);
1162 bind_in.sin_family = in->sin_family;
1163 bind_in.sin_port = in->sin_port;
1164 bind_in.sin_addr.s_addr = htonl(0x7F000000 | iface);
1166 si->bindname.sa_socklen = blen;
1167 memcpy(&si->bindname.sa.in, &bind_in, blen);
1170 break;
1172 #ifdef HAVE_IPV6
1173 case AF_INET6: {
1174 const struct sockaddr_in6 *in =
1175 (const struct sockaddr_in6 *)(const void *)inaddr;
1176 struct in6_addr cmp1, cmp2;
1178 switch (si->type) {
1179 case SOCK_STREAM:
1180 type = SOCKET_TYPE_CHAR_TCP_V6;
1181 break;
1182 case SOCK_DGRAM:
1183 type = SOCKET_TYPE_CHAR_UDP_V6;
1184 break;
1185 default:
1186 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n");
1187 errno = ESOCKTNOSUPPORT;
1188 return -1;
1191 /* XXX no multicast/broadcast */
1193 prt = ntohs(in->sin6_port);
1195 cmp1 = *swrap_ipv6();
1196 cmp2 = in->sin6_addr;
1197 cmp2.s6_addr[15] = 0;
1198 if (IN6_IS_ADDR_UNSPECIFIED(&in->sin6_addr)) {
1199 iface = socket_wrapper_default_iface();
1200 } else if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) {
1201 iface = in->sin6_addr.s6_addr[15];
1202 } else {
1203 errno = EADDRNOTAVAIL;
1204 return -1;
1207 /* Store the bind address for connect() */
1208 if (si->bindname.sa_socklen == 0) {
1209 struct sockaddr_in6 bind_in;
1210 socklen_t blen = sizeof(struct sockaddr_in6);
1212 ZERO_STRUCT(bind_in);
1213 bind_in.sin6_family = in->sin6_family;
1214 bind_in.sin6_port = in->sin6_port;
1216 bind_in.sin6_addr = *swrap_ipv6();
1217 bind_in.sin6_addr.s6_addr[15] = iface;
1219 memcpy(&si->bindname.sa.in6, &bind_in, blen);
1220 si->bindname.sa_socklen = blen;
1223 break;
1225 #endif
1226 default:
1227 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown address family\n");
1228 errno = EADDRNOTAVAIL;
1229 return -1;
1233 if (bcast) *bcast = is_bcast;
1235 if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) {
1236 errno = EINVAL;
1237 return -1;
1240 if (prt == 0) {
1241 /* handle auto-allocation of ephemeral ports */
1242 for (prt = 5001; prt < 10000; prt++) {
1243 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
1244 socket_wrapper_dir(), type, iface, prt);
1245 if (stat(un->sun_path, &st) == 0) continue;
1247 set_port(si->family, prt, &si->myname);
1248 set_port(si->family, prt, &si->bindname);
1250 break;
1252 if (prt == 10000) {
1253 errno = ENFILE;
1254 return -1;
1258 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
1259 socket_wrapper_dir(), type, iface, prt);
1260 SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
1261 return 0;
1264 static struct socket_info *find_socket_info(int fd)
1266 struct socket_info *i;
1268 for (i = sockets; i; i = i->next) {
1269 struct socket_info_fd *f;
1270 for (f = i->fds; f; f = f->next) {
1271 if (f->fd == fd) {
1272 return i;
1277 return NULL;
1280 #if 0 /* FIXME */
1281 static bool check_addr_port_in_use(const struct sockaddr *sa, socklen_t len)
1283 struct socket_info *s;
1285 /* first catch invalid input */
1286 switch (sa->sa_family) {
1287 case AF_INET:
1288 if (len < sizeof(struct sockaddr_in)) {
1289 return false;
1291 break;
1292 #if HAVE_IPV6
1293 case AF_INET6:
1294 if (len < sizeof(struct sockaddr_in6)) {
1295 return false;
1297 break;
1298 #endif
1299 default:
1300 return false;
1301 break;
1304 for (s = sockets; s != NULL; s = s->next) {
1305 if (s->myname == NULL) {
1306 continue;
1308 if (s->myname->sa_family != sa->sa_family) {
1309 continue;
1311 switch (s->myname->sa_family) {
1312 case AF_INET: {
1313 struct sockaddr_in *sin1, *sin2;
1315 sin1 = (struct sockaddr_in *)s->myname;
1316 sin2 = (struct sockaddr_in *)sa;
1318 if (sin1->sin_addr.s_addr == htonl(INADDR_ANY)) {
1319 continue;
1321 if (sin1->sin_port != sin2->sin_port) {
1322 continue;
1324 if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) {
1325 continue;
1328 /* found */
1329 return true;
1330 break;
1332 #if HAVE_IPV6
1333 case AF_INET6: {
1334 struct sockaddr_in6 *sin1, *sin2;
1336 sin1 = (struct sockaddr_in6 *)s->myname;
1337 sin2 = (struct sockaddr_in6 *)sa;
1339 if (sin1->sin6_port != sin2->sin6_port) {
1340 continue;
1342 if (!IN6_ARE_ADDR_EQUAL(&sin1->sin6_addr,
1343 &sin2->sin6_addr))
1345 continue;
1348 /* found */
1349 return true;
1350 break;
1352 #endif
1353 default:
1354 continue;
1355 break;
1360 return false;
1362 #endif
1364 static void swrap_remove_stale(int fd)
1366 struct socket_info *si = find_socket_info(fd);
1367 struct socket_info_fd *fi;
1369 if (si != NULL) {
1370 for (fi = si->fds; fi; fi = fi->next) {
1371 if (fi->fd == fd) {
1372 SWRAP_LOG(SWRAP_LOG_TRACE, "remove stale wrapper for %d", fd);
1373 SWRAP_DLIST_REMOVE(si->fds, fi);
1374 free(fi);
1375 break;
1379 if (si->fds == NULL) {
1380 SWRAP_DLIST_REMOVE(sockets, si);
1385 static int sockaddr_convert_to_un(struct socket_info *si,
1386 const struct sockaddr *in_addr,
1387 socklen_t in_len,
1388 struct sockaddr_un *out_addr,
1389 int alloc_sock,
1390 int *bcast)
1392 struct sockaddr *out = (struct sockaddr *)(void *)out_addr;
1394 (void) in_len; /* unused */
1396 if (out_addr == NULL) {
1397 return 0;
1400 out->sa_family = AF_UNIX;
1401 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1402 out->sa_len = sizeof(*out_addr);
1403 #endif
1405 switch (in_addr->sa_family) {
1406 case AF_UNSPEC: {
1407 const struct sockaddr_in *sin;
1408 if (si->family != AF_INET) {
1409 break;
1411 if (in_len < sizeof(struct sockaddr_in)) {
1412 break;
1414 sin = (const struct sockaddr_in *)in_addr;
1415 if(sin->sin_addr.s_addr != htonl(INADDR_ANY)) {
1416 break;
1420 * Note: in the special case of AF_UNSPEC and INADDR_ANY,
1421 * AF_UNSPEC is mapped to AF_INET and must be treated here.
1424 /* FALL THROUGH */
1426 case AF_INET:
1427 #ifdef HAVE_IPV6
1428 case AF_INET6:
1429 #endif
1430 switch (si->type) {
1431 case SOCK_STREAM:
1432 case SOCK_DGRAM:
1433 break;
1434 default:
1435 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n");
1436 errno = ESOCKTNOSUPPORT;
1437 return -1;
1439 if (alloc_sock) {
1440 return convert_in_un_alloc(si, in_addr, out_addr, bcast);
1441 } else {
1442 return convert_in_un_remote(si, in_addr, out_addr, bcast);
1444 default:
1445 break;
1448 errno = EAFNOSUPPORT;
1449 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown address family\n");
1450 return -1;
1453 static int sockaddr_convert_from_un(const struct socket_info *si,
1454 const struct sockaddr_un *in_addr,
1455 socklen_t un_addrlen,
1456 int family,
1457 struct sockaddr *out_addr,
1458 socklen_t *out_addrlen)
1460 int ret;
1462 if (out_addr == NULL || out_addrlen == NULL)
1463 return 0;
1465 if (un_addrlen == 0) {
1466 *out_addrlen = 0;
1467 return 0;
1470 switch (family) {
1471 case AF_INET:
1472 #ifdef HAVE_IPV6
1473 case AF_INET6:
1474 #endif
1475 switch (si->type) {
1476 case SOCK_STREAM:
1477 case SOCK_DGRAM:
1478 break;
1479 default:
1480 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n");
1481 errno = ESOCKTNOSUPPORT;
1482 return -1;
1484 ret = convert_un_in(in_addr, out_addr, out_addrlen);
1485 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1486 out_addr->sa_len = *out_addrlen;
1487 #endif
1488 return ret;
1489 default:
1490 break;
1493 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown address family\n");
1494 errno = EAFNOSUPPORT;
1495 return -1;
1498 enum swrap_packet_type {
1499 SWRAP_CONNECT_SEND,
1500 SWRAP_CONNECT_UNREACH,
1501 SWRAP_CONNECT_RECV,
1502 SWRAP_CONNECT_ACK,
1503 SWRAP_ACCEPT_SEND,
1504 SWRAP_ACCEPT_RECV,
1505 SWRAP_ACCEPT_ACK,
1506 SWRAP_RECVFROM,
1507 SWRAP_SENDTO,
1508 SWRAP_SENDTO_UNREACH,
1509 SWRAP_PENDING_RST,
1510 SWRAP_RECV,
1511 SWRAP_RECV_RST,
1512 SWRAP_SEND,
1513 SWRAP_SEND_RST,
1514 SWRAP_CLOSE_SEND,
1515 SWRAP_CLOSE_RECV,
1516 SWRAP_CLOSE_ACK,
1519 struct swrap_file_hdr {
1520 uint32_t magic;
1521 uint16_t version_major;
1522 uint16_t version_minor;
1523 int32_t timezone;
1524 uint32_t sigfigs;
1525 uint32_t frame_max_len;
1526 #define SWRAP_FRAME_LENGTH_MAX 0xFFFF
1527 uint32_t link_type;
1529 #define SWRAP_FILE_HDR_SIZE 24
1531 struct swrap_packet_frame {
1532 uint32_t seconds;
1533 uint32_t micro_seconds;
1534 uint32_t recorded_length;
1535 uint32_t full_length;
1537 #define SWRAP_PACKET_FRAME_SIZE 16
1539 union swrap_packet_ip {
1540 struct {
1541 uint8_t ver_hdrlen;
1542 uint8_t tos;
1543 uint16_t packet_length;
1544 uint16_t identification;
1545 uint8_t flags;
1546 uint8_t fragment;
1547 uint8_t ttl;
1548 uint8_t protocol;
1549 uint16_t hdr_checksum;
1550 uint32_t src_addr;
1551 uint32_t dest_addr;
1552 } v4;
1553 #define SWRAP_PACKET_IP_V4_SIZE 20
1554 struct {
1555 uint8_t ver_prio;
1556 uint8_t flow_label_high;
1557 uint16_t flow_label_low;
1558 uint16_t payload_length;
1559 uint8_t next_header;
1560 uint8_t hop_limit;
1561 uint8_t src_addr[16];
1562 uint8_t dest_addr[16];
1563 } v6;
1564 #define SWRAP_PACKET_IP_V6_SIZE 40
1566 #define SWRAP_PACKET_IP_SIZE 40
1568 union swrap_packet_payload {
1569 struct {
1570 uint16_t source_port;
1571 uint16_t dest_port;
1572 uint32_t seq_num;
1573 uint32_t ack_num;
1574 uint8_t hdr_length;
1575 uint8_t control;
1576 uint16_t window;
1577 uint16_t checksum;
1578 uint16_t urg;
1579 } tcp;
1580 #define SWRAP_PACKET_PAYLOAD_TCP_SIZE 20
1581 struct {
1582 uint16_t source_port;
1583 uint16_t dest_port;
1584 uint16_t length;
1585 uint16_t checksum;
1586 } udp;
1587 #define SWRAP_PACKET_PAYLOAD_UDP_SIZE 8
1588 struct {
1589 uint8_t type;
1590 uint8_t code;
1591 uint16_t checksum;
1592 uint32_t unused;
1593 } icmp4;
1594 #define SWRAP_PACKET_PAYLOAD_ICMP4_SIZE 8
1595 struct {
1596 uint8_t type;
1597 uint8_t code;
1598 uint16_t checksum;
1599 uint32_t unused;
1600 } icmp6;
1601 #define SWRAP_PACKET_PAYLOAD_ICMP6_SIZE 8
1603 #define SWRAP_PACKET_PAYLOAD_SIZE 20
1605 #define SWRAP_PACKET_MIN_ALLOC \
1606 (SWRAP_PACKET_FRAME_SIZE + \
1607 SWRAP_PACKET_IP_SIZE + \
1608 SWRAP_PACKET_PAYLOAD_SIZE)
1610 static const char *swrap_pcap_init_file(void)
1612 static int initialized = 0;
1613 static const char *s = NULL;
1614 static const struct swrap_file_hdr h;
1615 static const struct swrap_packet_frame f;
1616 static const union swrap_packet_ip i;
1617 static const union swrap_packet_payload p;
1619 if (initialized == 1) {
1620 return s;
1622 initialized = 1;
1625 * TODO: don't use the structs use plain buffer offsets
1626 * and PUSH_U8(), PUSH_U16() and PUSH_U32()
1628 * for now make sure we disable PCAP support
1629 * if the struct has alignment!
1631 if (sizeof(h) != SWRAP_FILE_HDR_SIZE) {
1632 return NULL;
1634 if (sizeof(f) != SWRAP_PACKET_FRAME_SIZE) {
1635 return NULL;
1637 if (sizeof(i) != SWRAP_PACKET_IP_SIZE) {
1638 return NULL;
1640 if (sizeof(i.v4) != SWRAP_PACKET_IP_V4_SIZE) {
1641 return NULL;
1643 if (sizeof(i.v6) != SWRAP_PACKET_IP_V6_SIZE) {
1644 return NULL;
1646 if (sizeof(p) != SWRAP_PACKET_PAYLOAD_SIZE) {
1647 return NULL;
1649 if (sizeof(p.tcp) != SWRAP_PACKET_PAYLOAD_TCP_SIZE) {
1650 return NULL;
1652 if (sizeof(p.udp) != SWRAP_PACKET_PAYLOAD_UDP_SIZE) {
1653 return NULL;
1655 if (sizeof(p.icmp4) != SWRAP_PACKET_PAYLOAD_ICMP4_SIZE) {
1656 return NULL;
1658 if (sizeof(p.icmp6) != SWRAP_PACKET_PAYLOAD_ICMP6_SIZE) {
1659 return NULL;
1662 s = getenv("SOCKET_WRAPPER_PCAP_FILE");
1663 if (s == NULL) {
1664 return NULL;
1666 if (strncmp(s, "./", 2) == 0) {
1667 s += 2;
1669 return s;
1672 static uint8_t *swrap_pcap_packet_init(struct timeval *tval,
1673 const struct sockaddr *src,
1674 const struct sockaddr *dest,
1675 int socket_type,
1676 const uint8_t *payload,
1677 size_t payload_len,
1678 unsigned long tcp_seqno,
1679 unsigned long tcp_ack,
1680 unsigned char tcp_ctl,
1681 int unreachable,
1682 size_t *_packet_len)
1684 uint8_t *base;
1685 uint8_t *buf;
1686 struct swrap_packet_frame *frame;
1687 union swrap_packet_ip *ip;
1688 union swrap_packet_payload *pay;
1689 size_t packet_len;
1690 size_t alloc_len;
1691 size_t nonwire_len = sizeof(*frame);
1692 size_t wire_hdr_len = 0;
1693 size_t wire_len = 0;
1694 size_t ip_hdr_len = 0;
1695 size_t icmp_hdr_len = 0;
1696 size_t icmp_truncate_len = 0;
1697 uint8_t protocol = 0, icmp_protocol = 0;
1698 const struct sockaddr_in *src_in = NULL;
1699 const struct sockaddr_in *dest_in = NULL;
1700 #ifdef HAVE_IPV6
1701 const struct sockaddr_in6 *src_in6 = NULL;
1702 const struct sockaddr_in6 *dest_in6 = NULL;
1703 #endif
1704 uint16_t src_port;
1705 uint16_t dest_port;
1707 switch (src->sa_family) {
1708 case AF_INET:
1709 src_in = (const struct sockaddr_in *)src;
1710 dest_in = (const struct sockaddr_in *)dest;
1711 src_port = src_in->sin_port;
1712 dest_port = dest_in->sin_port;
1713 ip_hdr_len = sizeof(ip->v4);
1714 break;
1715 #ifdef HAVE_IPV6
1716 case AF_INET6:
1717 src_in6 = (const struct sockaddr_in6 *)src;
1718 dest_in6 = (const struct sockaddr_in6 *)dest;
1719 src_port = src_in6->sin6_port;
1720 dest_port = dest_in6->sin6_port;
1721 ip_hdr_len = sizeof(ip->v6);
1722 break;
1723 #endif
1724 default:
1725 return NULL;
1728 switch (socket_type) {
1729 case SOCK_STREAM:
1730 protocol = 0x06; /* TCP */
1731 wire_hdr_len = ip_hdr_len + sizeof(pay->tcp);
1732 wire_len = wire_hdr_len + payload_len;
1733 break;
1735 case SOCK_DGRAM:
1736 protocol = 0x11; /* UDP */
1737 wire_hdr_len = ip_hdr_len + sizeof(pay->udp);
1738 wire_len = wire_hdr_len + payload_len;
1739 break;
1741 default:
1742 return NULL;
1745 if (unreachable) {
1746 icmp_protocol = protocol;
1747 switch (src->sa_family) {
1748 case AF_INET:
1749 protocol = 0x01; /* ICMPv4 */
1750 icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp4);
1751 break;
1752 #ifdef HAVE_IPV6
1753 case AF_INET6:
1754 protocol = 0x3A; /* ICMPv6 */
1755 icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp6);
1756 break;
1757 #endif
1759 if (wire_len > 64 ) {
1760 icmp_truncate_len = wire_len - 64;
1762 wire_hdr_len += icmp_hdr_len;
1763 wire_len += icmp_hdr_len;
1766 packet_len = nonwire_len + wire_len;
1767 alloc_len = packet_len;
1768 if (alloc_len < SWRAP_PACKET_MIN_ALLOC) {
1769 alloc_len = SWRAP_PACKET_MIN_ALLOC;
1772 base = (uint8_t *)malloc(alloc_len);
1773 if (base == NULL) {
1774 return NULL;
1776 memset(base, 0x0, alloc_len);
1778 buf = base;
1780 frame = (struct swrap_packet_frame *)buf;
1781 frame->seconds = tval->tv_sec;
1782 frame->micro_seconds = tval->tv_usec;
1783 frame->recorded_length = wire_len - icmp_truncate_len;
1784 frame->full_length = wire_len - icmp_truncate_len;
1785 buf += SWRAP_PACKET_FRAME_SIZE;
1787 ip = (union swrap_packet_ip *)buf;
1788 switch (src->sa_family) {
1789 case AF_INET:
1790 ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
1791 ip->v4.tos = 0x00;
1792 ip->v4.packet_length = htons(wire_len - icmp_truncate_len);
1793 ip->v4.identification = htons(0xFFFF);
1794 ip->v4.flags = 0x40; /* BIT 1 set - means don't fragment */
1795 ip->v4.fragment = htons(0x0000);
1796 ip->v4.ttl = 0xFF;
1797 ip->v4.protocol = protocol;
1798 ip->v4.hdr_checksum = htons(0x0000);
1799 ip->v4.src_addr = src_in->sin_addr.s_addr;
1800 ip->v4.dest_addr = dest_in->sin_addr.s_addr;
1801 buf += SWRAP_PACKET_IP_V4_SIZE;
1802 break;
1803 #ifdef HAVE_IPV6
1804 case AF_INET6:
1805 ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */
1806 ip->v6.flow_label_high = 0x00;
1807 ip->v6.flow_label_low = 0x0000;
1808 ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */
1809 ip->v6.next_header = protocol;
1810 memcpy(ip->v6.src_addr, src_in6->sin6_addr.s6_addr, 16);
1811 memcpy(ip->v6.dest_addr, dest_in6->sin6_addr.s6_addr, 16);
1812 buf += SWRAP_PACKET_IP_V6_SIZE;
1813 break;
1814 #endif
1817 if (unreachable) {
1818 pay = (union swrap_packet_payload *)buf;
1819 switch (src->sa_family) {
1820 case AF_INET:
1821 pay->icmp4.type = 0x03; /* destination unreachable */
1822 pay->icmp4.code = 0x01; /* host unreachable */
1823 pay->icmp4.checksum = htons(0x0000);
1824 pay->icmp4.unused = htonl(0x00000000);
1825 buf += SWRAP_PACKET_PAYLOAD_ICMP4_SIZE;
1827 /* set the ip header in the ICMP payload */
1828 ip = (union swrap_packet_ip *)buf;
1829 ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
1830 ip->v4.tos = 0x00;
1831 ip->v4.packet_length = htons(wire_len - icmp_hdr_len);
1832 ip->v4.identification = htons(0xFFFF);
1833 ip->v4.flags = 0x40; /* BIT 1 set - means don't fragment */
1834 ip->v4.fragment = htons(0x0000);
1835 ip->v4.ttl = 0xFF;
1836 ip->v4.protocol = icmp_protocol;
1837 ip->v4.hdr_checksum = htons(0x0000);
1838 ip->v4.src_addr = dest_in->sin_addr.s_addr;
1839 ip->v4.dest_addr = src_in->sin_addr.s_addr;
1840 buf += SWRAP_PACKET_IP_V4_SIZE;
1842 src_port = dest_in->sin_port;
1843 dest_port = src_in->sin_port;
1844 break;
1845 #ifdef HAVE_IPV6
1846 case AF_INET6:
1847 pay->icmp6.type = 0x01; /* destination unreachable */
1848 pay->icmp6.code = 0x03; /* address unreachable */
1849 pay->icmp6.checksum = htons(0x0000);
1850 pay->icmp6.unused = htonl(0x00000000);
1851 buf += SWRAP_PACKET_PAYLOAD_ICMP6_SIZE;
1853 /* set the ip header in the ICMP payload */
1854 ip = (union swrap_packet_ip *)buf;
1855 ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */
1856 ip->v6.flow_label_high = 0x00;
1857 ip->v6.flow_label_low = 0x0000;
1858 ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */
1859 ip->v6.next_header = protocol;
1860 memcpy(ip->v6.src_addr, dest_in6->sin6_addr.s6_addr, 16);
1861 memcpy(ip->v6.dest_addr, src_in6->sin6_addr.s6_addr, 16);
1862 buf += SWRAP_PACKET_IP_V6_SIZE;
1864 src_port = dest_in6->sin6_port;
1865 dest_port = src_in6->sin6_port;
1866 break;
1867 #endif
1871 pay = (union swrap_packet_payload *)buf;
1873 switch (socket_type) {
1874 case SOCK_STREAM:
1875 pay->tcp.source_port = src_port;
1876 pay->tcp.dest_port = dest_port;
1877 pay->tcp.seq_num = htonl(tcp_seqno);
1878 pay->tcp.ack_num = htonl(tcp_ack);
1879 pay->tcp.hdr_length = 0x50; /* 5 * 32 bit words */
1880 pay->tcp.control = tcp_ctl;
1881 pay->tcp.window = htons(0x7FFF);
1882 pay->tcp.checksum = htons(0x0000);
1883 pay->tcp.urg = htons(0x0000);
1884 buf += SWRAP_PACKET_PAYLOAD_TCP_SIZE;
1886 break;
1888 case SOCK_DGRAM:
1889 pay->udp.source_port = src_port;
1890 pay->udp.dest_port = dest_port;
1891 pay->udp.length = htons(8 + payload_len);
1892 pay->udp.checksum = htons(0x0000);
1893 buf += SWRAP_PACKET_PAYLOAD_UDP_SIZE;
1895 break;
1898 if (payload && payload_len > 0) {
1899 memcpy(buf, payload, payload_len);
1902 *_packet_len = packet_len - icmp_truncate_len;
1903 return base;
1906 static int swrap_pcap_get_fd(const char *fname)
1908 static int fd = -1;
1910 if (fd != -1) return fd;
1912 fd = libc_open(fname, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0644);
1913 if (fd != -1) {
1914 struct swrap_file_hdr file_hdr;
1915 file_hdr.magic = 0xA1B2C3D4;
1916 file_hdr.version_major = 0x0002;
1917 file_hdr.version_minor = 0x0004;
1918 file_hdr.timezone = 0x00000000;
1919 file_hdr.sigfigs = 0x00000000;
1920 file_hdr.frame_max_len = SWRAP_FRAME_LENGTH_MAX;
1921 file_hdr.link_type = 0x0065; /* 101 RAW IP */
1923 if (write(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) {
1924 close(fd);
1925 fd = -1;
1927 return fd;
1930 fd = libc_open(fname, O_WRONLY|O_APPEND, 0644);
1932 return fd;
1935 static uint8_t *swrap_pcap_marshall_packet(struct socket_info *si,
1936 const struct sockaddr *addr,
1937 enum swrap_packet_type type,
1938 const void *buf, size_t len,
1939 size_t *packet_len)
1941 const struct sockaddr *src_addr;
1942 const struct sockaddr *dest_addr;
1943 unsigned long tcp_seqno = 0;
1944 unsigned long tcp_ack = 0;
1945 unsigned char tcp_ctl = 0;
1946 int unreachable = 0;
1948 struct timeval tv;
1950 switch (si->family) {
1951 case AF_INET:
1952 break;
1953 #ifdef HAVE_IPV6
1954 case AF_INET6:
1955 break;
1956 #endif
1957 default:
1958 return NULL;
1961 switch (type) {
1962 case SWRAP_CONNECT_SEND:
1963 if (si->type != SOCK_STREAM) return NULL;
1965 src_addr = &si->myname.sa.s;
1966 dest_addr = addr;
1968 tcp_seqno = si->io.pck_snd;
1969 tcp_ack = si->io.pck_rcv;
1970 tcp_ctl = 0x02; /* SYN */
1972 si->io.pck_snd += 1;
1974 break;
1976 case SWRAP_CONNECT_RECV:
1977 if (si->type != SOCK_STREAM) return NULL;
1979 dest_addr = &si->myname.sa.s;
1980 src_addr = addr;
1982 tcp_seqno = si->io.pck_rcv;
1983 tcp_ack = si->io.pck_snd;
1984 tcp_ctl = 0x12; /** SYN,ACK */
1986 si->io.pck_rcv += 1;
1988 break;
1990 case SWRAP_CONNECT_UNREACH:
1991 if (si->type != SOCK_STREAM) return NULL;
1993 dest_addr = &si->myname.sa.s;
1994 src_addr = addr;
1996 /* Unreachable: resend the data of SWRAP_CONNECT_SEND */
1997 tcp_seqno = si->io.pck_snd - 1;
1998 tcp_ack = si->io.pck_rcv;
1999 tcp_ctl = 0x02; /* SYN */
2000 unreachable = 1;
2002 break;
2004 case SWRAP_CONNECT_ACK:
2005 if (si->type != SOCK_STREAM) return NULL;
2007 src_addr = &si->myname.sa.s;
2008 dest_addr = addr;
2010 tcp_seqno = si->io.pck_snd;
2011 tcp_ack = si->io.pck_rcv;
2012 tcp_ctl = 0x10; /* ACK */
2014 break;
2016 case SWRAP_ACCEPT_SEND:
2017 if (si->type != SOCK_STREAM) return NULL;
2019 dest_addr = &si->myname.sa.s;
2020 src_addr = addr;
2022 tcp_seqno = si->io.pck_rcv;
2023 tcp_ack = si->io.pck_snd;
2024 tcp_ctl = 0x02; /* SYN */
2026 si->io.pck_rcv += 1;
2028 break;
2030 case SWRAP_ACCEPT_RECV:
2031 if (si->type != SOCK_STREAM) return NULL;
2033 src_addr = &si->myname.sa.s;
2034 dest_addr = addr;
2036 tcp_seqno = si->io.pck_snd;
2037 tcp_ack = si->io.pck_rcv;
2038 tcp_ctl = 0x12; /* SYN,ACK */
2040 si->io.pck_snd += 1;
2042 break;
2044 case SWRAP_ACCEPT_ACK:
2045 if (si->type != SOCK_STREAM) return NULL;
2047 dest_addr = &si->myname.sa.s;
2048 src_addr = addr;
2050 tcp_seqno = si->io.pck_rcv;
2051 tcp_ack = si->io.pck_snd;
2052 tcp_ctl = 0x10; /* ACK */
2054 break;
2056 case SWRAP_SEND:
2057 src_addr = &si->myname.sa.s;
2058 dest_addr = &si->peername.sa.s;
2060 tcp_seqno = si->io.pck_snd;
2061 tcp_ack = si->io.pck_rcv;
2062 tcp_ctl = 0x18; /* PSH,ACK */
2064 si->io.pck_snd += len;
2066 break;
2068 case SWRAP_SEND_RST:
2069 dest_addr = &si->myname.sa.s;
2070 src_addr = &si->peername.sa.s;
2072 if (si->type == SOCK_DGRAM) {
2073 return swrap_pcap_marshall_packet(si,
2074 &si->peername.sa.s,
2075 SWRAP_SENDTO_UNREACH,
2076 buf,
2077 len,
2078 packet_len);
2081 tcp_seqno = si->io.pck_rcv;
2082 tcp_ack = si->io.pck_snd;
2083 tcp_ctl = 0x14; /** RST,ACK */
2085 break;
2087 case SWRAP_PENDING_RST:
2088 dest_addr = &si->myname.sa.s;
2089 src_addr = &si->peername.sa.s;
2091 if (si->type == SOCK_DGRAM) {
2092 return NULL;
2095 tcp_seqno = si->io.pck_rcv;
2096 tcp_ack = si->io.pck_snd;
2097 tcp_ctl = 0x14; /* RST,ACK */
2099 break;
2101 case SWRAP_RECV:
2102 dest_addr = &si->myname.sa.s;
2103 src_addr = &si->peername.sa.s;
2105 tcp_seqno = si->io.pck_rcv;
2106 tcp_ack = si->io.pck_snd;
2107 tcp_ctl = 0x18; /* PSH,ACK */
2109 si->io.pck_rcv += len;
2111 break;
2113 case SWRAP_RECV_RST:
2114 dest_addr = &si->myname.sa.s;
2115 src_addr = &si->peername.sa.s;
2117 if (si->type == SOCK_DGRAM) {
2118 return NULL;
2121 tcp_seqno = si->io.pck_rcv;
2122 tcp_ack = si->io.pck_snd;
2123 tcp_ctl = 0x14; /* RST,ACK */
2125 break;
2127 case SWRAP_SENDTO:
2128 src_addr = &si->myname.sa.s;
2129 dest_addr = addr;
2131 si->io.pck_snd += len;
2133 break;
2135 case SWRAP_SENDTO_UNREACH:
2136 dest_addr = &si->myname.sa.s;
2137 src_addr = addr;
2139 unreachable = 1;
2141 break;
2143 case SWRAP_RECVFROM:
2144 dest_addr = &si->myname.sa.s;
2145 src_addr = addr;
2147 si->io.pck_rcv += len;
2149 break;
2151 case SWRAP_CLOSE_SEND:
2152 if (si->type != SOCK_STREAM) return NULL;
2154 src_addr = &si->myname.sa.s;
2155 dest_addr = &si->peername.sa.s;
2157 tcp_seqno = si->io.pck_snd;
2158 tcp_ack = si->io.pck_rcv;
2159 tcp_ctl = 0x11; /* FIN, ACK */
2161 si->io.pck_snd += 1;
2163 break;
2165 case SWRAP_CLOSE_RECV:
2166 if (si->type != SOCK_STREAM) return NULL;
2168 dest_addr = &si->myname.sa.s;
2169 src_addr = &si->peername.sa.s;
2171 tcp_seqno = si->io.pck_rcv;
2172 tcp_ack = si->io.pck_snd;
2173 tcp_ctl = 0x11; /* FIN,ACK */
2175 si->io.pck_rcv += 1;
2177 break;
2179 case SWRAP_CLOSE_ACK:
2180 if (si->type != SOCK_STREAM) return NULL;
2182 src_addr = &si->myname.sa.s;
2183 dest_addr = &si->peername.sa.s;
2185 tcp_seqno = si->io.pck_snd;
2186 tcp_ack = si->io.pck_rcv;
2187 tcp_ctl = 0x10; /* ACK */
2189 break;
2190 default:
2191 return NULL;
2194 swrapGetTimeOfDay(&tv);
2196 return swrap_pcap_packet_init(&tv,
2197 src_addr,
2198 dest_addr,
2199 si->type,
2200 (const uint8_t *)buf,
2201 len,
2202 tcp_seqno,
2203 tcp_ack,
2204 tcp_ctl,
2205 unreachable,
2206 packet_len);
2209 static void swrap_pcap_dump_packet(struct socket_info *si,
2210 const struct sockaddr *addr,
2211 enum swrap_packet_type type,
2212 const void *buf, size_t len)
2214 const char *file_name;
2215 uint8_t *packet;
2216 size_t packet_len = 0;
2217 int fd;
2219 file_name = swrap_pcap_init_file();
2220 if (!file_name) {
2221 return;
2224 packet = swrap_pcap_marshall_packet(si,
2225 addr,
2226 type,
2227 buf,
2228 len,
2229 &packet_len);
2230 if (packet == NULL) {
2231 return;
2234 fd = swrap_pcap_get_fd(file_name);
2235 if (fd != -1) {
2236 if (write(fd, packet, packet_len) != (ssize_t)packet_len) {
2237 free(packet);
2238 return;
2242 free(packet);
2245 /****************************************************************************
2246 * SIGNALFD
2247 ***************************************************************************/
2249 #ifdef HAVE_SIGNALFD
2250 static int swrap_signalfd(int fd, const sigset_t *mask, int flags)
2252 int rc;
2254 rc = libc_signalfd(fd, mask, flags);
2255 if (rc != -1) {
2256 swrap_remove_stale(fd);
2259 return rc;
2262 int signalfd(int fd, const sigset_t *mask, int flags)
2264 return swrap_signalfd(fd, mask, flags);
2266 #endif
2268 /****************************************************************************
2269 * SOCKET
2270 ***************************************************************************/
2272 static int swrap_socket(int family, int type, int protocol)
2274 struct socket_info *si;
2275 struct socket_info_fd *fi;
2276 int fd;
2277 int real_type = type;
2280 * Remove possible addition flags passed to socket() so
2281 * do not fail checking the type.
2282 * See https://lwn.net/Articles/281965/
2284 #ifdef SOCK_CLOEXEC
2285 real_type &= ~SOCK_CLOEXEC;
2286 #endif
2287 #ifdef SOCK_NONBLOCK
2288 real_type &= ~SOCK_NONBLOCK;
2289 #endif
2291 if (!socket_wrapper_enabled()) {
2292 return libc_socket(family, type, protocol);
2295 switch (family) {
2296 case AF_INET:
2297 #ifdef HAVE_IPV6
2298 case AF_INET6:
2299 #endif
2300 break;
2301 case AF_UNIX:
2302 return libc_socket(family, type, protocol);
2303 default:
2304 errno = EAFNOSUPPORT;
2305 return -1;
2308 switch (real_type) {
2309 case SOCK_STREAM:
2310 break;
2311 case SOCK_DGRAM:
2312 break;
2313 default:
2314 errno = EPROTONOSUPPORT;
2315 return -1;
2318 switch (protocol) {
2319 case 0:
2320 break;
2321 case 6:
2322 if (real_type == SOCK_STREAM) {
2323 break;
2325 /*fall through*/
2326 case 17:
2327 if (real_type == SOCK_DGRAM) {
2328 break;
2330 /*fall through*/
2331 default:
2332 errno = EPROTONOSUPPORT;
2333 return -1;
2337 * We must call libc_socket with type, from the caller, not the version
2338 * we removed SOCK_CLOEXEC and SOCK_NONBLOCK from
2340 fd = libc_socket(AF_UNIX, type, 0);
2342 if (fd == -1) {
2343 return -1;
2346 /* Check if we have a stale fd and remove it */
2347 si = find_socket_info(fd);
2348 if (si != NULL) {
2349 swrap_remove_stale(fd);
2352 si = (struct socket_info *)malloc(sizeof(struct socket_info));
2353 memset(si, 0, sizeof(struct socket_info));
2354 if (si == NULL) {
2355 errno = ENOMEM;
2356 return -1;
2359 si->family = family;
2361 /* however, the rest of the socket_wrapper code expects just
2362 * the type, not the flags */
2363 si->type = real_type;
2364 si->protocol = protocol;
2367 * Setup myname so getsockname() can succeed to find out the socket
2368 * type.
2370 switch(si->family) {
2371 case AF_INET: {
2372 struct sockaddr_in sin = {
2373 .sin_family = AF_INET,
2376 si->myname.sa_socklen = sizeof(struct sockaddr_in);
2377 memcpy(&si->myname.sa.in, &sin, si->myname.sa_socklen);
2378 break;
2380 case AF_INET6: {
2381 struct sockaddr_in6 sin6 = {
2382 .sin6_family = AF_INET6,
2385 si->myname.sa_socklen = sizeof(struct sockaddr_in6);
2386 memcpy(&si->myname.sa.in6, &sin6, si->myname.sa_socklen);
2387 break;
2389 default:
2390 free(si);
2391 errno = EINVAL;
2392 return -1;
2395 fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
2396 if (fi == NULL) {
2397 free(si);
2398 errno = ENOMEM;
2399 return -1;
2402 fi->fd = fd;
2404 SWRAP_DLIST_ADD(si->fds, fi);
2405 SWRAP_DLIST_ADD(sockets, si);
2407 return fd;
2410 int socket(int family, int type, int protocol)
2412 return swrap_socket(family, type, protocol);
2415 /****************************************************************************
2416 * SOCKETPAIR
2417 ***************************************************************************/
2419 static int swrap_socketpair(int family, int type, int protocol, int sv[2])
2421 int rc;
2423 rc = libc_socketpair(family, type, protocol, sv);
2424 if (rc != -1) {
2425 swrap_remove_stale(sv[0]);
2426 swrap_remove_stale(sv[1]);
2429 return rc;
2432 int socketpair(int family, int type, int protocol, int sv[2])
2434 return swrap_socketpair(family, type, protocol, sv);
2437 /****************************************************************************
2438 * SOCKETPAIR
2439 ***************************************************************************/
2441 #ifdef HAVE_TIMERFD_CREATE
2442 static int swrap_timerfd_create(int clockid, int flags)
2444 int fd;
2446 fd = libc_timerfd_create(clockid, flags);
2447 if (fd != -1) {
2448 swrap_remove_stale(fd);
2451 return fd;
2454 int timerfd_create(int clockid, int flags)
2456 return swrap_timerfd_create(clockid, flags);
2458 #endif
2460 /****************************************************************************
2461 * PIPE
2462 ***************************************************************************/
2464 static int swrap_pipe(int pipefd[2])
2466 int rc;
2468 rc = libc_pipe(pipefd);
2469 if (rc != -1) {
2470 swrap_remove_stale(pipefd[0]);
2471 swrap_remove_stale(pipefd[1]);
2474 return rc;
2477 int pipe(int pipefd[2])
2479 return swrap_pipe(pipefd);
2482 /****************************************************************************
2483 * ACCEPT
2484 ***************************************************************************/
2486 static int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
2488 struct socket_info *parent_si, *child_si;
2489 struct socket_info_fd *child_fi;
2490 int fd;
2491 struct swrap_address un_addr = {
2492 .sa_socklen = sizeof(struct sockaddr_un),
2494 struct swrap_address un_my_addr = {
2495 .sa_socklen = sizeof(struct sockaddr_un),
2497 struct swrap_address in_addr = {
2498 .sa_socklen = sizeof(struct sockaddr_storage),
2500 struct swrap_address in_my_addr = {
2501 .sa_socklen = sizeof(struct sockaddr_storage),
2503 int ret;
2505 parent_si = find_socket_info(s);
2506 if (!parent_si) {
2507 return libc_accept(s, addr, addrlen);
2511 * assume out sockaddr have the same size as the in parent
2512 * socket family
2514 in_addr.sa_socklen = socket_length(parent_si->family);
2515 if (in_addr.sa_socklen <= 0) {
2516 errno = EINVAL;
2517 return -1;
2520 ret = libc_accept(s, &un_addr.sa.s, &un_addr.sa_socklen);
2521 if (ret == -1) {
2522 if (errno == ENOTSOCK) {
2523 /* Remove stale fds */
2524 swrap_remove_stale(s);
2526 return ret;
2529 fd = ret;
2531 ret = sockaddr_convert_from_un(parent_si,
2532 &un_addr.sa.un,
2533 un_addr.sa_socklen,
2534 parent_si->family,
2535 &in_addr.sa.s,
2536 &in_addr.sa_socklen);
2537 if (ret == -1) {
2538 close(fd);
2539 return ret;
2542 child_si = (struct socket_info *)malloc(sizeof(struct socket_info));
2543 memset(child_si, 0, sizeof(struct socket_info));
2545 child_fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
2546 if (child_fi == NULL) {
2547 free(child_si);
2548 close(fd);
2549 errno = ENOMEM;
2550 return -1;
2553 child_fi->fd = fd;
2555 SWRAP_DLIST_ADD(child_si->fds, child_fi);
2557 child_si->family = parent_si->family;
2558 child_si->type = parent_si->type;
2559 child_si->protocol = parent_si->protocol;
2560 child_si->bound = 1;
2561 child_si->is_server = 1;
2562 child_si->connected = 1;
2564 child_si->peername = (struct swrap_address) {
2565 .sa_socklen = in_addr.sa_socklen,
2567 memcpy(&child_si->peername.sa.ss, &in_addr.sa.ss, in_addr.sa_socklen);
2569 if (addr != NULL && addrlen != NULL) {
2570 size_t copy_len = MIN(*addrlen, in_addr.sa_socklen);
2571 if (copy_len > 0) {
2572 memcpy(addr, &in_addr.sa.ss, copy_len);
2574 *addrlen = in_addr.sa_socklen;
2577 ret = libc_getsockname(fd,
2578 &un_my_addr.sa.s,
2579 &un_my_addr.sa_socklen);
2580 if (ret == -1) {
2581 free(child_fi);
2582 free(child_si);
2583 close(fd);
2584 return ret;
2587 ret = sockaddr_convert_from_un(child_si,
2588 &un_my_addr.sa.un,
2589 un_my_addr.sa_socklen,
2590 child_si->family,
2591 &in_my_addr.sa.s,
2592 &in_my_addr.sa_socklen);
2593 if (ret == -1) {
2594 free(child_fi);
2595 free(child_si);
2596 close(fd);
2597 return ret;
2600 SWRAP_LOG(SWRAP_LOG_TRACE,
2601 "accept() path=%s, fd=%d",
2602 un_my_addr.sa.un.sun_path, s);
2604 child_si->myname = (struct swrap_address) {
2605 .sa_socklen = in_my_addr.sa_socklen,
2607 memcpy(&child_si->myname.sa.ss, &in_my_addr.sa.ss, in_my_addr.sa_socklen);
2609 SWRAP_DLIST_ADD(sockets, child_si);
2611 if (addr != NULL) {
2612 swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0);
2613 swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_RECV, NULL, 0);
2614 swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_ACK, NULL, 0);
2617 return fd;
2620 #ifdef HAVE_ACCEPT_PSOCKLEN_T
2621 int accept(int s, struct sockaddr *addr, Psocklen_t addrlen)
2622 #else
2623 int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
2624 #endif
2626 return swrap_accept(s, addr, (socklen_t *)addrlen);
2629 static int autobind_start_init;
2630 static int autobind_start;
2632 /* using sendto() or connect() on an unbound socket would give the
2633 recipient no way to reply, as unlike UDP and TCP, a unix domain
2634 socket can't auto-assign ephemeral port numbers, so we need to
2635 assign it here.
2636 Note: this might change the family from ipv6 to ipv4
2638 static int swrap_auto_bind(int fd, struct socket_info *si, int family)
2640 struct swrap_address un_addr = {
2641 .sa_socklen = sizeof(struct sockaddr_un),
2643 int i;
2644 char type;
2645 int ret;
2646 int port;
2647 struct stat st;
2649 if (autobind_start_init != 1) {
2650 autobind_start_init = 1;
2651 autobind_start = getpid();
2652 autobind_start %= 50000;
2653 autobind_start += 10000;
2656 un_addr.sa.un.sun_family = AF_UNIX;
2658 switch (family) {
2659 case AF_INET: {
2660 struct sockaddr_in in;
2662 switch (si->type) {
2663 case SOCK_STREAM:
2664 type = SOCKET_TYPE_CHAR_TCP;
2665 break;
2666 case SOCK_DGRAM:
2667 type = SOCKET_TYPE_CHAR_UDP;
2668 break;
2669 default:
2670 errno = ESOCKTNOSUPPORT;
2671 return -1;
2674 memset(&in, 0, sizeof(in));
2675 in.sin_family = AF_INET;
2676 in.sin_addr.s_addr = htonl(127<<24 |
2677 socket_wrapper_default_iface());
2679 si->myname = (struct swrap_address) {
2680 .sa_socklen = sizeof(in),
2682 memcpy(&si->myname.sa.in, &in, si->myname.sa_socklen);
2683 break;
2685 #ifdef HAVE_IPV6
2686 case AF_INET6: {
2687 struct sockaddr_in6 in6;
2689 if (si->family != family) {
2690 errno = ENETUNREACH;
2691 return -1;
2694 switch (si->type) {
2695 case SOCK_STREAM:
2696 type = SOCKET_TYPE_CHAR_TCP_V6;
2697 break;
2698 case SOCK_DGRAM:
2699 type = SOCKET_TYPE_CHAR_UDP_V6;
2700 break;
2701 default:
2702 errno = ESOCKTNOSUPPORT;
2703 return -1;
2706 memset(&in6, 0, sizeof(in6));
2707 in6.sin6_family = AF_INET6;
2708 in6.sin6_addr = *swrap_ipv6();
2709 in6.sin6_addr.s6_addr[15] = socket_wrapper_default_iface();
2711 si->myname = (struct swrap_address) {
2712 .sa_socklen = sizeof(in6),
2714 memcpy(&si->myname.sa.in6, &in6, si->myname.sa_socklen);
2715 break;
2717 #endif
2718 default:
2719 errno = ESOCKTNOSUPPORT;
2720 return -1;
2723 if (autobind_start > 60000) {
2724 autobind_start = 10000;
2727 for (i = 0; i < SOCKET_MAX_SOCKETS; i++) {
2728 port = autobind_start + i;
2729 snprintf(un_addr.sa.un.sun_path, un_addr.sa_socklen,
2730 "%s/"SOCKET_FORMAT, socket_wrapper_dir(),
2731 type, socket_wrapper_default_iface(), port);
2732 if (stat(un_addr.sa.un.sun_path, &st) == 0) continue;
2734 ret = libc_bind(fd, &un_addr.sa.s, un_addr.sa_socklen);
2735 if (ret == -1) return ret;
2737 si->un_addr = un_addr.sa.un;
2739 si->bound = 1;
2740 autobind_start = port + 1;
2741 break;
2743 if (i == SOCKET_MAX_SOCKETS) {
2744 SWRAP_LOG(SWRAP_LOG_ERROR, "Too many open unix sockets (%u) for "
2745 "interface "SOCKET_FORMAT,
2746 SOCKET_MAX_SOCKETS,
2747 type,
2748 socket_wrapper_default_iface(),
2750 errno = ENFILE;
2751 return -1;
2754 si->family = family;
2755 set_port(si->family, port, &si->myname);
2757 return 0;
2760 /****************************************************************************
2761 * CONNECT
2762 ***************************************************************************/
2764 static int swrap_connect(int s, const struct sockaddr *serv_addr,
2765 socklen_t addrlen)
2767 int ret;
2768 struct swrap_address un_addr = {
2769 .sa_socklen = sizeof(struct sockaddr_un),
2771 struct socket_info *si = find_socket_info(s);
2772 int bcast = 0;
2774 if (!si) {
2775 return libc_connect(s, serv_addr, addrlen);
2778 if (si->bound == 0) {
2779 ret = swrap_auto_bind(s, si, serv_addr->sa_family);
2780 if (ret == -1) return -1;
2783 if (si->family != serv_addr->sa_family) {
2784 errno = EINVAL;
2785 return -1;
2788 ret = sockaddr_convert_to_un(si, serv_addr,
2789 addrlen, &un_addr.sa.un, 0, &bcast);
2790 if (ret == -1) return -1;
2792 if (bcast) {
2793 errno = ENETUNREACH;
2794 return -1;
2797 if (si->type == SOCK_DGRAM) {
2798 si->defer_connect = 1;
2799 ret = 0;
2800 } else {
2801 swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0);
2803 ret = libc_connect(s,
2804 &un_addr.sa.s,
2805 un_addr.sa_socklen);
2808 SWRAP_LOG(SWRAP_LOG_TRACE,
2809 "connect() path=%s, fd=%d",
2810 un_addr.un.sun_path, s);
2813 /* to give better errors */
2814 if (ret == -1 && errno == ENOENT) {
2815 errno = EHOSTUNREACH;
2818 if (ret == 0) {
2819 si->peername = (struct swrap_address) {
2820 .sa_socklen = addrlen,
2823 memcpy(&si->peername.sa.ss, serv_addr, addrlen);
2824 si->connected = 1;
2827 * When we connect() on a socket than we have to bind the
2828 * outgoing connection on the interface we use for the
2829 * transport. We already bound it on the right interface
2830 * but here we have to update the name so getsockname()
2831 * returns correct information.
2833 if (si->bindname.sa_socklen > 0) {
2834 si->myname = (struct swrap_address) {
2835 .sa_socklen = si->bindname.sa_socklen,
2838 memcpy(&si->myname.sa.ss,
2839 &si->bindname.sa.ss,
2840 si->bindname.sa_socklen);
2842 /* Cleanup bindname */
2843 si->bindname = (struct swrap_address) {
2844 .sa_socklen = 0,
2848 swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0);
2849 swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0);
2850 } else {
2851 swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_UNREACH, NULL, 0);
2854 return ret;
2857 int connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen)
2859 return swrap_connect(s, serv_addr, addrlen);
2862 /****************************************************************************
2863 * BIND
2864 ***************************************************************************/
2866 static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
2868 int ret;
2869 struct swrap_address un_addr = {
2870 .sa_socklen = sizeof(struct sockaddr_un),
2872 struct socket_info *si = find_socket_info(s);
2873 int bind_error = 0;
2874 #if 0 /* FIXME */
2875 bool in_use;
2876 #endif
2878 if (!si) {
2879 return libc_bind(s, myaddr, addrlen);
2882 switch (si->family) {
2883 case AF_INET: {
2884 const struct sockaddr_in *sin;
2885 if (addrlen < sizeof(struct sockaddr_in)) {
2886 bind_error = EINVAL;
2887 break;
2890 sin = (const struct sockaddr_in *)myaddr;
2892 if (sin->sin_family != AF_INET) {
2893 bind_error = EAFNOSUPPORT;
2896 /* special case for AF_UNSPEC */
2897 if (sin->sin_family == AF_UNSPEC &&
2898 (sin->sin_addr.s_addr == htonl(INADDR_ANY)))
2900 bind_error = 0;
2903 break;
2905 #ifdef HAVE_IPV6
2906 case AF_INET6: {
2907 const struct sockaddr_in6 *sin6;
2908 if (addrlen < sizeof(struct sockaddr_in6)) {
2909 bind_error = EINVAL;
2910 break;
2913 sin6 = (const struct sockaddr_in6 *)myaddr;
2915 if (sin6->sin6_family != AF_INET6) {
2916 bind_error = EAFNOSUPPORT;
2919 break;
2921 #endif
2922 default:
2923 bind_error = EINVAL;
2924 break;
2927 if (bind_error != 0) {
2928 errno = bind_error;
2929 return -1;
2932 #if 0 /* FIXME */
2933 in_use = check_addr_port_in_use(myaddr, addrlen);
2934 if (in_use) {
2935 errno = EADDRINUSE;
2936 return -1;
2938 #endif
2940 si->myname.sa_socklen = addrlen;
2941 memcpy(&si->myname.sa.ss, myaddr, addrlen);
2943 ret = sockaddr_convert_to_un(si,
2944 myaddr,
2945 addrlen,
2946 &un_addr.sa.un,
2948 &si->bcast);
2949 if (ret == -1) return -1;
2951 unlink(un_addr.sa.un.sun_path);
2953 ret = libc_bind(s, &un_addr.sa.s, un_addr.sa_socklen);
2955 SWRAP_LOG(SWRAP_LOG_TRACE,
2956 "bind() path=%s, fd=%d",
2957 un_addr.sa_un.sun_path, s);
2959 if (ret == 0) {
2960 si->bound = 1;
2963 return ret;
2966 int bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
2968 return swrap_bind(s, myaddr, addrlen);
2971 /****************************************************************************
2972 * BINDRESVPORT
2973 ***************************************************************************/
2975 #ifdef HAVE_BINDRESVPORT
2976 static int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen);
2978 static int swrap_bindresvport_sa(int sd, struct sockaddr *sa)
2980 struct swrap_address myaddr = {
2981 .sa_socklen = sizeof(struct sockaddr_storage),
2983 socklen_t salen;
2984 static uint16_t port;
2985 uint16_t i;
2986 int rc = -1;
2987 int af;
2989 #define SWRAP_STARTPORT 600
2990 #define SWRAP_ENDPORT (IPPORT_RESERVED - 1)
2991 #define SWRAP_NPORTS (SWRAP_ENDPORT - SWRAP_STARTPORT + 1)
2993 if (port == 0) {
2994 port = (getpid() % SWRAP_NPORTS) + SWRAP_STARTPORT;
2997 if (sa == NULL) {
2998 salen = myaddr.sa_socklen;
2999 sa = &myaddr.sa.s;
3001 rc = swrap_getsockname(sd, &myaddr.sa.s, &salen);
3002 if (rc < 0) {
3003 return -1;
3006 af = sa->sa_family;
3007 memset(&myaddr.sa.ss, 0, salen);
3008 } else {
3009 af = sa->sa_family;
3012 for (i = 0; i < SWRAP_NPORTS; i++, port++) {
3013 switch(af) {
3014 case AF_INET: {
3015 struct sockaddr_in *sinp = (struct sockaddr_in *)(void *)sa;
3017 salen = sizeof(struct sockaddr_in);
3018 sinp->sin_port = htons(port);
3019 break;
3021 case AF_INET6: {
3022 struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *)sa;
3024 salen = sizeof(struct sockaddr_in6);
3025 sin6p->sin6_port = htons(port);
3026 break;
3028 default:
3029 errno = EAFNOSUPPORT;
3030 return -1;
3032 sa->sa_family = af;
3034 if (port > SWRAP_ENDPORT) {
3035 port = SWRAP_STARTPORT;
3038 rc = swrap_bind(sd, (struct sockaddr *)sa, salen);
3039 if (rc == 0 || errno != EADDRINUSE) {
3040 break;
3044 return rc;
3047 int bindresvport(int sockfd, struct sockaddr_in *sinp)
3049 return swrap_bindresvport_sa(sockfd, (struct sockaddr *)sinp);
3051 #endif
3053 /****************************************************************************
3054 * LISTEN
3055 ***************************************************************************/
3057 static int swrap_listen(int s, int backlog)
3059 int ret;
3060 struct socket_info *si = find_socket_info(s);
3062 if (!si) {
3063 return libc_listen(s, backlog);
3066 ret = libc_listen(s, backlog);
3068 return ret;
3071 int listen(int s, int backlog)
3073 return swrap_listen(s, backlog);
3076 /****************************************************************************
3077 * FOPEN
3078 ***************************************************************************/
3080 static FILE *swrap_fopen(const char *name, const char *mode)
3082 FILE *fp;
3084 fp = libc_fopen(name, mode);
3085 if (fp != NULL) {
3086 int fd = fileno(fp);
3088 swrap_remove_stale(fd);
3091 return fp;
3094 FILE *fopen(const char *name, const char *mode)
3096 return swrap_fopen(name, mode);
3099 /****************************************************************************
3100 * OPEN
3101 ***************************************************************************/
3103 static int swrap_vopen(const char *pathname, int flags, va_list ap)
3105 int ret;
3107 ret = libc_vopen(pathname, flags, ap);
3108 if (ret != -1) {
3110 * There are methods for closing descriptors (libc-internal code
3111 * paths, direct syscalls) which close descriptors in ways that
3112 * we can't intercept, so try to recover when we notice that
3113 * that's happened
3115 swrap_remove_stale(ret);
3117 return ret;
3120 int open(const char *pathname, int flags, ...)
3122 va_list ap;
3123 int fd;
3125 va_start(ap, flags);
3126 fd = swrap_vopen(pathname, flags, ap);
3127 va_end(ap);
3129 return fd;
3132 /****************************************************************************
3133 * GETPEERNAME
3134 ***************************************************************************/
3136 static int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
3138 struct socket_info *si = find_socket_info(s);
3139 socklen_t len;
3141 if (!si) {
3142 return libc_getpeername(s, name, addrlen);
3145 if (si->peername.sa_socklen == 0)
3147 errno = ENOTCONN;
3148 return -1;
3151 len = MIN(*addrlen, si->peername.sa_socklen);
3152 if (len == 0) {
3153 return 0;
3156 memcpy(name, &si->peername.sa.ss, len);
3157 *addrlen = si->peername.sa_socklen;
3159 return 0;
3162 #ifdef HAVE_ACCEPT_PSOCKLEN_T
3163 int getpeername(int s, struct sockaddr *name, Psocklen_t addrlen)
3164 #else
3165 int getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
3166 #endif
3168 return swrap_getpeername(s, name, (socklen_t *)addrlen);
3171 /****************************************************************************
3172 * GETSOCKNAME
3173 ***************************************************************************/
3175 static int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
3177 struct socket_info *si = find_socket_info(s);
3178 socklen_t len;
3180 if (!si) {
3181 return libc_getsockname(s, name, addrlen);
3184 len = MIN(*addrlen, si->myname.sa_socklen);
3185 if (len == 0) {
3186 return 0;
3189 memcpy(name, &si->myname.sa.ss, len);
3190 *addrlen = si->myname.sa_socklen;
3192 return 0;
3195 #ifdef HAVE_ACCEPT_PSOCKLEN_T
3196 int getsockname(int s, struct sockaddr *name, Psocklen_t addrlen)
3197 #else
3198 int getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
3199 #endif
3201 return swrap_getsockname(s, name, (socklen_t *)addrlen);
3204 /****************************************************************************
3205 * GETSOCKOPT
3206 ***************************************************************************/
3208 #ifndef SO_PROTOCOL
3209 # ifdef SO_PROTOTYPE /* The Solaris name */
3210 # define SO_PROTOCOL SO_PROTOTYPE
3211 # endif /* SO_PROTOTYPE */
3212 #endif /* SO_PROTOCOL */
3214 static int swrap_getsockopt(int s, int level, int optname,
3215 void *optval, socklen_t *optlen)
3217 struct socket_info *si = find_socket_info(s);
3219 if (!si) {
3220 return libc_getsockopt(s,
3221 level,
3222 optname,
3223 optval,
3224 optlen);
3227 if (level == SOL_SOCKET) {
3228 switch (optname) {
3229 #ifdef SO_DOMAIN
3230 case SO_DOMAIN:
3231 if (optval == NULL || optlen == NULL ||
3232 *optlen < (socklen_t)sizeof(int)) {
3233 errno = EINVAL;
3234 return -1;
3237 *optlen = sizeof(int);
3238 *(int *)optval = si->family;
3239 return 0;
3240 #endif /* SO_DOMAIN */
3242 #ifdef SO_PROTOCOL
3243 case SO_PROTOCOL:
3244 if (optval == NULL || optlen == NULL ||
3245 *optlen < (socklen_t)sizeof(int)) {
3246 errno = EINVAL;
3247 return -1;
3250 *optlen = sizeof(int);
3251 *(int *)optval = si->protocol;
3252 return 0;
3253 #endif /* SO_PROTOCOL */
3254 case SO_TYPE:
3255 if (optval == NULL || optlen == NULL ||
3256 *optlen < (socklen_t)sizeof(int)) {
3257 errno = EINVAL;
3258 return -1;
3261 *optlen = sizeof(int);
3262 *(int *)optval = si->type;
3263 return 0;
3264 default:
3265 return libc_getsockopt(s,
3266 level,
3267 optname,
3268 optval,
3269 optlen);
3273 errno = ENOPROTOOPT;
3274 return -1;
3277 #ifdef HAVE_ACCEPT_PSOCKLEN_T
3278 int getsockopt(int s, int level, int optname, void *optval, Psocklen_t optlen)
3279 #else
3280 int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
3281 #endif
3283 return swrap_getsockopt(s, level, optname, optval, (socklen_t *)optlen);
3286 /****************************************************************************
3287 * SETSOCKOPT
3288 ***************************************************************************/
3290 static int swrap_setsockopt(int s, int level, int optname,
3291 const void *optval, socklen_t optlen)
3293 struct socket_info *si = find_socket_info(s);
3295 if (!si) {
3296 return libc_setsockopt(s,
3297 level,
3298 optname,
3299 optval,
3300 optlen);
3303 if (level == SOL_SOCKET) {
3304 return libc_setsockopt(s,
3305 level,
3306 optname,
3307 optval,
3308 optlen);
3311 switch (si->family) {
3312 case AF_INET:
3313 if (level == IPPROTO_IP) {
3314 #ifdef IP_PKTINFO
3315 if (optname == IP_PKTINFO) {
3316 si->pktinfo = AF_INET;
3318 #endif /* IP_PKTINFO */
3320 return 0;
3321 #ifdef HAVE_IPV6
3322 case AF_INET6:
3323 if (level == IPPROTO_IPV6) {
3324 #ifdef IPV6_RECVPKTINFO
3325 if (optname == IPV6_RECVPKTINFO) {
3326 si->pktinfo = AF_INET6;
3328 #endif /* IPV6_PKTINFO */
3330 return 0;
3331 #endif
3332 default:
3333 errno = ENOPROTOOPT;
3334 return -1;
3338 int setsockopt(int s, int level, int optname,
3339 const void *optval, socklen_t optlen)
3341 return swrap_setsockopt(s, level, optname, optval, optlen);
3344 /****************************************************************************
3345 * IOCTL
3346 ***************************************************************************/
3348 static int swrap_vioctl(int s, unsigned long int r, va_list va)
3350 struct socket_info *si = find_socket_info(s);
3351 va_list ap;
3352 int value;
3353 int rc;
3355 if (!si) {
3356 return libc_vioctl(s, r, va);
3359 va_copy(ap, va);
3361 rc = libc_vioctl(s, r, va);
3363 switch (r) {
3364 case FIONREAD:
3365 value = *((int *)va_arg(ap, int *));
3367 if (rc == -1 && errno != EAGAIN && errno != ENOBUFS) {
3368 swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
3369 } else if (value == 0) { /* END OF FILE */
3370 swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
3372 break;
3375 va_end(ap);
3377 return rc;
3380 #ifdef HAVE_IOCTL_INT
3381 int ioctl(int s, int r, ...)
3382 #else
3383 int ioctl(int s, unsigned long int r, ...)
3384 #endif
3386 va_list va;
3387 int rc;
3389 va_start(va, r);
3391 rc = swrap_vioctl(s, (unsigned long int) r, va);
3393 va_end(va);
3395 return rc;
3398 /*****************
3399 * CMSG
3400 *****************/
3402 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
3404 #ifndef CMSG_ALIGN
3405 # ifdef _ALIGN /* BSD */
3406 #define CMSG_ALIGN _ALIGN
3407 # else
3408 #define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1))
3409 # endif /* _ALIGN */
3410 #endif /* CMSG_ALIGN */
3413 * @brief Add a cmsghdr to a msghdr.
3415 * This is an function to add any type of cmsghdr. It will operate on the
3416 * msg->msg_control and msg->msg_controllen you pass in by adapting them to
3417 * the buffer position after the added cmsg element. Hence, this function is
3418 * intended to be used with an intermediate msghdr and not on the original
3419 * one handed in by the client.
3421 * @param[in] msg The msghdr to which to add the cmsg.
3423 * @param[in] level The cmsg level to set.
3425 * @param[in] type The cmsg type to set.
3427 * @param[in] data The cmsg data to set.
3429 * @param[in] len the length of the data to set.
3431 static void swrap_msghdr_add_cmsghdr(struct msghdr *msg,
3432 int level,
3433 int type,
3434 const void *data,
3435 size_t len)
3437 size_t cmlen = CMSG_LEN(len);
3438 size_t cmspace = CMSG_SPACE(len);
3439 uint8_t cmbuf[cmspace];
3440 void *cast_ptr = (void *)cmbuf;
3441 struct cmsghdr *cm = (struct cmsghdr *)cast_ptr;
3442 uint8_t *p;
3444 memset(cmbuf, 0, cmspace);
3446 if (msg->msg_controllen < cmlen) {
3447 cmlen = msg->msg_controllen;
3448 msg->msg_flags |= MSG_CTRUNC;
3451 if (msg->msg_controllen < cmspace) {
3452 cmspace = msg->msg_controllen;
3456 * We copy the full input data into an intermediate cmsghdr first
3457 * in order to more easily cope with truncation.
3459 cm->cmsg_len = cmlen;
3460 cm->cmsg_level = level;
3461 cm->cmsg_type = type;
3462 memcpy(CMSG_DATA(cm), data, len);
3465 * We now copy the possibly truncated buffer.
3466 * We copy cmlen bytes, but consume cmspace bytes,
3467 * leaving the possible padding uninitialiazed.
3469 p = (uint8_t *)msg->msg_control;
3470 memcpy(p, cm, cmlen);
3471 p += cmspace;
3472 msg->msg_control = p;
3473 msg->msg_controllen -= cmspace;
3475 return;
3478 static int swrap_msghdr_add_pktinfo(struct socket_info *si,
3479 struct msghdr *msg)
3481 /* Add packet info */
3482 switch (si->pktinfo) {
3483 #if defined(IP_PKTINFO) && (defined(HAVE_STRUCT_IN_PKTINFO) || defined(IP_RECVDSTADDR))
3484 case AF_INET: {
3485 struct sockaddr_in *sin;
3486 #if defined(HAVE_STRUCT_IN_PKTINFO)
3487 struct in_pktinfo pkt;
3488 #elif defined(IP_RECVDSTADDR)
3489 struct in_addr pkt;
3490 #endif
3492 if (si->bindname.sa_socklen == sizeof(struct sockaddr_in)) {
3493 sin = &si->bindname.sa.in;
3494 } else {
3495 if (si->myname.sa_socklen != sizeof(struct sockaddr_in)) {
3496 return 0;
3498 sin = &si->myname.sa.in;
3501 ZERO_STRUCT(pkt);
3503 #if defined(HAVE_STRUCT_IN_PKTINFO)
3504 pkt.ipi_ifindex = socket_wrapper_default_iface();
3505 pkt.ipi_addr.s_addr = sin->sin_addr.s_addr;
3506 #elif defined(IP_RECVDSTADDR)
3507 pkt = sin->sin_addr;
3508 #endif
3510 swrap_msghdr_add_cmsghdr(msg, IPPROTO_IP, IP_PKTINFO,
3511 &pkt, sizeof(pkt));
3513 break;
3515 #endif /* IP_PKTINFO */
3516 #if defined(HAVE_IPV6)
3517 case AF_INET6: {
3518 #if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO)
3519 struct sockaddr_in6 *sin6;
3520 struct in6_pktinfo pkt6;
3522 if (si->bindname.sa_socklen == sizeof(struct sockaddr_in6)) {
3523 sin6 = &si->bindname.sa.in6;
3524 } else {
3525 if (si->myname.sa_socklen != sizeof(struct sockaddr_in6)) {
3526 return 0;
3528 sin6 = &si->myname.sa.in6;
3531 ZERO_STRUCT(pkt6);
3533 pkt6.ipi6_ifindex = socket_wrapper_default_iface();
3534 pkt6.ipi6_addr = sin6->sin6_addr;
3536 swrap_msghdr_add_cmsghdr(msg, IPPROTO_IPV6, IPV6_PKTINFO,
3537 &pkt6, sizeof(pkt6));
3538 #endif /* HAVE_STRUCT_IN6_PKTINFO */
3540 break;
3542 #endif /* IPV6_PKTINFO */
3543 default:
3544 return -1;
3547 return 0;
3550 static int swrap_msghdr_add_socket_info(struct socket_info *si,
3551 struct msghdr *omsg)
3553 int rc = 0;
3555 if (si->pktinfo > 0) {
3556 rc = swrap_msghdr_add_pktinfo(si, omsg);
3559 return rc;
3562 static int swrap_sendmsg_copy_cmsg(struct cmsghdr *cmsg,
3563 uint8_t **cm_data,
3564 size_t *cm_data_space);
3565 static int swrap_sendmsg_filter_cmsg_socket(struct cmsghdr *cmsg,
3566 uint8_t **cm_data,
3567 size_t *cm_data_space);
3569 static int swrap_sendmsg_filter_cmsghdr(struct msghdr *msg,
3570 uint8_t **cm_data,
3571 size_t *cm_data_space) {
3572 struct cmsghdr *cmsg;
3573 int rc = -1;
3575 /* Nothing to do */
3576 if (msg->msg_controllen == 0 || msg->msg_control == NULL) {
3577 return 0;
3580 for (cmsg = CMSG_FIRSTHDR(msg);
3581 cmsg != NULL;
3582 cmsg = CMSG_NXTHDR(msg, cmsg)) {
3583 switch (cmsg->cmsg_level) {
3584 case IPPROTO_IP:
3585 rc = swrap_sendmsg_filter_cmsg_socket(cmsg,
3586 cm_data,
3587 cm_data_space);
3588 break;
3589 default:
3590 rc = swrap_sendmsg_copy_cmsg(cmsg,
3591 cm_data,
3592 cm_data_space);
3593 break;
3597 return rc;
3600 static int swrap_sendmsg_copy_cmsg(struct cmsghdr *cmsg,
3601 uint8_t **cm_data,
3602 size_t *cm_data_space)
3604 size_t cmspace;
3605 uint8_t *p;
3607 cmspace =
3608 (*cm_data_space) +
3609 CMSG_SPACE(cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)));
3611 p = realloc((*cm_data), cmspace);
3612 if (p == NULL) {
3613 return -1;
3615 (*cm_data) = p;
3617 p = (*cm_data) + (*cm_data_space);
3618 *cm_data_space = cmspace;
3620 memcpy(p, cmsg, cmsg->cmsg_len);
3622 return 0;
3625 static int swrap_sendmsg_filter_cmsg_pktinfo(struct cmsghdr *cmsg,
3626 uint8_t **cm_data,
3627 size_t *cm_data_space);
3630 static int swrap_sendmsg_filter_cmsg_socket(struct cmsghdr *cmsg,
3631 uint8_t **cm_data,
3632 size_t *cm_data_space)
3634 int rc = -1;
3636 switch(cmsg->cmsg_type) {
3637 #ifdef IP_PKTINFO
3638 case IP_PKTINFO:
3639 rc = swrap_sendmsg_filter_cmsg_pktinfo(cmsg,
3640 cm_data,
3641 cm_data_space);
3642 break;
3643 #endif
3644 #ifdef IPV6_PKTINFO
3645 case IPV6_PKTINFO:
3646 rc = swrap_sendmsg_filter_cmsg_pktinfo(cmsg,
3647 cm_data,
3648 cm_data_space);
3649 break;
3650 #endif
3651 default:
3652 break;
3655 return rc;
3658 static int swrap_sendmsg_filter_cmsg_pktinfo(struct cmsghdr *cmsg,
3659 uint8_t **cm_data,
3660 size_t *cm_data_space)
3662 (void)cmsg; /* unused */
3663 (void)cm_data; /* unused */
3664 (void)cm_data_space; /* unused */
3667 * Passing a IP pktinfo to a unix socket might be rejected by the
3668 * Kernel, at least on FreeBSD. So skip this cmsg.
3670 return 0;
3672 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
3674 static ssize_t swrap_sendmsg_before(int fd,
3675 struct socket_info *si,
3676 struct msghdr *msg,
3677 struct iovec *tmp_iov,
3678 struct sockaddr_un *tmp_un,
3679 const struct sockaddr_un **to_un,
3680 const struct sockaddr **to,
3681 int *bcast)
3683 size_t i, len = 0;
3684 ssize_t ret;
3686 if (to_un) {
3687 *to_un = NULL;
3689 if (to) {
3690 *to = NULL;
3692 if (bcast) {
3693 *bcast = 0;
3696 switch (si->type) {
3697 case SOCK_STREAM:
3698 if (!si->connected) {
3699 errno = ENOTCONN;
3700 return -1;
3703 if (msg->msg_iovlen == 0) {
3704 break;
3707 for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
3708 size_t nlen;
3709 nlen = len + msg->msg_iov[i].iov_len;
3710 if (nlen > SOCKET_MAX_PACKET) {
3711 break;
3714 msg->msg_iovlen = i;
3715 if (msg->msg_iovlen == 0) {
3716 *tmp_iov = msg->msg_iov[0];
3717 tmp_iov->iov_len = MIN(tmp_iov->iov_len, SOCKET_MAX_PACKET);
3718 msg->msg_iov = tmp_iov;
3719 msg->msg_iovlen = 1;
3721 break;
3723 case SOCK_DGRAM:
3724 if (si->connected) {
3725 if (msg->msg_name) {
3726 errno = EISCONN;
3727 return -1;
3729 } else {
3730 const struct sockaddr *msg_name;
3731 msg_name = (const struct sockaddr *)msg->msg_name;
3733 if (msg_name == NULL) {
3734 errno = ENOTCONN;
3735 return -1;
3739 ret = sockaddr_convert_to_un(si, msg_name, msg->msg_namelen,
3740 tmp_un, 0, bcast);
3741 if (ret == -1) return -1;
3743 if (to_un) {
3744 *to_un = tmp_un;
3746 if (to) {
3747 *to = msg_name;
3749 msg->msg_name = tmp_un;
3750 msg->msg_namelen = sizeof(*tmp_un);
3753 if (si->bound == 0) {
3754 ret = swrap_auto_bind(fd, si, si->family);
3755 if (ret == -1) {
3756 if (errno == ENOTSOCK) {
3757 swrap_remove_stale(fd);
3758 return -ENOTSOCK;
3759 } else {
3760 SWRAP_LOG(SWRAP_LOG_ERROR, "swrap_sendmsg_before failed");
3761 return -1;
3766 if (!si->defer_connect) {
3767 break;
3770 ret = sockaddr_convert_to_un(si,
3771 &si->peername.sa.s,
3772 si->peername.sa_socklen,
3773 tmp_un,
3775 NULL);
3776 if (ret == -1) return -1;
3778 ret = libc_connect(fd,
3779 (struct sockaddr *)(void *)tmp_un,
3780 sizeof(*tmp_un));
3782 /* to give better errors */
3783 if (ret == -1 && errno == ENOENT) {
3784 errno = EHOSTUNREACH;
3787 if (ret == -1) {
3788 return ret;
3791 si->defer_connect = 0;
3792 break;
3793 default:
3794 errno = EHOSTUNREACH;
3795 return -1;
3798 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
3799 if (msg->msg_controllen > 0 && msg->msg_control != NULL) {
3800 uint8_t *cmbuf = NULL;
3801 size_t cmlen = 0;
3803 ret = swrap_sendmsg_filter_cmsghdr(msg, &cmbuf, &cmlen);
3804 if (ret < 0) {
3805 free(cmbuf);
3806 return -1;
3809 if (cmlen == 0) {
3810 msg->msg_controllen = 0;
3811 msg->msg_control = NULL;
3812 } else if (cmlen < msg->msg_controllen && cmbuf != NULL) {
3813 memcpy(msg->msg_control, cmbuf, cmlen);
3814 msg->msg_controllen = cmlen;
3816 free(cmbuf);
3818 #endif
3820 return 0;
3823 static void swrap_sendmsg_after(int fd,
3824 struct socket_info *si,
3825 struct msghdr *msg,
3826 const struct sockaddr *to,
3827 ssize_t ret)
3829 int saved_errno = errno;
3830 size_t i, len = 0;
3831 uint8_t *buf;
3832 off_t ofs = 0;
3833 size_t avail = 0;
3834 size_t remain;
3836 /* to give better errors */
3837 if (ret == -1) {
3838 if (saved_errno == ENOENT) {
3839 saved_errno = EHOSTUNREACH;
3840 } else if (saved_errno == ENOTSOCK) {
3841 /* If the fd is not a socket, remove it */
3842 swrap_remove_stale(fd);
3846 for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
3847 avail += msg->msg_iov[i].iov_len;
3850 if (ret == -1) {
3851 remain = MIN(80, avail);
3852 } else {
3853 remain = ret;
3856 /* we capture it as one single packet */
3857 buf = (uint8_t *)malloc(remain);
3858 if (!buf) {
3859 /* we just not capture the packet */
3860 errno = saved_errno;
3861 return;
3864 for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
3865 size_t this_time = MIN(remain, (size_t)msg->msg_iov[i].iov_len);
3866 memcpy(buf + ofs,
3867 msg->msg_iov[i].iov_base,
3868 this_time);
3869 ofs += this_time;
3870 remain -= this_time;
3872 len = ofs;
3874 switch (si->type) {
3875 case SOCK_STREAM:
3876 if (ret == -1) {
3877 swrap_pcap_dump_packet(si, NULL, SWRAP_SEND, buf, len);
3878 swrap_pcap_dump_packet(si, NULL, SWRAP_SEND_RST, NULL, 0);
3879 } else {
3880 swrap_pcap_dump_packet(si, NULL, SWRAP_SEND, buf, len);
3882 break;
3884 case SOCK_DGRAM:
3885 if (si->connected) {
3886 to = &si->peername.sa.s;
3888 if (ret == -1) {
3889 swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
3890 swrap_pcap_dump_packet(si, to, SWRAP_SENDTO_UNREACH, buf, len);
3891 } else {
3892 swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
3894 break;
3897 free(buf);
3898 errno = saved_errno;
3901 static int swrap_recvmsg_before(int fd,
3902 struct socket_info *si,
3903 struct msghdr *msg,
3904 struct iovec *tmp_iov)
3906 size_t i, len = 0;
3907 ssize_t ret;
3909 (void)fd; /* unused */
3911 switch (si->type) {
3912 case SOCK_STREAM:
3913 if (!si->connected) {
3914 errno = ENOTCONN;
3915 return -1;
3918 if (msg->msg_iovlen == 0) {
3919 break;
3922 for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
3923 size_t nlen;
3924 nlen = len + msg->msg_iov[i].iov_len;
3925 if (nlen > SOCKET_MAX_PACKET) {
3926 break;
3929 msg->msg_iovlen = i;
3930 if (msg->msg_iovlen == 0) {
3931 *tmp_iov = msg->msg_iov[0];
3932 tmp_iov->iov_len = MIN(tmp_iov->iov_len, SOCKET_MAX_PACKET);
3933 msg->msg_iov = tmp_iov;
3934 msg->msg_iovlen = 1;
3936 break;
3938 case SOCK_DGRAM:
3939 if (msg->msg_name == NULL) {
3940 errno = EINVAL;
3941 return -1;
3944 if (msg->msg_iovlen == 0) {
3945 break;
3948 if (si->bound == 0) {
3949 ret = swrap_auto_bind(fd, si, si->family);
3950 if (ret == -1) {
3952 * When attempting to read or write to a
3953 * descriptor, if an underlying autobind fails
3954 * because it's not a socket, stop intercepting
3955 * uses of that descriptor.
3957 if (errno == ENOTSOCK) {
3958 swrap_remove_stale(fd);
3959 return -ENOTSOCK;
3960 } else {
3961 SWRAP_LOG(SWRAP_LOG_ERROR,
3962 "swrap_recvmsg_before failed");
3963 return -1;
3967 break;
3968 default:
3969 errno = EHOSTUNREACH;
3970 return -1;
3973 return 0;
3976 static int swrap_recvmsg_after(int fd,
3977 struct socket_info *si,
3978 struct msghdr *msg,
3979 const struct sockaddr_un *un_addr,
3980 socklen_t un_addrlen,
3981 ssize_t ret)
3983 int saved_errno = errno;
3984 size_t i;
3985 uint8_t *buf = NULL;
3986 off_t ofs = 0;
3987 size_t avail = 0;
3988 size_t remain;
3989 int rc;
3991 /* to give better errors */
3992 if (ret == -1) {
3993 if (saved_errno == ENOENT) {
3994 saved_errno = EHOSTUNREACH;
3995 } else if (saved_errno == ENOTSOCK) {
3996 /* If the fd is not a socket, remove it */
3997 swrap_remove_stale(fd);
4001 for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
4002 avail += msg->msg_iov[i].iov_len;
4005 if (avail == 0) {
4006 rc = 0;
4007 goto done;
4010 if (ret == -1) {
4011 remain = MIN(80, avail);
4012 } else {
4013 remain = ret;
4016 /* we capture it as one single packet */
4017 buf = (uint8_t *)malloc(remain);
4018 if (buf == NULL) {
4019 /* we just not capture the packet */
4020 errno = saved_errno;
4021 return -1;
4024 for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
4025 size_t this_time = MIN(remain, (size_t)msg->msg_iov[i].iov_len);
4026 memcpy(buf + ofs,
4027 msg->msg_iov[i].iov_base,
4028 this_time);
4029 ofs += this_time;
4030 remain -= this_time;
4033 switch (si->type) {
4034 case SOCK_STREAM:
4035 if (ret == -1 && saved_errno != EAGAIN && saved_errno != ENOBUFS) {
4036 swrap_pcap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
4037 } else if (ret == 0) { /* END OF FILE */
4038 swrap_pcap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
4039 } else if (ret > 0) {
4040 swrap_pcap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
4042 break;
4044 case SOCK_DGRAM:
4045 if (ret == -1) {
4046 break;
4049 if (un_addr != NULL) {
4050 rc = sockaddr_convert_from_un(si,
4051 un_addr,
4052 un_addrlen,
4053 si->family,
4054 msg->msg_name,
4055 &msg->msg_namelen);
4056 if (rc == -1) {
4057 goto done;
4060 swrap_pcap_dump_packet(si,
4061 msg->msg_name,
4062 SWRAP_RECVFROM,
4063 buf,
4064 ret);
4065 } else {
4066 swrap_pcap_dump_packet(si,
4067 msg->msg_name,
4068 SWRAP_RECV,
4069 buf,
4070 ret);
4073 break;
4076 rc = 0;
4077 done:
4078 free(buf);
4079 errno = saved_errno;
4081 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4082 if (rc == 0 &&
4083 msg->msg_controllen > 0 &&
4084 msg->msg_control != NULL) {
4085 rc = swrap_msghdr_add_socket_info(si, msg);
4086 if (rc < 0) {
4087 return -1;
4090 #endif
4092 return rc;
4095 /****************************************************************************
4096 * RECVFROM
4097 ***************************************************************************/
4099 static ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags,
4100 struct sockaddr *from, socklen_t *fromlen)
4102 struct swrap_address from_addr = {
4103 .sa_socklen = sizeof(struct sockaddr_un),
4105 ssize_t ret;
4106 struct socket_info *si = find_socket_info(s);
4107 struct swrap_address saddr = {
4108 .sa_socklen = sizeof(struct sockaddr_storage),
4110 struct msghdr msg;
4111 struct iovec tmp;
4112 int tret;
4114 if (!si) {
4115 return libc_recvfrom(s,
4116 buf,
4117 len,
4118 flags,
4119 from,
4120 fromlen);
4123 tmp.iov_base = buf;
4124 tmp.iov_len = len;
4126 ZERO_STRUCT(msg);
4127 if (from != NULL && fromlen != NULL) {
4128 msg.msg_name = from; /* optional address */
4129 msg.msg_namelen = *fromlen; /* size of address */
4130 } else {
4131 msg.msg_name = &saddr.sa.s; /* optional address */
4132 msg.msg_namelen = saddr.sa_socklen; /* size of address */
4134 msg.msg_iov = &tmp; /* scatter/gather array */
4135 msg.msg_iovlen = 1; /* # elements in msg_iov */
4136 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4137 msg.msg_control = NULL; /* ancillary data, see below */
4138 msg.msg_controllen = 0; /* ancillary data buffer len */
4139 msg.msg_flags = 0; /* flags on received message */
4140 #endif
4142 tret = swrap_recvmsg_before(s, si, &msg, &tmp);
4143 if (tret < 0) {
4144 return -1;
4147 buf = msg.msg_iov[0].iov_base;
4148 len = msg.msg_iov[0].iov_len;
4150 ret = libc_recvfrom(s,
4151 buf,
4152 len,
4153 flags,
4154 &from_addr.sa.s,
4155 &from_addr.sa_socklen);
4156 if (ret == -1) {
4157 return ret;
4160 tret = swrap_recvmsg_after(s,
4162 &msg,
4163 &from_addr.sa.un,
4164 from_addr.sa_socklen,
4165 ret);
4166 if (tret != 0) {
4167 return tret;
4170 if (from != NULL && fromlen != NULL) {
4171 *fromlen = msg.msg_namelen;
4174 return ret;
4177 #ifdef HAVE_ACCEPT_PSOCKLEN_T
4178 ssize_t recvfrom(int s, void *buf, size_t len, int flags,
4179 struct sockaddr *from, Psocklen_t fromlen)
4180 #else
4181 ssize_t recvfrom(int s, void *buf, size_t len, int flags,
4182 struct sockaddr *from, socklen_t *fromlen)
4183 #endif
4185 return swrap_recvfrom(s, buf, len, flags, from, (socklen_t *)fromlen);
4188 /****************************************************************************
4189 * SENDTO
4190 ***************************************************************************/
4192 static ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags,
4193 const struct sockaddr *to, socklen_t tolen)
4195 struct msghdr msg;
4196 struct iovec tmp;
4197 struct swrap_address un_addr = {
4198 .sa_socklen = sizeof(struct sockaddr_un),
4200 const struct sockaddr_un *to_un = NULL;
4201 ssize_t ret;
4202 int rc;
4203 struct socket_info *si = find_socket_info(s);
4204 int bcast = 0;
4206 if (!si) {
4207 return libc_sendto(s, buf, len, flags, to, tolen);
4210 tmp.iov_base = discard_const_p(char, buf);
4211 tmp.iov_len = len;
4213 ZERO_STRUCT(msg);
4214 msg.msg_name = discard_const_p(struct sockaddr, to); /* optional address */
4215 msg.msg_namelen = tolen; /* size of address */
4216 msg.msg_iov = &tmp; /* scatter/gather array */
4217 msg.msg_iovlen = 1; /* # elements in msg_iov */
4218 #if HAVE_STRUCT_MSGHDR_MSG_CONTROL
4219 msg.msg_control = NULL; /* ancillary data, see below */
4220 msg.msg_controllen = 0; /* ancillary data buffer len */
4221 msg.msg_flags = 0; /* flags on received message */
4222 #endif
4224 rc = swrap_sendmsg_before(s,
4226 &msg,
4227 &tmp,
4228 &un_addr.sa.un,
4229 &to_un,
4230 &to,
4231 &bcast);
4232 if (rc < 0) {
4233 return -1;
4236 buf = msg.msg_iov[0].iov_base;
4237 len = msg.msg_iov[0].iov_len;
4239 if (bcast) {
4240 struct stat st;
4241 unsigned int iface;
4242 unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
4243 char type;
4245 type = SOCKET_TYPE_CHAR_UDP;
4247 for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
4248 snprintf(un_addr.sa.un.sun_path,
4249 sizeof(un_addr.sa.un.sun_path),
4250 "%s/"SOCKET_FORMAT,
4251 socket_wrapper_dir(), type, iface, prt);
4252 if (stat(un_addr.sa.un.sun_path, &st) != 0) continue;
4254 /* ignore the any errors in broadcast sends */
4255 libc_sendto(s,
4256 buf,
4257 len,
4258 flags,
4259 &un_addr.sa.s,
4260 un_addr.sa_socklen);
4263 swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
4265 return len;
4268 ret = libc_sendto(s,
4269 buf,
4270 len,
4271 flags,
4272 (struct sockaddr *)msg.msg_name,
4273 msg.msg_namelen);
4275 swrap_sendmsg_after(s, si, &msg, to, ret);
4277 return ret;
4280 ssize_t sendto(int s, const void *buf, size_t len, int flags,
4281 const struct sockaddr *to, socklen_t tolen)
4283 return swrap_sendto(s, buf, len, flags, to, tolen);
4286 /****************************************************************************
4287 * READV
4288 ***************************************************************************/
4290 static ssize_t swrap_recv(int s, void *buf, size_t len, int flags)
4292 struct socket_info *si;
4293 struct msghdr msg;
4294 struct swrap_address saddr = {
4295 .sa_socklen = sizeof(struct sockaddr_storage),
4297 struct iovec tmp;
4298 ssize_t ret;
4299 int tret;
4301 si = find_socket_info(s);
4302 if (si == NULL) {
4303 return libc_recv(s, buf, len, flags);
4306 tmp.iov_base = buf;
4307 tmp.iov_len = len;
4309 ZERO_STRUCT(msg);
4310 msg.msg_name = &saddr.sa.s; /* optional address */
4311 msg.msg_namelen = saddr.sa_socklen; /* size of address */
4312 msg.msg_iov = &tmp; /* scatter/gather array */
4313 msg.msg_iovlen = 1; /* # elements in msg_iov */
4314 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4315 msg.msg_control = NULL; /* ancillary data, see below */
4316 msg.msg_controllen = 0; /* ancillary data buffer len */
4317 msg.msg_flags = 0; /* flags on received message */
4318 #endif
4320 tret = swrap_recvmsg_before(s, si, &msg, &tmp);
4321 if (tret < 0) {
4322 return -1;
4325 buf = msg.msg_iov[0].iov_base;
4326 len = msg.msg_iov[0].iov_len;
4328 ret = libc_recv(s, buf, len, flags);
4330 tret = swrap_recvmsg_after(s, si, &msg, NULL, 0, ret);
4331 if (tret != 0) {
4332 return tret;
4335 return ret;
4338 ssize_t recv(int s, void *buf, size_t len, int flags)
4340 return swrap_recv(s, buf, len, flags);
4343 /****************************************************************************
4344 * READ
4345 ***************************************************************************/
4347 static ssize_t swrap_read(int s, void *buf, size_t len)
4349 struct socket_info *si;
4350 struct msghdr msg;
4351 struct iovec tmp;
4352 struct swrap_address saddr = {
4353 .sa_socklen = sizeof(struct sockaddr_storage),
4355 ssize_t ret;
4356 int tret;
4358 si = find_socket_info(s);
4359 if (si == NULL) {
4360 return libc_read(s, buf, len);
4363 tmp.iov_base = buf;
4364 tmp.iov_len = len;
4366 ZERO_STRUCT(msg);
4367 msg.msg_name = &saddr.sa.ss; /* optional address */
4368 msg.msg_namelen = saddr.sa_socklen; /* size of address */
4369 msg.msg_iov = &tmp; /* scatter/gather array */
4370 msg.msg_iovlen = 1; /* # elements in msg_iov */
4371 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4372 msg.msg_control = NULL; /* ancillary data, see below */
4373 msg.msg_controllen = 0; /* ancillary data buffer len */
4374 msg.msg_flags = 0; /* flags on received message */
4375 #endif
4377 tret = swrap_recvmsg_before(s, si, &msg, &tmp);
4378 if (tret < 0) {
4379 if (tret == -ENOTSOCK) {
4380 return libc_read(s, buf, len);
4382 return -1;
4385 buf = msg.msg_iov[0].iov_base;
4386 len = msg.msg_iov[0].iov_len;
4388 ret = libc_read(s, buf, len);
4390 tret = swrap_recvmsg_after(s, si, &msg, NULL, 0, ret);
4391 if (tret != 0) {
4392 return tret;
4395 return ret;
4398 ssize_t read(int s, void *buf, size_t len)
4400 return swrap_read(s, buf, len);
4403 /****************************************************************************
4404 * SEND
4405 ***************************************************************************/
4407 static ssize_t swrap_send(int s, const void *buf, size_t len, int flags)
4409 struct msghdr msg;
4410 struct iovec tmp;
4411 struct sockaddr_un un_addr;
4412 ssize_t ret;
4413 int rc;
4414 struct socket_info *si = find_socket_info(s);
4416 if (!si) {
4417 return libc_send(s, buf, len, flags);
4420 tmp.iov_base = discard_const_p(char, buf);
4421 tmp.iov_len = len;
4423 ZERO_STRUCT(msg);
4424 msg.msg_name = NULL; /* optional address */
4425 msg.msg_namelen = 0; /* size of address */
4426 msg.msg_iov = &tmp; /* scatter/gather array */
4427 msg.msg_iovlen = 1; /* # elements in msg_iov */
4428 #if HAVE_STRUCT_MSGHDR_MSG_CONTROL
4429 msg.msg_control = NULL; /* ancillary data, see below */
4430 msg.msg_controllen = 0; /* ancillary data buffer len */
4431 msg.msg_flags = 0; /* flags on received message */
4432 #endif
4434 rc = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, NULL, NULL, NULL);
4435 if (rc < 0) {
4436 return -1;
4439 buf = msg.msg_iov[0].iov_base;
4440 len = msg.msg_iov[0].iov_len;
4442 ret = libc_send(s, buf, len, flags);
4444 swrap_sendmsg_after(s, si, &msg, NULL, ret);
4446 return ret;
4449 ssize_t send(int s, const void *buf, size_t len, int flags)
4451 return swrap_send(s, buf, len, flags);
4454 /****************************************************************************
4455 * RECVMSG
4456 ***************************************************************************/
4458 static ssize_t swrap_recvmsg(int s, struct msghdr *omsg, int flags)
4460 struct swrap_address from_addr = {
4461 .sa_socklen = sizeof(struct sockaddr_un),
4463 struct socket_info *si;
4464 struct msghdr msg;
4465 struct iovec tmp;
4466 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4467 size_t msg_ctrllen_filled;
4468 size_t msg_ctrllen_left;
4469 #endif
4471 ssize_t ret;
4472 int rc;
4474 si = find_socket_info(s);
4475 if (si == NULL) {
4476 return libc_recvmsg(s, omsg, flags);
4479 tmp.iov_base = NULL;
4480 tmp.iov_len = 0;
4482 ZERO_STRUCT(msg);
4483 msg.msg_name = &from_addr.sa; /* optional address */
4484 msg.msg_namelen = from_addr.sa_socklen; /* size of address */
4485 msg.msg_iov = omsg->msg_iov; /* scatter/gather array */
4486 msg.msg_iovlen = omsg->msg_iovlen; /* # elements in msg_iov */
4487 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4488 msg_ctrllen_filled = 0;
4489 msg_ctrllen_left = omsg->msg_controllen;
4491 msg.msg_control = omsg->msg_control; /* ancillary data, see below */
4492 msg.msg_controllen = omsg->msg_controllen; /* ancillary data buffer len */
4493 msg.msg_flags = omsg->msg_flags; /* flags on received message */
4494 #endif
4496 rc = swrap_recvmsg_before(s, si, &msg, &tmp);
4497 if (rc < 0) {
4498 return -1;
4501 ret = libc_recvmsg(s, &msg, flags);
4503 msg.msg_name = omsg->msg_name;
4504 msg.msg_namelen = omsg->msg_namelen;
4506 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4507 msg_ctrllen_filled += msg.msg_controllen;
4508 msg_ctrllen_left -= msg.msg_controllen;
4510 if (omsg->msg_control != NULL) {
4511 uint8_t *p;
4513 p = omsg->msg_control;
4514 p += msg_ctrllen_filled;
4516 msg.msg_control = p;
4517 msg.msg_controllen = msg_ctrllen_left;
4518 } else {
4519 msg.msg_control = NULL;
4520 msg.msg_controllen = 0;
4522 #endif
4524 rc = swrap_recvmsg_after(s,
4526 &msg,
4527 &from_addr.sa.un,
4528 from_addr.sa_socklen,
4529 ret);
4530 if (rc != 0) {
4531 return rc;
4534 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4535 if (omsg->msg_control != NULL) {
4536 /* msg.msg_controllen = space left */
4537 msg_ctrllen_left = msg.msg_controllen;
4538 msg_ctrllen_filled = omsg->msg_controllen - msg_ctrllen_left;
4541 /* Update the original message length */
4542 omsg->msg_controllen = msg_ctrllen_filled;
4543 omsg->msg_flags = msg.msg_flags;
4544 #endif
4545 omsg->msg_iovlen = msg.msg_iovlen;
4547 return ret;
4550 ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
4552 return swrap_recvmsg(sockfd, msg, flags);
4555 /****************************************************************************
4556 * SENDMSG
4557 ***************************************************************************/
4559 static ssize_t swrap_sendmsg(int s, const struct msghdr *omsg, int flags)
4561 struct msghdr msg;
4562 struct iovec tmp;
4563 struct sockaddr_un un_addr;
4564 const struct sockaddr_un *to_un = NULL;
4565 const struct sockaddr *to = NULL;
4566 ssize_t ret;
4567 int rc;
4568 struct socket_info *si = find_socket_info(s);
4569 int bcast = 0;
4571 if (!si) {
4572 return libc_sendmsg(s, omsg, flags);
4575 ZERO_STRUCT(un_addr);
4577 tmp.iov_base = NULL;
4578 tmp.iov_len = 0;
4580 ZERO_STRUCT(msg);
4581 msg.msg_name = omsg->msg_name; /* optional address */
4582 msg.msg_namelen = omsg->msg_namelen; /* size of address */
4583 msg.msg_iov = omsg->msg_iov; /* scatter/gather array */
4584 msg.msg_iovlen = omsg->msg_iovlen; /* # elements in msg_iov */
4585 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4586 if (msg.msg_controllen > 0 && msg.msg_control != NULL) {
4587 /* omsg is a const so use a local buffer for modifications */
4588 uint8_t cmbuf[omsg->msg_controllen];
4590 memcpy(cmbuf, omsg->msg_control, omsg->msg_controllen);
4592 msg.msg_control = cmbuf; /* ancillary data, see below */
4593 msg.msg_controllen = omsg->msg_controllen; /* ancillary data buffer len */
4595 msg.msg_flags = omsg->msg_flags; /* flags on received message */
4596 #endif
4598 rc = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, &to_un, &to, &bcast);
4599 if (rc < 0) {
4600 return -1;
4603 if (bcast) {
4604 struct stat st;
4605 unsigned int iface;
4606 unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
4607 char type;
4608 size_t i, len = 0;
4609 uint8_t *buf;
4610 off_t ofs = 0;
4611 size_t avail = 0;
4612 size_t remain;
4614 for (i = 0; i < (size_t)msg.msg_iovlen; i++) {
4615 avail += msg.msg_iov[i].iov_len;
4618 len = avail;
4619 remain = avail;
4621 /* we capture it as one single packet */
4622 buf = (uint8_t *)malloc(remain);
4623 if (!buf) {
4624 return -1;
4627 for (i = 0; i < (size_t)msg.msg_iovlen; i++) {
4628 size_t this_time = MIN(remain, (size_t)msg.msg_iov[i].iov_len);
4629 memcpy(buf + ofs,
4630 msg.msg_iov[i].iov_base,
4631 this_time);
4632 ofs += this_time;
4633 remain -= this_time;
4636 type = SOCKET_TYPE_CHAR_UDP;
4638 for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
4639 snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
4640 socket_wrapper_dir(), type, iface, prt);
4641 if (stat(un_addr.sun_path, &st) != 0) continue;
4643 msg.msg_name = &un_addr; /* optional address */
4644 msg.msg_namelen = sizeof(un_addr); /* size of address */
4646 /* ignore the any errors in broadcast sends */
4647 libc_sendmsg(s, &msg, flags);
4650 swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
4651 free(buf);
4653 return len;
4656 ret = libc_sendmsg(s, &msg, flags);
4658 swrap_sendmsg_after(s, si, &msg, to, ret);
4660 return ret;
4663 ssize_t sendmsg(int s, const struct msghdr *omsg, int flags)
4665 return swrap_sendmsg(s, omsg, flags);
4668 /****************************************************************************
4669 * READV
4670 ***************************************************************************/
4672 static ssize_t swrap_readv(int s, const struct iovec *vector, int count)
4674 struct socket_info *si;
4675 struct msghdr msg;
4676 struct iovec tmp;
4677 struct swrap_address saddr = {
4678 .sa_socklen = sizeof(struct sockaddr_storage)
4680 ssize_t ret;
4681 int rc;
4683 si = find_socket_info(s);
4684 if (si == NULL) {
4685 return libc_readv(s, vector, count);
4688 tmp.iov_base = NULL;
4689 tmp.iov_len = 0;
4691 ZERO_STRUCT(msg);
4692 msg.msg_name = &saddr.sa.s; /* optional address */
4693 msg.msg_namelen = saddr.sa_socklen; /* size of address */
4694 msg.msg_iov = discard_const_p(struct iovec, vector); /* scatter/gather array */
4695 msg.msg_iovlen = count; /* # elements in msg_iov */
4696 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4697 msg.msg_control = NULL; /* ancillary data, see below */
4698 msg.msg_controllen = 0; /* ancillary data buffer len */
4699 msg.msg_flags = 0; /* flags on received message */
4700 #endif
4702 rc = swrap_recvmsg_before(s, si, &msg, &tmp);
4703 if (rc < 0) {
4704 if (rc == -ENOTSOCK) {
4705 return libc_readv(s, vector, count);
4707 return -1;
4710 ret = libc_readv(s, msg.msg_iov, msg.msg_iovlen);
4712 rc = swrap_recvmsg_after(s, si, &msg, NULL, 0, ret);
4713 if (rc != 0) {
4714 return rc;
4717 return ret;
4720 ssize_t readv(int s, const struct iovec *vector, int count)
4722 return swrap_readv(s, vector, count);
4725 /****************************************************************************
4726 * WRITEV
4727 ***************************************************************************/
4729 static ssize_t swrap_writev(int s, const struct iovec *vector, int count)
4731 struct msghdr msg;
4732 struct iovec tmp;
4733 struct sockaddr_un un_addr;
4734 ssize_t ret;
4735 int rc;
4736 struct socket_info *si = find_socket_info(s);
4738 if (!si) {
4739 return libc_writev(s, vector, count);
4742 tmp.iov_base = NULL;
4743 tmp.iov_len = 0;
4745 ZERO_STRUCT(msg);
4746 msg.msg_name = NULL; /* optional address */
4747 msg.msg_namelen = 0; /* size of address */
4748 msg.msg_iov = discard_const_p(struct iovec, vector); /* scatter/gather array */
4749 msg.msg_iovlen = count; /* # elements in msg_iov */
4750 #if HAVE_STRUCT_MSGHDR_MSG_CONTROL
4751 msg.msg_control = NULL; /* ancillary data, see below */
4752 msg.msg_controllen = 0; /* ancillary data buffer len */
4753 msg.msg_flags = 0; /* flags on received message */
4754 #endif
4756 rc = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, NULL, NULL, NULL);
4757 if (rc < 0) {
4758 if (rc == -ENOTSOCK) {
4759 return libc_readv(s, vector, count);
4761 return -1;
4764 ret = libc_writev(s, msg.msg_iov, msg.msg_iovlen);
4766 swrap_sendmsg_after(s, si, &msg, NULL, ret);
4768 return ret;
4771 ssize_t writev(int s, const struct iovec *vector, int count)
4773 return swrap_writev(s, vector, count);
4776 /****************************
4777 * CLOSE
4778 ***************************/
4780 static int swrap_close(int fd)
4782 struct socket_info *si = find_socket_info(fd);
4783 struct socket_info_fd *fi;
4784 int ret;
4786 if (!si) {
4787 return libc_close(fd);
4790 for (fi = si->fds; fi; fi = fi->next) {
4791 if (fi->fd == fd) {
4792 SWRAP_DLIST_REMOVE(si->fds, fi);
4793 free(fi);
4794 break;
4798 if (si->fds) {
4799 /* there are still references left */
4800 return libc_close(fd);
4803 SWRAP_DLIST_REMOVE(sockets, si);
4805 if (si->myname.sa_socklen > 0 && si->peername.sa_socklen > 0) {
4806 swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_SEND, NULL, 0);
4809 ret = libc_close(fd);
4811 if (si->myname.sa_socklen > 0 && si->peername.sa_socklen > 0) {
4812 swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_RECV, NULL, 0);
4813 swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_ACK, NULL, 0);
4816 if (si->un_addr.sun_path[0] != '\0') {
4817 unlink(si->un_addr.sun_path);
4819 free(si);
4821 return ret;
4824 int close(int fd)
4826 return swrap_close(fd);
4829 /****************************
4830 * DUP
4831 ***************************/
4833 static int swrap_dup(int fd)
4835 struct socket_info *si;
4836 struct socket_info_fd *fi;
4838 si = find_socket_info(fd);
4840 if (!si) {
4841 return libc_dup(fd);
4844 fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
4845 if (fi == NULL) {
4846 errno = ENOMEM;
4847 return -1;
4850 fi->fd = libc_dup(fd);
4851 if (fi->fd == -1) {
4852 int saved_errno = errno;
4853 free(fi);
4854 errno = saved_errno;
4855 return -1;
4858 /* Make sure we don't have an entry for the fd */
4859 swrap_remove_stale(fi->fd);
4861 SWRAP_DLIST_ADD(si->fds, fi);
4862 return fi->fd;
4865 int dup(int fd)
4867 return swrap_dup(fd);
4870 /****************************
4871 * DUP2
4872 ***************************/
4874 static int swrap_dup2(int fd, int newfd)
4876 struct socket_info *si;
4877 struct socket_info_fd *fi;
4879 si = find_socket_info(fd);
4881 if (!si) {
4882 return libc_dup2(fd, newfd);
4885 if (find_socket_info(newfd)) {
4886 /* dup2() does an implicit close of newfd, which we
4887 * need to emulate */
4888 swrap_close(newfd);
4891 fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
4892 if (fi == NULL) {
4893 errno = ENOMEM;
4894 return -1;
4897 fi->fd = libc_dup2(fd, newfd);
4898 if (fi->fd == -1) {
4899 int saved_errno = errno;
4900 free(fi);
4901 errno = saved_errno;
4902 return -1;
4905 /* Make sure we don't have an entry for the fd */
4906 swrap_remove_stale(fi->fd);
4908 SWRAP_DLIST_ADD(si->fds, fi);
4909 return fi->fd;
4912 int dup2(int fd, int newfd)
4914 return swrap_dup2(fd, newfd);
4917 /****************************
4918 * DUP2
4919 ***************************/
4921 #ifdef HAVE_EVENTFD
4922 static int swrap_eventfd(int count, int flags)
4924 int fd;
4926 fd = libc_eventfd(count, flags);
4927 if (fd != -1) {
4928 swrap_remove_stale(fd);
4931 return fd;
4934 int eventfd(int count, int flags)
4936 return swrap_eventfd(count, flags);
4938 #endif
4940 /****************************
4941 * DESTRUCTOR
4942 ***************************/
4945 * This function is called when the library is unloaded and makes sure that
4946 * sockets get closed and the unix file for the socket are unlinked.
4948 void swrap_destructor(void)
4950 struct socket_info *s = sockets;
4952 while (s != NULL) {
4953 struct socket_info_fd *f = s->fds;
4954 if (f != NULL) {
4955 swrap_close(f->fd);
4957 s = sockets;