swrap: Fix type punning warnings when loading functions.
[Samba.git] / lib / socket_wrapper / socket_wrapper.c
blob88183c121bad1469d9db8eba0253e155b5524409
1 /*
2 * Copyright (c) 2005-2008 Jelmer Vernooij <jelmer@samba.org>
3 * Copyright (C) 2006-2014 Stefan Metzmacher <metze@samba.org>
4 * Copyright (C) 2013-2014 Andreas Schneider <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_cast_ptr = _swrap_load_lib_function(lib, #fn_name); \
524 *(void **) (&swrap.fns.libc_##fn_name) = \
525 swrap_cast_ptr; \
530 * IMPORTANT
532 * Functions especially from libc need to be loaded individually, you can't load
533 * all at once or gdb will segfault at startup. The same applies to valgrind and
534 * has probably something todo with with the linker.
535 * So we need load each function at the point it is called the first time.
537 static int libc_accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
539 swrap_load_lib_function(SWRAP_LIBSOCKET, accept);
541 return swrap.fns.libc_accept(sockfd, addr, addrlen);
544 static int libc_bind(int sockfd,
545 const struct sockaddr *addr,
546 socklen_t addrlen)
548 swrap_load_lib_function(SWRAP_LIBSOCKET, bind);
550 return swrap.fns.libc_bind(sockfd, addr, addrlen);
553 static int libc_close(int fd)
555 swrap_load_lib_function(SWRAP_LIBC, close);
557 return swrap.fns.libc_close(fd);
560 static int libc_connect(int sockfd,
561 const struct sockaddr *addr,
562 socklen_t addrlen)
564 swrap_load_lib_function(SWRAP_LIBSOCKET, connect);
566 return swrap.fns.libc_connect(sockfd, addr, addrlen);
569 static int libc_dup(int fd)
571 swrap_load_lib_function(SWRAP_LIBC, dup);
573 return swrap.fns.libc_dup(fd);
576 static int libc_dup2(int oldfd, int newfd)
578 swrap_load_lib_function(SWRAP_LIBC, dup2);
580 return swrap.fns.libc_dup2(oldfd, newfd);
583 #ifdef HAVE_EVENTFD
584 static int libc_eventfd(int count, int flags)
586 swrap_load_lib_function(SWRAP_LIBC, eventfd);
588 return swrap.fns.libc_eventfd(count, flags);
590 #endif
592 static int libc_getpeername(int sockfd,
593 struct sockaddr *addr,
594 socklen_t *addrlen)
596 swrap_load_lib_function(SWRAP_LIBSOCKET, getpeername);
598 return swrap.fns.libc_getpeername(sockfd, addr, addrlen);
601 static int libc_getsockname(int sockfd,
602 struct sockaddr *addr,
603 socklen_t *addrlen)
605 swrap_load_lib_function(SWRAP_LIBSOCKET, getsockname);
607 return swrap.fns.libc_getsockname(sockfd, addr, addrlen);
610 static int libc_getsockopt(int sockfd,
611 int level,
612 int optname,
613 void *optval,
614 socklen_t *optlen)
616 swrap_load_lib_function(SWRAP_LIBSOCKET, getsockopt);
618 return swrap.fns.libc_getsockopt(sockfd, level, optname, optval, optlen);
621 static int libc_vioctl(int d, unsigned long int request, va_list ap)
623 long int args[4];
624 int rc;
625 int i;
627 swrap_load_lib_function(SWRAP_LIBC, ioctl);
629 for (i = 0; i < 4; i++) {
630 args[i] = va_arg(ap, long int);
633 rc = swrap.fns.libc_ioctl(d,
634 request,
635 args[0],
636 args[1],
637 args[2],
638 args[3]);
640 return rc;
643 static int libc_listen(int sockfd, int backlog)
645 swrap_load_lib_function(SWRAP_LIBSOCKET, listen);
647 return swrap.fns.libc_listen(sockfd, backlog);
650 static FILE *libc_fopen(const char *name, const char *mode)
652 swrap_load_lib_function(SWRAP_LIBC, fopen);
654 return swrap.fns.libc_fopen(name, mode);
657 static int libc_vopen(const char *pathname, int flags, va_list ap)
659 long int mode = 0;
660 int fd;
662 swrap_load_lib_function(SWRAP_LIBC, open);
664 mode = va_arg(ap, long int);
666 fd = swrap.fns.libc_open(pathname, flags, (mode_t)mode);
668 return fd;
671 static int libc_open(const char *pathname, int flags, ...)
673 va_list ap;
674 int fd;
676 va_start(ap, flags);
677 fd = libc_vopen(pathname, flags, ap);
678 va_end(ap);
680 return fd;
683 static int libc_pipe(int pipefd[2])
685 swrap_load_lib_function(SWRAP_LIBSOCKET, pipe);
687 return swrap.fns.libc_pipe(pipefd);
690 static int libc_read(int fd, void *buf, size_t count)
692 swrap_load_lib_function(SWRAP_LIBC, read);
694 return swrap.fns.libc_read(fd, buf, count);
697 static ssize_t libc_readv(int fd, const struct iovec *iov, int iovcnt)
699 swrap_load_lib_function(SWRAP_LIBSOCKET, readv);
701 return swrap.fns.libc_readv(fd, iov, iovcnt);
704 static int libc_recv(int sockfd, void *buf, size_t len, int flags)
706 swrap_load_lib_function(SWRAP_LIBSOCKET, recv);
708 return swrap.fns.libc_recv(sockfd, buf, len, flags);
711 static int libc_recvfrom(int sockfd,
712 void *buf,
713 size_t len,
714 int flags,
715 struct sockaddr *src_addr,
716 socklen_t *addrlen)
718 swrap_load_lib_function(SWRAP_LIBSOCKET, recvfrom);
720 return swrap.fns.libc_recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
723 static int libc_recvmsg(int sockfd, struct msghdr *msg, int flags)
725 swrap_load_lib_function(SWRAP_LIBSOCKET, recvmsg);
727 return swrap.fns.libc_recvmsg(sockfd, msg, flags);
730 static int libc_send(int sockfd, const void *buf, size_t len, int flags)
732 swrap_load_lib_function(SWRAP_LIBSOCKET, send);
734 return swrap.fns.libc_send(sockfd, buf, len, flags);
737 static int libc_sendmsg(int sockfd, const struct msghdr *msg, int flags)
739 swrap_load_lib_function(SWRAP_LIBSOCKET, sendmsg);
741 return swrap.fns.libc_sendmsg(sockfd, msg, flags);
744 static int libc_sendto(int sockfd,
745 const void *buf,
746 size_t len,
747 int flags,
748 const struct sockaddr *dst_addr,
749 socklen_t addrlen)
751 swrap_load_lib_function(SWRAP_LIBSOCKET, sendto);
753 return swrap.fns.libc_sendto(sockfd, buf, len, flags, dst_addr, addrlen);
756 static int libc_setsockopt(int sockfd,
757 int level,
758 int optname,
759 const void *optval,
760 socklen_t optlen)
762 swrap_load_lib_function(SWRAP_LIBSOCKET, setsockopt);
764 return swrap.fns.libc_setsockopt(sockfd, level, optname, optval, optlen);
767 #ifdef HAVE_SIGNALFD
768 static int libc_signalfd(int fd, const sigset_t *mask, int flags)
770 swrap_load_lib_function(SWRAP_LIBSOCKET, signalfd);
772 return swrap.fns.libc_signalfd(fd, mask, flags);
774 #endif
776 static int libc_socket(int domain, int type, int protocol)
778 swrap_load_lib_function(SWRAP_LIBSOCKET, socket);
780 return swrap.fns.libc_socket(domain, type, protocol);
783 static int libc_socketpair(int domain, int type, int protocol, int sv[2])
785 swrap_load_lib_function(SWRAP_LIBSOCKET, socketpair);
787 return swrap.fns.libc_socketpair(domain, type, protocol, sv);
790 #ifdef HAVE_TIMERFD_CREATE
791 static int libc_timerfd_create(int clockid, int flags)
793 swrap_load_lib_function(SWRAP_LIBC, timerfd_create);
795 return swrap.fns.libc_timerfd_create(clockid, flags);
797 #endif
799 static ssize_t libc_writev(int fd, const struct iovec *iov, int iovcnt)
801 swrap_load_lib_function(SWRAP_LIBSOCKET, writev);
803 return swrap.fns.libc_writev(fd, iov, iovcnt);
806 /*********************************************************
807 * SWRAP HELPER FUNCTIONS
808 *********************************************************/
810 #ifdef HAVE_IPV6
812 * FD00::5357:5FXX
814 static const struct in6_addr *swrap_ipv6(void)
816 static struct in6_addr v;
817 static int initialized;
818 int ret;
820 if (initialized) {
821 return &v;
823 initialized = 1;
825 ret = inet_pton(AF_INET6, "FD00::5357:5F00", &v);
826 if (ret <= 0) {
827 abort();
830 return &v;
832 #endif
834 static void set_port(int family, int prt, struct swrap_address *addr)
836 switch (family) {
837 case AF_INET:
838 addr->sa.in.sin_port = htons(prt);
839 break;
840 #ifdef HAVE_IPV6
841 case AF_INET6:
842 addr->sa.in6.sin6_port = htons(prt);
843 break;
844 #endif
848 static size_t socket_length(int family)
850 switch (family) {
851 case AF_INET:
852 return sizeof(struct sockaddr_in);
853 #ifdef HAVE_IPV6
854 case AF_INET6:
855 return sizeof(struct sockaddr_in6);
856 #endif
858 return 0;
861 static const char *socket_wrapper_dir(void)
863 const char *s = getenv("SOCKET_WRAPPER_DIR");
864 if (s == NULL) {
865 return NULL;
867 /* TODO use realpath(3) here, when we add support for threads */
868 if (strncmp(s, "./", 2) == 0) {
869 s += 2;
872 SWRAP_LOG(SWRAP_LOG_TRACE, "socket_wrapper_dir: %s", s);
873 return s;
876 bool socket_wrapper_enabled(void)
878 const char *s = socket_wrapper_dir();
880 return s != NULL ? true : false;
883 static unsigned int socket_wrapper_default_iface(void)
885 const char *s = getenv("SOCKET_WRAPPER_DEFAULT_IFACE");
886 if (s) {
887 unsigned int iface;
888 if (sscanf(s, "%u", &iface) == 1) {
889 if (iface >= 1 && iface <= MAX_WRAPPED_INTERFACES) {
890 return iface;
895 return 1;/* 127.0.0.1 */
898 static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, socklen_t *len)
900 unsigned int iface;
901 unsigned int prt;
902 const char *p;
903 char type;
905 p = strrchr(un->sun_path, '/');
906 if (p) p++; else p = un->sun_path;
908 if (sscanf(p, SOCKET_FORMAT, &type, &iface, &prt) != 3) {
909 errno = EINVAL;
910 return -1;
913 SWRAP_LOG(SWRAP_LOG_TRACE, "type %c iface %u port %u",
914 type, iface, prt);
916 if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) {
917 errno = EINVAL;
918 return -1;
921 if (prt > 0xFFFF) {
922 errno = EINVAL;
923 return -1;
926 switch(type) {
927 case SOCKET_TYPE_CHAR_TCP:
928 case SOCKET_TYPE_CHAR_UDP: {
929 struct sockaddr_in *in2 = (struct sockaddr_in *)(void *)in;
931 if ((*len) < sizeof(*in2)) {
932 errno = EINVAL;
933 return -1;
936 memset(in2, 0, sizeof(*in2));
937 in2->sin_family = AF_INET;
938 in2->sin_addr.s_addr = htonl((127<<24) | iface);
939 in2->sin_port = htons(prt);
941 *len = sizeof(*in2);
942 break;
944 #ifdef HAVE_IPV6
945 case SOCKET_TYPE_CHAR_TCP_V6:
946 case SOCKET_TYPE_CHAR_UDP_V6: {
947 struct sockaddr_in6 *in2 = (struct sockaddr_in6 *)(void *)in;
949 if ((*len) < sizeof(*in2)) {
950 errno = EINVAL;
951 return -1;
954 memset(in2, 0, sizeof(*in2));
955 in2->sin6_family = AF_INET6;
956 in2->sin6_addr = *swrap_ipv6();
957 in2->sin6_addr.s6_addr[15] = iface;
958 in2->sin6_port = htons(prt);
960 *len = sizeof(*in2);
961 break;
963 #endif
964 default:
965 errno = EINVAL;
966 return -1;
969 return 0;
972 static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un,
973 int *bcast)
975 char type = '\0';
976 unsigned int prt;
977 unsigned int iface;
978 int is_bcast = 0;
980 if (bcast) *bcast = 0;
982 switch (inaddr->sa_family) {
983 case AF_INET: {
984 const struct sockaddr_in *in =
985 (const struct sockaddr_in *)(const void *)inaddr;
986 unsigned int addr = ntohl(in->sin_addr.s_addr);
987 char u_type = '\0';
988 char b_type = '\0';
989 char a_type = '\0';
991 switch (si->type) {
992 case SOCK_STREAM:
993 u_type = SOCKET_TYPE_CHAR_TCP;
994 break;
995 case SOCK_DGRAM:
996 u_type = SOCKET_TYPE_CHAR_UDP;
997 a_type = SOCKET_TYPE_CHAR_UDP;
998 b_type = SOCKET_TYPE_CHAR_UDP;
999 break;
1000 default:
1001 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n");
1002 errno = ESOCKTNOSUPPORT;
1003 return -1;
1006 prt = ntohs(in->sin_port);
1007 if (a_type && addr == 0xFFFFFFFF) {
1008 /* 255.255.255.255 only udp */
1009 is_bcast = 2;
1010 type = a_type;
1011 iface = socket_wrapper_default_iface();
1012 } else if (b_type && addr == 0x7FFFFFFF) {
1013 /* 127.255.255.255 only udp */
1014 is_bcast = 1;
1015 type = b_type;
1016 iface = socket_wrapper_default_iface();
1017 } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
1018 /* 127.0.0.X */
1019 is_bcast = 0;
1020 type = u_type;
1021 iface = (addr & 0x000000FF);
1022 } else {
1023 errno = ENETUNREACH;
1024 return -1;
1026 if (bcast) *bcast = is_bcast;
1027 break;
1029 #ifdef HAVE_IPV6
1030 case AF_INET6: {
1031 const struct sockaddr_in6 *in =
1032 (const struct sockaddr_in6 *)(const void *)inaddr;
1033 struct in6_addr cmp1, cmp2;
1035 switch (si->type) {
1036 case SOCK_STREAM:
1037 type = SOCKET_TYPE_CHAR_TCP_V6;
1038 break;
1039 case SOCK_DGRAM:
1040 type = SOCKET_TYPE_CHAR_UDP_V6;
1041 break;
1042 default:
1043 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n");
1044 errno = ESOCKTNOSUPPORT;
1045 return -1;
1048 /* XXX no multicast/broadcast */
1050 prt = ntohs(in->sin6_port);
1052 cmp1 = *swrap_ipv6();
1053 cmp2 = in->sin6_addr;
1054 cmp2.s6_addr[15] = 0;
1055 if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) {
1056 iface = in->sin6_addr.s6_addr[15];
1057 } else {
1058 errno = ENETUNREACH;
1059 return -1;
1062 break;
1064 #endif
1065 default:
1066 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown address family!\n");
1067 errno = ENETUNREACH;
1068 return -1;
1071 if (prt == 0) {
1072 SWRAP_LOG(SWRAP_LOG_WARN, "Port not set\n");
1073 errno = EINVAL;
1074 return -1;
1077 if (is_bcast) {
1078 snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL",
1079 socket_wrapper_dir());
1080 SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
1081 /* the caller need to do more processing */
1082 return 0;
1085 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
1086 socket_wrapper_dir(), type, iface, prt);
1087 SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
1089 return 0;
1092 static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un,
1093 int *bcast)
1095 char type = '\0';
1096 unsigned int prt;
1097 unsigned int iface;
1098 struct stat st;
1099 int is_bcast = 0;
1101 if (bcast) *bcast = 0;
1103 switch (si->family) {
1104 case AF_INET: {
1105 const struct sockaddr_in *in =
1106 (const struct sockaddr_in *)(const void *)inaddr;
1107 unsigned int addr = ntohl(in->sin_addr.s_addr);
1108 char u_type = '\0';
1109 char d_type = '\0';
1110 char b_type = '\0';
1111 char a_type = '\0';
1113 prt = ntohs(in->sin_port);
1115 switch (si->type) {
1116 case SOCK_STREAM:
1117 u_type = SOCKET_TYPE_CHAR_TCP;
1118 d_type = SOCKET_TYPE_CHAR_TCP;
1119 break;
1120 case SOCK_DGRAM:
1121 u_type = SOCKET_TYPE_CHAR_UDP;
1122 d_type = SOCKET_TYPE_CHAR_UDP;
1123 a_type = SOCKET_TYPE_CHAR_UDP;
1124 b_type = SOCKET_TYPE_CHAR_UDP;
1125 break;
1126 default:
1127 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n");
1128 errno = ESOCKTNOSUPPORT;
1129 return -1;
1132 if (addr == 0) {
1133 /* 0.0.0.0 */
1134 is_bcast = 0;
1135 type = d_type;
1136 iface = socket_wrapper_default_iface();
1137 } else if (a_type && addr == 0xFFFFFFFF) {
1138 /* 255.255.255.255 only udp */
1139 is_bcast = 2;
1140 type = a_type;
1141 iface = socket_wrapper_default_iface();
1142 } else if (b_type && addr == 0x7FFFFFFF) {
1143 /* 127.255.255.255 only udp */
1144 is_bcast = 1;
1145 type = b_type;
1146 iface = socket_wrapper_default_iface();
1147 } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
1148 /* 127.0.0.X */
1149 is_bcast = 0;
1150 type = u_type;
1151 iface = (addr & 0x000000FF);
1152 } else {
1153 errno = EADDRNOTAVAIL;
1154 return -1;
1157 /* Store the bind address for connect() */
1158 if (si->bindname.sa_socklen == 0) {
1159 struct sockaddr_in bind_in;
1160 socklen_t blen = sizeof(struct sockaddr_in);
1162 ZERO_STRUCT(bind_in);
1163 bind_in.sin_family = in->sin_family;
1164 bind_in.sin_port = in->sin_port;
1165 bind_in.sin_addr.s_addr = htonl(0x7F000000 | iface);
1167 si->bindname.sa_socklen = blen;
1168 memcpy(&si->bindname.sa.in, &bind_in, blen);
1171 break;
1173 #ifdef HAVE_IPV6
1174 case AF_INET6: {
1175 const struct sockaddr_in6 *in =
1176 (const struct sockaddr_in6 *)(const void *)inaddr;
1177 struct in6_addr cmp1, cmp2;
1179 switch (si->type) {
1180 case SOCK_STREAM:
1181 type = SOCKET_TYPE_CHAR_TCP_V6;
1182 break;
1183 case SOCK_DGRAM:
1184 type = SOCKET_TYPE_CHAR_UDP_V6;
1185 break;
1186 default:
1187 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n");
1188 errno = ESOCKTNOSUPPORT;
1189 return -1;
1192 /* XXX no multicast/broadcast */
1194 prt = ntohs(in->sin6_port);
1196 cmp1 = *swrap_ipv6();
1197 cmp2 = in->sin6_addr;
1198 cmp2.s6_addr[15] = 0;
1199 if (IN6_IS_ADDR_UNSPECIFIED(&in->sin6_addr)) {
1200 iface = socket_wrapper_default_iface();
1201 } else if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) {
1202 iface = in->sin6_addr.s6_addr[15];
1203 } else {
1204 errno = EADDRNOTAVAIL;
1205 return -1;
1208 /* Store the bind address for connect() */
1209 if (si->bindname.sa_socklen == 0) {
1210 struct sockaddr_in6 bind_in;
1211 socklen_t blen = sizeof(struct sockaddr_in6);
1213 ZERO_STRUCT(bind_in);
1214 bind_in.sin6_family = in->sin6_family;
1215 bind_in.sin6_port = in->sin6_port;
1217 bind_in.sin6_addr = *swrap_ipv6();
1218 bind_in.sin6_addr.s6_addr[15] = iface;
1220 memcpy(&si->bindname.sa.in6, &bind_in, blen);
1221 si->bindname.sa_socklen = blen;
1224 break;
1226 #endif
1227 default:
1228 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown address family\n");
1229 errno = EADDRNOTAVAIL;
1230 return -1;
1234 if (bcast) *bcast = is_bcast;
1236 if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) {
1237 errno = EINVAL;
1238 return -1;
1241 if (prt == 0) {
1242 /* handle auto-allocation of ephemeral ports */
1243 for (prt = 5001; prt < 10000; prt++) {
1244 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
1245 socket_wrapper_dir(), type, iface, prt);
1246 if (stat(un->sun_path, &st) == 0) continue;
1248 set_port(si->family, prt, &si->myname);
1249 set_port(si->family, prt, &si->bindname);
1251 break;
1253 if (prt == 10000) {
1254 errno = ENFILE;
1255 return -1;
1259 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
1260 socket_wrapper_dir(), type, iface, prt);
1261 SWRAP_LOG(SWRAP_LOG_DEBUG, "un path [%s]", un->sun_path);
1262 return 0;
1265 static struct socket_info *find_socket_info(int fd)
1267 struct socket_info *i;
1269 for (i = sockets; i; i = i->next) {
1270 struct socket_info_fd *f;
1271 for (f = i->fds; f; f = f->next) {
1272 if (f->fd == fd) {
1273 return i;
1278 return NULL;
1281 #if 0 /* FIXME */
1282 static bool check_addr_port_in_use(const struct sockaddr *sa, socklen_t len)
1284 struct socket_info *s;
1286 /* first catch invalid input */
1287 switch (sa->sa_family) {
1288 case AF_INET:
1289 if (len < sizeof(struct sockaddr_in)) {
1290 return false;
1292 break;
1293 #if HAVE_IPV6
1294 case AF_INET6:
1295 if (len < sizeof(struct sockaddr_in6)) {
1296 return false;
1298 break;
1299 #endif
1300 default:
1301 return false;
1302 break;
1305 for (s = sockets; s != NULL; s = s->next) {
1306 if (s->myname == NULL) {
1307 continue;
1309 if (s->myname->sa_family != sa->sa_family) {
1310 continue;
1312 switch (s->myname->sa_family) {
1313 case AF_INET: {
1314 struct sockaddr_in *sin1, *sin2;
1316 sin1 = (struct sockaddr_in *)s->myname;
1317 sin2 = (struct sockaddr_in *)sa;
1319 if (sin1->sin_addr.s_addr == htonl(INADDR_ANY)) {
1320 continue;
1322 if (sin1->sin_port != sin2->sin_port) {
1323 continue;
1325 if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) {
1326 continue;
1329 /* found */
1330 return true;
1331 break;
1333 #if HAVE_IPV6
1334 case AF_INET6: {
1335 struct sockaddr_in6 *sin1, *sin2;
1337 sin1 = (struct sockaddr_in6 *)s->myname;
1338 sin2 = (struct sockaddr_in6 *)sa;
1340 if (sin1->sin6_port != sin2->sin6_port) {
1341 continue;
1343 if (!IN6_ARE_ADDR_EQUAL(&sin1->sin6_addr,
1344 &sin2->sin6_addr))
1346 continue;
1349 /* found */
1350 return true;
1351 break;
1353 #endif
1354 default:
1355 continue;
1356 break;
1361 return false;
1363 #endif
1365 static void swrap_remove_stale(int fd)
1367 struct socket_info *si = find_socket_info(fd);
1368 struct socket_info_fd *fi;
1370 if (si != NULL) {
1371 for (fi = si->fds; fi; fi = fi->next) {
1372 if (fi->fd == fd) {
1373 SWRAP_LOG(SWRAP_LOG_TRACE, "remove stale wrapper for %d", fd);
1374 SWRAP_DLIST_REMOVE(si->fds, fi);
1375 free(fi);
1376 break;
1380 if (si->fds == NULL) {
1381 SWRAP_DLIST_REMOVE(sockets, si);
1386 static int sockaddr_convert_to_un(struct socket_info *si,
1387 const struct sockaddr *in_addr,
1388 socklen_t in_len,
1389 struct sockaddr_un *out_addr,
1390 int alloc_sock,
1391 int *bcast)
1393 struct sockaddr *out = (struct sockaddr *)(void *)out_addr;
1395 (void) in_len; /* unused */
1397 if (out_addr == NULL) {
1398 return 0;
1401 out->sa_family = AF_UNIX;
1402 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1403 out->sa_len = sizeof(*out_addr);
1404 #endif
1406 switch (in_addr->sa_family) {
1407 case AF_UNSPEC: {
1408 const struct sockaddr_in *sin;
1409 if (si->family != AF_INET) {
1410 break;
1412 if (in_len < sizeof(struct sockaddr_in)) {
1413 break;
1415 sin = (const struct sockaddr_in *)in_addr;
1416 if(sin->sin_addr.s_addr != htonl(INADDR_ANY)) {
1417 break;
1421 * Note: in the special case of AF_UNSPEC and INADDR_ANY,
1422 * AF_UNSPEC is mapped to AF_INET and must be treated here.
1425 /* FALL THROUGH */
1427 case AF_INET:
1428 #ifdef HAVE_IPV6
1429 case AF_INET6:
1430 #endif
1431 switch (si->type) {
1432 case SOCK_STREAM:
1433 case SOCK_DGRAM:
1434 break;
1435 default:
1436 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n");
1437 errno = ESOCKTNOSUPPORT;
1438 return -1;
1440 if (alloc_sock) {
1441 return convert_in_un_alloc(si, in_addr, out_addr, bcast);
1442 } else {
1443 return convert_in_un_remote(si, in_addr, out_addr, bcast);
1445 default:
1446 break;
1449 errno = EAFNOSUPPORT;
1450 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown address family\n");
1451 return -1;
1454 static int sockaddr_convert_from_un(const struct socket_info *si,
1455 const struct sockaddr_un *in_addr,
1456 socklen_t un_addrlen,
1457 int family,
1458 struct sockaddr *out_addr,
1459 socklen_t *out_addrlen)
1461 int ret;
1463 if (out_addr == NULL || out_addrlen == NULL)
1464 return 0;
1466 if (un_addrlen == 0) {
1467 *out_addrlen = 0;
1468 return 0;
1471 switch (family) {
1472 case AF_INET:
1473 #ifdef HAVE_IPV6
1474 case AF_INET6:
1475 #endif
1476 switch (si->type) {
1477 case SOCK_STREAM:
1478 case SOCK_DGRAM:
1479 break;
1480 default:
1481 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown socket type!\n");
1482 errno = ESOCKTNOSUPPORT;
1483 return -1;
1485 ret = convert_un_in(in_addr, out_addr, out_addrlen);
1486 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1487 out_addr->sa_len = *out_addrlen;
1488 #endif
1489 return ret;
1490 default:
1491 break;
1494 SWRAP_LOG(SWRAP_LOG_ERROR, "Unknown address family\n");
1495 errno = EAFNOSUPPORT;
1496 return -1;
1499 enum swrap_packet_type {
1500 SWRAP_CONNECT_SEND,
1501 SWRAP_CONNECT_UNREACH,
1502 SWRAP_CONNECT_RECV,
1503 SWRAP_CONNECT_ACK,
1504 SWRAP_ACCEPT_SEND,
1505 SWRAP_ACCEPT_RECV,
1506 SWRAP_ACCEPT_ACK,
1507 SWRAP_RECVFROM,
1508 SWRAP_SENDTO,
1509 SWRAP_SENDTO_UNREACH,
1510 SWRAP_PENDING_RST,
1511 SWRAP_RECV,
1512 SWRAP_RECV_RST,
1513 SWRAP_SEND,
1514 SWRAP_SEND_RST,
1515 SWRAP_CLOSE_SEND,
1516 SWRAP_CLOSE_RECV,
1517 SWRAP_CLOSE_ACK,
1520 struct swrap_file_hdr {
1521 uint32_t magic;
1522 uint16_t version_major;
1523 uint16_t version_minor;
1524 int32_t timezone;
1525 uint32_t sigfigs;
1526 uint32_t frame_max_len;
1527 #define SWRAP_FRAME_LENGTH_MAX 0xFFFF
1528 uint32_t link_type;
1530 #define SWRAP_FILE_HDR_SIZE 24
1532 struct swrap_packet_frame {
1533 uint32_t seconds;
1534 uint32_t micro_seconds;
1535 uint32_t recorded_length;
1536 uint32_t full_length;
1538 #define SWRAP_PACKET_FRAME_SIZE 16
1540 union swrap_packet_ip {
1541 struct {
1542 uint8_t ver_hdrlen;
1543 uint8_t tos;
1544 uint16_t packet_length;
1545 uint16_t identification;
1546 uint8_t flags;
1547 uint8_t fragment;
1548 uint8_t ttl;
1549 uint8_t protocol;
1550 uint16_t hdr_checksum;
1551 uint32_t src_addr;
1552 uint32_t dest_addr;
1553 } v4;
1554 #define SWRAP_PACKET_IP_V4_SIZE 20
1555 struct {
1556 uint8_t ver_prio;
1557 uint8_t flow_label_high;
1558 uint16_t flow_label_low;
1559 uint16_t payload_length;
1560 uint8_t next_header;
1561 uint8_t hop_limit;
1562 uint8_t src_addr[16];
1563 uint8_t dest_addr[16];
1564 } v6;
1565 #define SWRAP_PACKET_IP_V6_SIZE 40
1567 #define SWRAP_PACKET_IP_SIZE 40
1569 union swrap_packet_payload {
1570 struct {
1571 uint16_t source_port;
1572 uint16_t dest_port;
1573 uint32_t seq_num;
1574 uint32_t ack_num;
1575 uint8_t hdr_length;
1576 uint8_t control;
1577 uint16_t window;
1578 uint16_t checksum;
1579 uint16_t urg;
1580 } tcp;
1581 #define SWRAP_PACKET_PAYLOAD_TCP_SIZE 20
1582 struct {
1583 uint16_t source_port;
1584 uint16_t dest_port;
1585 uint16_t length;
1586 uint16_t checksum;
1587 } udp;
1588 #define SWRAP_PACKET_PAYLOAD_UDP_SIZE 8
1589 struct {
1590 uint8_t type;
1591 uint8_t code;
1592 uint16_t checksum;
1593 uint32_t unused;
1594 } icmp4;
1595 #define SWRAP_PACKET_PAYLOAD_ICMP4_SIZE 8
1596 struct {
1597 uint8_t type;
1598 uint8_t code;
1599 uint16_t checksum;
1600 uint32_t unused;
1601 } icmp6;
1602 #define SWRAP_PACKET_PAYLOAD_ICMP6_SIZE 8
1604 #define SWRAP_PACKET_PAYLOAD_SIZE 20
1606 #define SWRAP_PACKET_MIN_ALLOC \
1607 (SWRAP_PACKET_FRAME_SIZE + \
1608 SWRAP_PACKET_IP_SIZE + \
1609 SWRAP_PACKET_PAYLOAD_SIZE)
1611 static const char *swrap_pcap_init_file(void)
1613 static int initialized = 0;
1614 static const char *s = NULL;
1615 static const struct swrap_file_hdr h;
1616 static const struct swrap_packet_frame f;
1617 static const union swrap_packet_ip i;
1618 static const union swrap_packet_payload p;
1620 if (initialized == 1) {
1621 return s;
1623 initialized = 1;
1626 * TODO: don't use the structs use plain buffer offsets
1627 * and PUSH_U8(), PUSH_U16() and PUSH_U32()
1629 * for now make sure we disable PCAP support
1630 * if the struct has alignment!
1632 if (sizeof(h) != SWRAP_FILE_HDR_SIZE) {
1633 return NULL;
1635 if (sizeof(f) != SWRAP_PACKET_FRAME_SIZE) {
1636 return NULL;
1638 if (sizeof(i) != SWRAP_PACKET_IP_SIZE) {
1639 return NULL;
1641 if (sizeof(i.v4) != SWRAP_PACKET_IP_V4_SIZE) {
1642 return NULL;
1644 if (sizeof(i.v6) != SWRAP_PACKET_IP_V6_SIZE) {
1645 return NULL;
1647 if (sizeof(p) != SWRAP_PACKET_PAYLOAD_SIZE) {
1648 return NULL;
1650 if (sizeof(p.tcp) != SWRAP_PACKET_PAYLOAD_TCP_SIZE) {
1651 return NULL;
1653 if (sizeof(p.udp) != SWRAP_PACKET_PAYLOAD_UDP_SIZE) {
1654 return NULL;
1656 if (sizeof(p.icmp4) != SWRAP_PACKET_PAYLOAD_ICMP4_SIZE) {
1657 return NULL;
1659 if (sizeof(p.icmp6) != SWRAP_PACKET_PAYLOAD_ICMP6_SIZE) {
1660 return NULL;
1663 s = getenv("SOCKET_WRAPPER_PCAP_FILE");
1664 if (s == NULL) {
1665 return NULL;
1667 if (strncmp(s, "./", 2) == 0) {
1668 s += 2;
1670 return s;
1673 static uint8_t *swrap_pcap_packet_init(struct timeval *tval,
1674 const struct sockaddr *src,
1675 const struct sockaddr *dest,
1676 int socket_type,
1677 const uint8_t *payload,
1678 size_t payload_len,
1679 unsigned long tcp_seqno,
1680 unsigned long tcp_ack,
1681 unsigned char tcp_ctl,
1682 int unreachable,
1683 size_t *_packet_len)
1685 uint8_t *base;
1686 uint8_t *buf;
1687 struct swrap_packet_frame *frame;
1688 union swrap_packet_ip *ip;
1689 union swrap_packet_payload *pay;
1690 size_t packet_len;
1691 size_t alloc_len;
1692 size_t nonwire_len = sizeof(*frame);
1693 size_t wire_hdr_len = 0;
1694 size_t wire_len = 0;
1695 size_t ip_hdr_len = 0;
1696 size_t icmp_hdr_len = 0;
1697 size_t icmp_truncate_len = 0;
1698 uint8_t protocol = 0, icmp_protocol = 0;
1699 const struct sockaddr_in *src_in = NULL;
1700 const struct sockaddr_in *dest_in = NULL;
1701 #ifdef HAVE_IPV6
1702 const struct sockaddr_in6 *src_in6 = NULL;
1703 const struct sockaddr_in6 *dest_in6 = NULL;
1704 #endif
1705 uint16_t src_port;
1706 uint16_t dest_port;
1708 switch (src->sa_family) {
1709 case AF_INET:
1710 src_in = (const struct sockaddr_in *)src;
1711 dest_in = (const struct sockaddr_in *)dest;
1712 src_port = src_in->sin_port;
1713 dest_port = dest_in->sin_port;
1714 ip_hdr_len = sizeof(ip->v4);
1715 break;
1716 #ifdef HAVE_IPV6
1717 case AF_INET6:
1718 src_in6 = (const struct sockaddr_in6 *)src;
1719 dest_in6 = (const struct sockaddr_in6 *)dest;
1720 src_port = src_in6->sin6_port;
1721 dest_port = dest_in6->sin6_port;
1722 ip_hdr_len = sizeof(ip->v6);
1723 break;
1724 #endif
1725 default:
1726 return NULL;
1729 switch (socket_type) {
1730 case SOCK_STREAM:
1731 protocol = 0x06; /* TCP */
1732 wire_hdr_len = ip_hdr_len + sizeof(pay->tcp);
1733 wire_len = wire_hdr_len + payload_len;
1734 break;
1736 case SOCK_DGRAM:
1737 protocol = 0x11; /* UDP */
1738 wire_hdr_len = ip_hdr_len + sizeof(pay->udp);
1739 wire_len = wire_hdr_len + payload_len;
1740 break;
1742 default:
1743 return NULL;
1746 if (unreachable) {
1747 icmp_protocol = protocol;
1748 switch (src->sa_family) {
1749 case AF_INET:
1750 protocol = 0x01; /* ICMPv4 */
1751 icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp4);
1752 break;
1753 #ifdef HAVE_IPV6
1754 case AF_INET6:
1755 protocol = 0x3A; /* ICMPv6 */
1756 icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp6);
1757 break;
1758 #endif
1760 if (wire_len > 64 ) {
1761 icmp_truncate_len = wire_len - 64;
1763 wire_hdr_len += icmp_hdr_len;
1764 wire_len += icmp_hdr_len;
1767 packet_len = nonwire_len + wire_len;
1768 alloc_len = packet_len;
1769 if (alloc_len < SWRAP_PACKET_MIN_ALLOC) {
1770 alloc_len = SWRAP_PACKET_MIN_ALLOC;
1773 base = (uint8_t *)malloc(alloc_len);
1774 if (base == NULL) {
1775 return NULL;
1777 memset(base, 0x0, alloc_len);
1779 buf = base;
1781 frame = (struct swrap_packet_frame *)buf;
1782 frame->seconds = tval->tv_sec;
1783 frame->micro_seconds = tval->tv_usec;
1784 frame->recorded_length = wire_len - icmp_truncate_len;
1785 frame->full_length = wire_len - icmp_truncate_len;
1786 buf += SWRAP_PACKET_FRAME_SIZE;
1788 ip = (union swrap_packet_ip *)buf;
1789 switch (src->sa_family) {
1790 case AF_INET:
1791 ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
1792 ip->v4.tos = 0x00;
1793 ip->v4.packet_length = htons(wire_len - icmp_truncate_len);
1794 ip->v4.identification = htons(0xFFFF);
1795 ip->v4.flags = 0x40; /* BIT 1 set - means don't fragment */
1796 ip->v4.fragment = htons(0x0000);
1797 ip->v4.ttl = 0xFF;
1798 ip->v4.protocol = protocol;
1799 ip->v4.hdr_checksum = htons(0x0000);
1800 ip->v4.src_addr = src_in->sin_addr.s_addr;
1801 ip->v4.dest_addr = dest_in->sin_addr.s_addr;
1802 buf += SWRAP_PACKET_IP_V4_SIZE;
1803 break;
1804 #ifdef HAVE_IPV6
1805 case AF_INET6:
1806 ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */
1807 ip->v6.flow_label_high = 0x00;
1808 ip->v6.flow_label_low = 0x0000;
1809 ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */
1810 ip->v6.next_header = protocol;
1811 memcpy(ip->v6.src_addr, src_in6->sin6_addr.s6_addr, 16);
1812 memcpy(ip->v6.dest_addr, dest_in6->sin6_addr.s6_addr, 16);
1813 buf += SWRAP_PACKET_IP_V6_SIZE;
1814 break;
1815 #endif
1818 if (unreachable) {
1819 pay = (union swrap_packet_payload *)buf;
1820 switch (src->sa_family) {
1821 case AF_INET:
1822 pay->icmp4.type = 0x03; /* destination unreachable */
1823 pay->icmp4.code = 0x01; /* host unreachable */
1824 pay->icmp4.checksum = htons(0x0000);
1825 pay->icmp4.unused = htonl(0x00000000);
1826 buf += SWRAP_PACKET_PAYLOAD_ICMP4_SIZE;
1828 /* set the ip header in the ICMP payload */
1829 ip = (union swrap_packet_ip *)buf;
1830 ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
1831 ip->v4.tos = 0x00;
1832 ip->v4.packet_length = htons(wire_len - icmp_hdr_len);
1833 ip->v4.identification = htons(0xFFFF);
1834 ip->v4.flags = 0x40; /* BIT 1 set - means don't fragment */
1835 ip->v4.fragment = htons(0x0000);
1836 ip->v4.ttl = 0xFF;
1837 ip->v4.protocol = icmp_protocol;
1838 ip->v4.hdr_checksum = htons(0x0000);
1839 ip->v4.src_addr = dest_in->sin_addr.s_addr;
1840 ip->v4.dest_addr = src_in->sin_addr.s_addr;
1841 buf += SWRAP_PACKET_IP_V4_SIZE;
1843 src_port = dest_in->sin_port;
1844 dest_port = src_in->sin_port;
1845 break;
1846 #ifdef HAVE_IPV6
1847 case AF_INET6:
1848 pay->icmp6.type = 0x01; /* destination unreachable */
1849 pay->icmp6.code = 0x03; /* address unreachable */
1850 pay->icmp6.checksum = htons(0x0000);
1851 pay->icmp6.unused = htonl(0x00000000);
1852 buf += SWRAP_PACKET_PAYLOAD_ICMP6_SIZE;
1854 /* set the ip header in the ICMP payload */
1855 ip = (union swrap_packet_ip *)buf;
1856 ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */
1857 ip->v6.flow_label_high = 0x00;
1858 ip->v6.flow_label_low = 0x0000;
1859 ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */
1860 ip->v6.next_header = protocol;
1861 memcpy(ip->v6.src_addr, dest_in6->sin6_addr.s6_addr, 16);
1862 memcpy(ip->v6.dest_addr, src_in6->sin6_addr.s6_addr, 16);
1863 buf += SWRAP_PACKET_IP_V6_SIZE;
1865 src_port = dest_in6->sin6_port;
1866 dest_port = src_in6->sin6_port;
1867 break;
1868 #endif
1872 pay = (union swrap_packet_payload *)buf;
1874 switch (socket_type) {
1875 case SOCK_STREAM:
1876 pay->tcp.source_port = src_port;
1877 pay->tcp.dest_port = dest_port;
1878 pay->tcp.seq_num = htonl(tcp_seqno);
1879 pay->tcp.ack_num = htonl(tcp_ack);
1880 pay->tcp.hdr_length = 0x50; /* 5 * 32 bit words */
1881 pay->tcp.control = tcp_ctl;
1882 pay->tcp.window = htons(0x7FFF);
1883 pay->tcp.checksum = htons(0x0000);
1884 pay->tcp.urg = htons(0x0000);
1885 buf += SWRAP_PACKET_PAYLOAD_TCP_SIZE;
1887 break;
1889 case SOCK_DGRAM:
1890 pay->udp.source_port = src_port;
1891 pay->udp.dest_port = dest_port;
1892 pay->udp.length = htons(8 + payload_len);
1893 pay->udp.checksum = htons(0x0000);
1894 buf += SWRAP_PACKET_PAYLOAD_UDP_SIZE;
1896 break;
1899 if (payload && payload_len > 0) {
1900 memcpy(buf, payload, payload_len);
1903 *_packet_len = packet_len - icmp_truncate_len;
1904 return base;
1907 static int swrap_pcap_get_fd(const char *fname)
1909 static int fd = -1;
1911 if (fd != -1) return fd;
1913 fd = libc_open(fname, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0644);
1914 if (fd != -1) {
1915 struct swrap_file_hdr file_hdr;
1916 file_hdr.magic = 0xA1B2C3D4;
1917 file_hdr.version_major = 0x0002;
1918 file_hdr.version_minor = 0x0004;
1919 file_hdr.timezone = 0x00000000;
1920 file_hdr.sigfigs = 0x00000000;
1921 file_hdr.frame_max_len = SWRAP_FRAME_LENGTH_MAX;
1922 file_hdr.link_type = 0x0065; /* 101 RAW IP */
1924 if (write(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) {
1925 close(fd);
1926 fd = -1;
1928 return fd;
1931 fd = libc_open(fname, O_WRONLY|O_APPEND, 0644);
1933 return fd;
1936 static uint8_t *swrap_pcap_marshall_packet(struct socket_info *si,
1937 const struct sockaddr *addr,
1938 enum swrap_packet_type type,
1939 const void *buf, size_t len,
1940 size_t *packet_len)
1942 const struct sockaddr *src_addr;
1943 const struct sockaddr *dest_addr;
1944 unsigned long tcp_seqno = 0;
1945 unsigned long tcp_ack = 0;
1946 unsigned char tcp_ctl = 0;
1947 int unreachable = 0;
1949 struct timeval tv;
1951 switch (si->family) {
1952 case AF_INET:
1953 break;
1954 #ifdef HAVE_IPV6
1955 case AF_INET6:
1956 break;
1957 #endif
1958 default:
1959 return NULL;
1962 switch (type) {
1963 case SWRAP_CONNECT_SEND:
1964 if (si->type != SOCK_STREAM) return NULL;
1966 src_addr = &si->myname.sa.s;
1967 dest_addr = addr;
1969 tcp_seqno = si->io.pck_snd;
1970 tcp_ack = si->io.pck_rcv;
1971 tcp_ctl = 0x02; /* SYN */
1973 si->io.pck_snd += 1;
1975 break;
1977 case SWRAP_CONNECT_RECV:
1978 if (si->type != SOCK_STREAM) return NULL;
1980 dest_addr = &si->myname.sa.s;
1981 src_addr = addr;
1983 tcp_seqno = si->io.pck_rcv;
1984 tcp_ack = si->io.pck_snd;
1985 tcp_ctl = 0x12; /** SYN,ACK */
1987 si->io.pck_rcv += 1;
1989 break;
1991 case SWRAP_CONNECT_UNREACH:
1992 if (si->type != SOCK_STREAM) return NULL;
1994 dest_addr = &si->myname.sa.s;
1995 src_addr = addr;
1997 /* Unreachable: resend the data of SWRAP_CONNECT_SEND */
1998 tcp_seqno = si->io.pck_snd - 1;
1999 tcp_ack = si->io.pck_rcv;
2000 tcp_ctl = 0x02; /* SYN */
2001 unreachable = 1;
2003 break;
2005 case SWRAP_CONNECT_ACK:
2006 if (si->type != SOCK_STREAM) return NULL;
2008 src_addr = &si->myname.sa.s;
2009 dest_addr = addr;
2011 tcp_seqno = si->io.pck_snd;
2012 tcp_ack = si->io.pck_rcv;
2013 tcp_ctl = 0x10; /* ACK */
2015 break;
2017 case SWRAP_ACCEPT_SEND:
2018 if (si->type != SOCK_STREAM) return NULL;
2020 dest_addr = &si->myname.sa.s;
2021 src_addr = addr;
2023 tcp_seqno = si->io.pck_rcv;
2024 tcp_ack = si->io.pck_snd;
2025 tcp_ctl = 0x02; /* SYN */
2027 si->io.pck_rcv += 1;
2029 break;
2031 case SWRAP_ACCEPT_RECV:
2032 if (si->type != SOCK_STREAM) return NULL;
2034 src_addr = &si->myname.sa.s;
2035 dest_addr = addr;
2037 tcp_seqno = si->io.pck_snd;
2038 tcp_ack = si->io.pck_rcv;
2039 tcp_ctl = 0x12; /* SYN,ACK */
2041 si->io.pck_snd += 1;
2043 break;
2045 case SWRAP_ACCEPT_ACK:
2046 if (si->type != SOCK_STREAM) return NULL;
2048 dest_addr = &si->myname.sa.s;
2049 src_addr = addr;
2051 tcp_seqno = si->io.pck_rcv;
2052 tcp_ack = si->io.pck_snd;
2053 tcp_ctl = 0x10; /* ACK */
2055 break;
2057 case SWRAP_SEND:
2058 src_addr = &si->myname.sa.s;
2059 dest_addr = &si->peername.sa.s;
2061 tcp_seqno = si->io.pck_snd;
2062 tcp_ack = si->io.pck_rcv;
2063 tcp_ctl = 0x18; /* PSH,ACK */
2065 si->io.pck_snd += len;
2067 break;
2069 case SWRAP_SEND_RST:
2070 dest_addr = &si->myname.sa.s;
2071 src_addr = &si->peername.sa.s;
2073 if (si->type == SOCK_DGRAM) {
2074 return swrap_pcap_marshall_packet(si,
2075 &si->peername.sa.s,
2076 SWRAP_SENDTO_UNREACH,
2077 buf,
2078 len,
2079 packet_len);
2082 tcp_seqno = si->io.pck_rcv;
2083 tcp_ack = si->io.pck_snd;
2084 tcp_ctl = 0x14; /** RST,ACK */
2086 break;
2088 case SWRAP_PENDING_RST:
2089 dest_addr = &si->myname.sa.s;
2090 src_addr = &si->peername.sa.s;
2092 if (si->type == SOCK_DGRAM) {
2093 return NULL;
2096 tcp_seqno = si->io.pck_rcv;
2097 tcp_ack = si->io.pck_snd;
2098 tcp_ctl = 0x14; /* RST,ACK */
2100 break;
2102 case SWRAP_RECV:
2103 dest_addr = &si->myname.sa.s;
2104 src_addr = &si->peername.sa.s;
2106 tcp_seqno = si->io.pck_rcv;
2107 tcp_ack = si->io.pck_snd;
2108 tcp_ctl = 0x18; /* PSH,ACK */
2110 si->io.pck_rcv += len;
2112 break;
2114 case SWRAP_RECV_RST:
2115 dest_addr = &si->myname.sa.s;
2116 src_addr = &si->peername.sa.s;
2118 if (si->type == SOCK_DGRAM) {
2119 return NULL;
2122 tcp_seqno = si->io.pck_rcv;
2123 tcp_ack = si->io.pck_snd;
2124 tcp_ctl = 0x14; /* RST,ACK */
2126 break;
2128 case SWRAP_SENDTO:
2129 src_addr = &si->myname.sa.s;
2130 dest_addr = addr;
2132 si->io.pck_snd += len;
2134 break;
2136 case SWRAP_SENDTO_UNREACH:
2137 dest_addr = &si->myname.sa.s;
2138 src_addr = addr;
2140 unreachable = 1;
2142 break;
2144 case SWRAP_RECVFROM:
2145 dest_addr = &si->myname.sa.s;
2146 src_addr = addr;
2148 si->io.pck_rcv += len;
2150 break;
2152 case SWRAP_CLOSE_SEND:
2153 if (si->type != SOCK_STREAM) return NULL;
2155 src_addr = &si->myname.sa.s;
2156 dest_addr = &si->peername.sa.s;
2158 tcp_seqno = si->io.pck_snd;
2159 tcp_ack = si->io.pck_rcv;
2160 tcp_ctl = 0x11; /* FIN, ACK */
2162 si->io.pck_snd += 1;
2164 break;
2166 case SWRAP_CLOSE_RECV:
2167 if (si->type != SOCK_STREAM) return NULL;
2169 dest_addr = &si->myname.sa.s;
2170 src_addr = &si->peername.sa.s;
2172 tcp_seqno = si->io.pck_rcv;
2173 tcp_ack = si->io.pck_snd;
2174 tcp_ctl = 0x11; /* FIN,ACK */
2176 si->io.pck_rcv += 1;
2178 break;
2180 case SWRAP_CLOSE_ACK:
2181 if (si->type != SOCK_STREAM) return NULL;
2183 src_addr = &si->myname.sa.s;
2184 dest_addr = &si->peername.sa.s;
2186 tcp_seqno = si->io.pck_snd;
2187 tcp_ack = si->io.pck_rcv;
2188 tcp_ctl = 0x10; /* ACK */
2190 break;
2191 default:
2192 return NULL;
2195 swrapGetTimeOfDay(&tv);
2197 return swrap_pcap_packet_init(&tv,
2198 src_addr,
2199 dest_addr,
2200 si->type,
2201 (const uint8_t *)buf,
2202 len,
2203 tcp_seqno,
2204 tcp_ack,
2205 tcp_ctl,
2206 unreachable,
2207 packet_len);
2210 static void swrap_pcap_dump_packet(struct socket_info *si,
2211 const struct sockaddr *addr,
2212 enum swrap_packet_type type,
2213 const void *buf, size_t len)
2215 const char *file_name;
2216 uint8_t *packet;
2217 size_t packet_len = 0;
2218 int fd;
2220 file_name = swrap_pcap_init_file();
2221 if (!file_name) {
2222 return;
2225 packet = swrap_pcap_marshall_packet(si,
2226 addr,
2227 type,
2228 buf,
2229 len,
2230 &packet_len);
2231 if (packet == NULL) {
2232 return;
2235 fd = swrap_pcap_get_fd(file_name);
2236 if (fd != -1) {
2237 if (write(fd, packet, packet_len) != (ssize_t)packet_len) {
2238 free(packet);
2239 return;
2243 free(packet);
2246 /****************************************************************************
2247 * SIGNALFD
2248 ***************************************************************************/
2250 #ifdef HAVE_SIGNALFD
2251 static int swrap_signalfd(int fd, const sigset_t *mask, int flags)
2253 int rc;
2255 rc = libc_signalfd(fd, mask, flags);
2256 if (rc != -1) {
2257 swrap_remove_stale(fd);
2260 return rc;
2263 int signalfd(int fd, const sigset_t *mask, int flags)
2265 return swrap_signalfd(fd, mask, flags);
2267 #endif
2269 /****************************************************************************
2270 * SOCKET
2271 ***************************************************************************/
2273 static int swrap_socket(int family, int type, int protocol)
2275 struct socket_info *si;
2276 struct socket_info_fd *fi;
2277 int fd;
2278 int real_type = type;
2281 * Remove possible addition flags passed to socket() so
2282 * do not fail checking the type.
2283 * See https://lwn.net/Articles/281965/
2285 #ifdef SOCK_CLOEXEC
2286 real_type &= ~SOCK_CLOEXEC;
2287 #endif
2288 #ifdef SOCK_NONBLOCK
2289 real_type &= ~SOCK_NONBLOCK;
2290 #endif
2292 if (!socket_wrapper_enabled()) {
2293 return libc_socket(family, type, protocol);
2296 switch (family) {
2297 case AF_INET:
2298 #ifdef HAVE_IPV6
2299 case AF_INET6:
2300 #endif
2301 break;
2302 case AF_UNIX:
2303 return libc_socket(family, type, protocol);
2304 default:
2305 errno = EAFNOSUPPORT;
2306 return -1;
2309 switch (real_type) {
2310 case SOCK_STREAM:
2311 break;
2312 case SOCK_DGRAM:
2313 break;
2314 default:
2315 errno = EPROTONOSUPPORT;
2316 return -1;
2319 switch (protocol) {
2320 case 0:
2321 break;
2322 case 6:
2323 if (real_type == SOCK_STREAM) {
2324 break;
2326 /*fall through*/
2327 case 17:
2328 if (real_type == SOCK_DGRAM) {
2329 break;
2331 /*fall through*/
2332 default:
2333 errno = EPROTONOSUPPORT;
2334 return -1;
2338 * We must call libc_socket with type, from the caller, not the version
2339 * we removed SOCK_CLOEXEC and SOCK_NONBLOCK from
2341 fd = libc_socket(AF_UNIX, type, 0);
2343 if (fd == -1) {
2344 return -1;
2347 /* Check if we have a stale fd and remove it */
2348 si = find_socket_info(fd);
2349 if (si != NULL) {
2350 swrap_remove_stale(fd);
2353 si = (struct socket_info *)malloc(sizeof(struct socket_info));
2354 memset(si, 0, sizeof(struct socket_info));
2355 if (si == NULL) {
2356 errno = ENOMEM;
2357 return -1;
2360 si->family = family;
2362 /* however, the rest of the socket_wrapper code expects just
2363 * the type, not the flags */
2364 si->type = real_type;
2365 si->protocol = protocol;
2368 * Setup myname so getsockname() can succeed to find out the socket
2369 * type.
2371 switch(si->family) {
2372 case AF_INET: {
2373 struct sockaddr_in sin = {
2374 .sin_family = AF_INET,
2377 si->myname.sa_socklen = sizeof(struct sockaddr_in);
2378 memcpy(&si->myname.sa.in, &sin, si->myname.sa_socklen);
2379 break;
2381 case AF_INET6: {
2382 struct sockaddr_in6 sin6 = {
2383 .sin6_family = AF_INET6,
2386 si->myname.sa_socklen = sizeof(struct sockaddr_in6);
2387 memcpy(&si->myname.sa.in6, &sin6, si->myname.sa_socklen);
2388 break;
2390 default:
2391 free(si);
2392 errno = EINVAL;
2393 return -1;
2396 fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
2397 if (fi == NULL) {
2398 free(si);
2399 errno = ENOMEM;
2400 return -1;
2403 fi->fd = fd;
2405 SWRAP_DLIST_ADD(si->fds, fi);
2406 SWRAP_DLIST_ADD(sockets, si);
2408 return fd;
2411 int socket(int family, int type, int protocol)
2413 return swrap_socket(family, type, protocol);
2416 /****************************************************************************
2417 * SOCKETPAIR
2418 ***************************************************************************/
2420 static int swrap_socketpair(int family, int type, int protocol, int sv[2])
2422 int rc;
2424 rc = libc_socketpair(family, type, protocol, sv);
2425 if (rc != -1) {
2426 swrap_remove_stale(sv[0]);
2427 swrap_remove_stale(sv[1]);
2430 return rc;
2433 int socketpair(int family, int type, int protocol, int sv[2])
2435 return swrap_socketpair(family, type, protocol, sv);
2438 /****************************************************************************
2439 * SOCKETPAIR
2440 ***************************************************************************/
2442 #ifdef HAVE_TIMERFD_CREATE
2443 static int swrap_timerfd_create(int clockid, int flags)
2445 int fd;
2447 fd = libc_timerfd_create(clockid, flags);
2448 if (fd != -1) {
2449 swrap_remove_stale(fd);
2452 return fd;
2455 int timerfd_create(int clockid, int flags)
2457 return swrap_timerfd_create(clockid, flags);
2459 #endif
2461 /****************************************************************************
2462 * PIPE
2463 ***************************************************************************/
2465 static int swrap_pipe(int pipefd[2])
2467 int rc;
2469 rc = libc_pipe(pipefd);
2470 if (rc != -1) {
2471 swrap_remove_stale(pipefd[0]);
2472 swrap_remove_stale(pipefd[1]);
2475 return rc;
2478 int pipe(int pipefd[2])
2480 return swrap_pipe(pipefd);
2483 /****************************************************************************
2484 * ACCEPT
2485 ***************************************************************************/
2487 static int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
2489 struct socket_info *parent_si, *child_si;
2490 struct socket_info_fd *child_fi;
2491 int fd;
2492 struct swrap_address un_addr = {
2493 .sa_socklen = sizeof(struct sockaddr_un),
2495 struct swrap_address un_my_addr = {
2496 .sa_socklen = sizeof(struct sockaddr_un),
2498 struct swrap_address in_addr = {
2499 .sa_socklen = sizeof(struct sockaddr_storage),
2501 struct swrap_address in_my_addr = {
2502 .sa_socklen = sizeof(struct sockaddr_storage),
2504 int ret;
2506 parent_si = find_socket_info(s);
2507 if (!parent_si) {
2508 return libc_accept(s, addr, addrlen);
2512 * assume out sockaddr have the same size as the in parent
2513 * socket family
2515 in_addr.sa_socklen = socket_length(parent_si->family);
2516 if (in_addr.sa_socklen <= 0) {
2517 errno = EINVAL;
2518 return -1;
2521 ret = libc_accept(s, &un_addr.sa.s, &un_addr.sa_socklen);
2522 if (ret == -1) {
2523 if (errno == ENOTSOCK) {
2524 /* Remove stale fds */
2525 swrap_remove_stale(s);
2527 return ret;
2530 fd = ret;
2532 ret = sockaddr_convert_from_un(parent_si,
2533 &un_addr.sa.un,
2534 un_addr.sa_socklen,
2535 parent_si->family,
2536 &in_addr.sa.s,
2537 &in_addr.sa_socklen);
2538 if (ret == -1) {
2539 close(fd);
2540 return ret;
2543 child_si = (struct socket_info *)malloc(sizeof(struct socket_info));
2544 memset(child_si, 0, sizeof(struct socket_info));
2546 child_fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
2547 if (child_fi == NULL) {
2548 free(child_si);
2549 close(fd);
2550 errno = ENOMEM;
2551 return -1;
2554 child_fi->fd = fd;
2556 SWRAP_DLIST_ADD(child_si->fds, child_fi);
2558 child_si->family = parent_si->family;
2559 child_si->type = parent_si->type;
2560 child_si->protocol = parent_si->protocol;
2561 child_si->bound = 1;
2562 child_si->is_server = 1;
2563 child_si->connected = 1;
2565 child_si->peername = (struct swrap_address) {
2566 .sa_socklen = in_addr.sa_socklen,
2568 memcpy(&child_si->peername.sa.ss, &in_addr.sa.ss, in_addr.sa_socklen);
2570 if (addr != NULL && addrlen != NULL) {
2571 size_t copy_len = MIN(*addrlen, in_addr.sa_socklen);
2572 if (copy_len > 0) {
2573 memcpy(addr, &in_addr.sa.ss, copy_len);
2575 *addrlen = in_addr.sa_socklen;
2578 ret = libc_getsockname(fd,
2579 &un_my_addr.sa.s,
2580 &un_my_addr.sa_socklen);
2581 if (ret == -1) {
2582 free(child_fi);
2583 free(child_si);
2584 close(fd);
2585 return ret;
2588 ret = sockaddr_convert_from_un(child_si,
2589 &un_my_addr.sa.un,
2590 un_my_addr.sa_socklen,
2591 child_si->family,
2592 &in_my_addr.sa.s,
2593 &in_my_addr.sa_socklen);
2594 if (ret == -1) {
2595 free(child_fi);
2596 free(child_si);
2597 close(fd);
2598 return ret;
2601 SWRAP_LOG(SWRAP_LOG_TRACE,
2602 "accept() path=%s, fd=%d",
2603 un_my_addr.sa.un.sun_path, s);
2605 child_si->myname = (struct swrap_address) {
2606 .sa_socklen = in_my_addr.sa_socklen,
2608 memcpy(&child_si->myname.sa.ss, &in_my_addr.sa.ss, in_my_addr.sa_socklen);
2610 SWRAP_DLIST_ADD(sockets, child_si);
2612 if (addr != NULL) {
2613 swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0);
2614 swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_RECV, NULL, 0);
2615 swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_ACK, NULL, 0);
2618 return fd;
2621 #ifdef HAVE_ACCEPT_PSOCKLEN_T
2622 int accept(int s, struct sockaddr *addr, Psocklen_t addrlen)
2623 #else
2624 int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
2625 #endif
2627 return swrap_accept(s, addr, (socklen_t *)addrlen);
2630 static int autobind_start_init;
2631 static int autobind_start;
2633 /* using sendto() or connect() on an unbound socket would give the
2634 recipient no way to reply, as unlike UDP and TCP, a unix domain
2635 socket can't auto-assign ephemeral port numbers, so we need to
2636 assign it here.
2637 Note: this might change the family from ipv6 to ipv4
2639 static int swrap_auto_bind(int fd, struct socket_info *si, int family)
2641 struct swrap_address un_addr = {
2642 .sa_socklen = sizeof(struct sockaddr_un),
2644 int i;
2645 char type;
2646 int ret;
2647 int port;
2648 struct stat st;
2650 if (autobind_start_init != 1) {
2651 autobind_start_init = 1;
2652 autobind_start = getpid();
2653 autobind_start %= 50000;
2654 autobind_start += 10000;
2657 un_addr.sa.un.sun_family = AF_UNIX;
2659 switch (family) {
2660 case AF_INET: {
2661 struct sockaddr_in in;
2663 switch (si->type) {
2664 case SOCK_STREAM:
2665 type = SOCKET_TYPE_CHAR_TCP;
2666 break;
2667 case SOCK_DGRAM:
2668 type = SOCKET_TYPE_CHAR_UDP;
2669 break;
2670 default:
2671 errno = ESOCKTNOSUPPORT;
2672 return -1;
2675 memset(&in, 0, sizeof(in));
2676 in.sin_family = AF_INET;
2677 in.sin_addr.s_addr = htonl(127<<24 |
2678 socket_wrapper_default_iface());
2680 si->myname = (struct swrap_address) {
2681 .sa_socklen = sizeof(in),
2683 memcpy(&si->myname.sa.in, &in, si->myname.sa_socklen);
2684 break;
2686 #ifdef HAVE_IPV6
2687 case AF_INET6: {
2688 struct sockaddr_in6 in6;
2690 if (si->family != family) {
2691 errno = ENETUNREACH;
2692 return -1;
2695 switch (si->type) {
2696 case SOCK_STREAM:
2697 type = SOCKET_TYPE_CHAR_TCP_V6;
2698 break;
2699 case SOCK_DGRAM:
2700 type = SOCKET_TYPE_CHAR_UDP_V6;
2701 break;
2702 default:
2703 errno = ESOCKTNOSUPPORT;
2704 return -1;
2707 memset(&in6, 0, sizeof(in6));
2708 in6.sin6_family = AF_INET6;
2709 in6.sin6_addr = *swrap_ipv6();
2710 in6.sin6_addr.s6_addr[15] = socket_wrapper_default_iface();
2712 si->myname = (struct swrap_address) {
2713 .sa_socklen = sizeof(in6),
2715 memcpy(&si->myname.sa.in6, &in6, si->myname.sa_socklen);
2716 break;
2718 #endif
2719 default:
2720 errno = ESOCKTNOSUPPORT;
2721 return -1;
2724 if (autobind_start > 60000) {
2725 autobind_start = 10000;
2728 for (i = 0; i < SOCKET_MAX_SOCKETS; i++) {
2729 port = autobind_start + i;
2730 snprintf(un_addr.sa.un.sun_path, un_addr.sa_socklen,
2731 "%s/"SOCKET_FORMAT, socket_wrapper_dir(),
2732 type, socket_wrapper_default_iface(), port);
2733 if (stat(un_addr.sa.un.sun_path, &st) == 0) continue;
2735 ret = libc_bind(fd, &un_addr.sa.s, un_addr.sa_socklen);
2736 if (ret == -1) return ret;
2738 si->un_addr = un_addr.sa.un;
2740 si->bound = 1;
2741 autobind_start = port + 1;
2742 break;
2744 if (i == SOCKET_MAX_SOCKETS) {
2745 SWRAP_LOG(SWRAP_LOG_ERROR, "Too many open unix sockets (%u) for "
2746 "interface "SOCKET_FORMAT,
2747 SOCKET_MAX_SOCKETS,
2748 type,
2749 socket_wrapper_default_iface(),
2751 errno = ENFILE;
2752 return -1;
2755 si->family = family;
2756 set_port(si->family, port, &si->myname);
2758 return 0;
2761 /****************************************************************************
2762 * CONNECT
2763 ***************************************************************************/
2765 static int swrap_connect(int s, const struct sockaddr *serv_addr,
2766 socklen_t addrlen)
2768 int ret;
2769 struct swrap_address un_addr = {
2770 .sa_socklen = sizeof(struct sockaddr_un),
2772 struct socket_info *si = find_socket_info(s);
2773 int bcast = 0;
2775 if (!si) {
2776 return libc_connect(s, serv_addr, addrlen);
2779 if (si->bound == 0) {
2780 ret = swrap_auto_bind(s, si, serv_addr->sa_family);
2781 if (ret == -1) return -1;
2784 if (si->family != serv_addr->sa_family) {
2785 errno = EINVAL;
2786 return -1;
2789 ret = sockaddr_convert_to_un(si, serv_addr,
2790 addrlen, &un_addr.sa.un, 0, &bcast);
2791 if (ret == -1) return -1;
2793 if (bcast) {
2794 errno = ENETUNREACH;
2795 return -1;
2798 if (si->type == SOCK_DGRAM) {
2799 si->defer_connect = 1;
2800 ret = 0;
2801 } else {
2802 swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0);
2804 ret = libc_connect(s,
2805 &un_addr.sa.s,
2806 un_addr.sa_socklen);
2809 SWRAP_LOG(SWRAP_LOG_TRACE,
2810 "connect() path=%s, fd=%d",
2811 un_addr.sa.un.sun_path, s);
2814 /* to give better errors */
2815 if (ret == -1 && errno == ENOENT) {
2816 errno = EHOSTUNREACH;
2819 if (ret == 0) {
2820 si->peername = (struct swrap_address) {
2821 .sa_socklen = addrlen,
2824 memcpy(&si->peername.sa.ss, serv_addr, addrlen);
2825 si->connected = 1;
2828 * When we connect() on a socket than we have to bind the
2829 * outgoing connection on the interface we use for the
2830 * transport. We already bound it on the right interface
2831 * but here we have to update the name so getsockname()
2832 * returns correct information.
2834 if (si->bindname.sa_socklen > 0) {
2835 si->myname = (struct swrap_address) {
2836 .sa_socklen = si->bindname.sa_socklen,
2839 memcpy(&si->myname.sa.ss,
2840 &si->bindname.sa.ss,
2841 si->bindname.sa_socklen);
2843 /* Cleanup bindname */
2844 si->bindname = (struct swrap_address) {
2845 .sa_socklen = 0,
2849 swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0);
2850 swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0);
2851 } else {
2852 swrap_pcap_dump_packet(si, serv_addr, SWRAP_CONNECT_UNREACH, NULL, 0);
2855 return ret;
2858 int connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen)
2860 return swrap_connect(s, serv_addr, addrlen);
2863 /****************************************************************************
2864 * BIND
2865 ***************************************************************************/
2867 static int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
2869 int ret;
2870 struct swrap_address un_addr = {
2871 .sa_socklen = sizeof(struct sockaddr_un),
2873 struct socket_info *si = find_socket_info(s);
2874 int bind_error = 0;
2875 #if 0 /* FIXME */
2876 bool in_use;
2877 #endif
2879 if (!si) {
2880 return libc_bind(s, myaddr, addrlen);
2883 switch (si->family) {
2884 case AF_INET: {
2885 const struct sockaddr_in *sin;
2886 if (addrlen < sizeof(struct sockaddr_in)) {
2887 bind_error = EINVAL;
2888 break;
2891 sin = (const struct sockaddr_in *)myaddr;
2893 if (sin->sin_family != AF_INET) {
2894 bind_error = EAFNOSUPPORT;
2897 /* special case for AF_UNSPEC */
2898 if (sin->sin_family == AF_UNSPEC &&
2899 (sin->sin_addr.s_addr == htonl(INADDR_ANY)))
2901 bind_error = 0;
2904 break;
2906 #ifdef HAVE_IPV6
2907 case AF_INET6: {
2908 const struct sockaddr_in6 *sin6;
2909 if (addrlen < sizeof(struct sockaddr_in6)) {
2910 bind_error = EINVAL;
2911 break;
2914 sin6 = (const struct sockaddr_in6 *)myaddr;
2916 if (sin6->sin6_family != AF_INET6) {
2917 bind_error = EAFNOSUPPORT;
2920 break;
2922 #endif
2923 default:
2924 bind_error = EINVAL;
2925 break;
2928 if (bind_error != 0) {
2929 errno = bind_error;
2930 return -1;
2933 #if 0 /* FIXME */
2934 in_use = check_addr_port_in_use(myaddr, addrlen);
2935 if (in_use) {
2936 errno = EADDRINUSE;
2937 return -1;
2939 #endif
2941 si->myname.sa_socklen = addrlen;
2942 memcpy(&si->myname.sa.ss, myaddr, addrlen);
2944 ret = sockaddr_convert_to_un(si,
2945 myaddr,
2946 addrlen,
2947 &un_addr.sa.un,
2949 &si->bcast);
2950 if (ret == -1) return -1;
2952 unlink(un_addr.sa.un.sun_path);
2954 ret = libc_bind(s, &un_addr.sa.s, un_addr.sa_socklen);
2956 SWRAP_LOG(SWRAP_LOG_TRACE,
2957 "bind() path=%s, fd=%d",
2958 un_addr.sa.un.sun_path, s);
2960 if (ret == 0) {
2961 si->bound = 1;
2964 return ret;
2967 int bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
2969 return swrap_bind(s, myaddr, addrlen);
2972 /****************************************************************************
2973 * BINDRESVPORT
2974 ***************************************************************************/
2976 #ifdef HAVE_BINDRESVPORT
2977 static int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen);
2979 static int swrap_bindresvport_sa(int sd, struct sockaddr *sa)
2981 struct swrap_address myaddr = {
2982 .sa_socklen = sizeof(struct sockaddr_storage),
2984 socklen_t salen;
2985 static uint16_t port;
2986 uint16_t i;
2987 int rc = -1;
2988 int af;
2990 #define SWRAP_STARTPORT 600
2991 #define SWRAP_ENDPORT (IPPORT_RESERVED - 1)
2992 #define SWRAP_NPORTS (SWRAP_ENDPORT - SWRAP_STARTPORT + 1)
2994 if (port == 0) {
2995 port = (getpid() % SWRAP_NPORTS) + SWRAP_STARTPORT;
2998 if (sa == NULL) {
2999 salen = myaddr.sa_socklen;
3000 sa = &myaddr.sa.s;
3002 rc = swrap_getsockname(sd, &myaddr.sa.s, &salen);
3003 if (rc < 0) {
3004 return -1;
3007 af = sa->sa_family;
3008 memset(&myaddr.sa.ss, 0, salen);
3009 } else {
3010 af = sa->sa_family;
3013 for (i = 0; i < SWRAP_NPORTS; i++, port++) {
3014 switch(af) {
3015 case AF_INET: {
3016 struct sockaddr_in *sinp = (struct sockaddr_in *)(void *)sa;
3018 salen = sizeof(struct sockaddr_in);
3019 sinp->sin_port = htons(port);
3020 break;
3022 case AF_INET6: {
3023 struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *)sa;
3025 salen = sizeof(struct sockaddr_in6);
3026 sin6p->sin6_port = htons(port);
3027 break;
3029 default:
3030 errno = EAFNOSUPPORT;
3031 return -1;
3033 sa->sa_family = af;
3035 if (port > SWRAP_ENDPORT) {
3036 port = SWRAP_STARTPORT;
3039 rc = swrap_bind(sd, (struct sockaddr *)sa, salen);
3040 if (rc == 0 || errno != EADDRINUSE) {
3041 break;
3045 return rc;
3048 int bindresvport(int sockfd, struct sockaddr_in *sinp)
3050 return swrap_bindresvport_sa(sockfd, (struct sockaddr *)sinp);
3052 #endif
3054 /****************************************************************************
3055 * LISTEN
3056 ***************************************************************************/
3058 static int swrap_listen(int s, int backlog)
3060 int ret;
3061 struct socket_info *si = find_socket_info(s);
3063 if (!si) {
3064 return libc_listen(s, backlog);
3067 ret = libc_listen(s, backlog);
3069 return ret;
3072 int listen(int s, int backlog)
3074 return swrap_listen(s, backlog);
3077 /****************************************************************************
3078 * FOPEN
3079 ***************************************************************************/
3081 static FILE *swrap_fopen(const char *name, const char *mode)
3083 FILE *fp;
3085 fp = libc_fopen(name, mode);
3086 if (fp != NULL) {
3087 int fd = fileno(fp);
3089 swrap_remove_stale(fd);
3092 return fp;
3095 FILE *fopen(const char *name, const char *mode)
3097 return swrap_fopen(name, mode);
3100 /****************************************************************************
3101 * OPEN
3102 ***************************************************************************/
3104 static int swrap_vopen(const char *pathname, int flags, va_list ap)
3106 int ret;
3108 ret = libc_vopen(pathname, flags, ap);
3109 if (ret != -1) {
3111 * There are methods for closing descriptors (libc-internal code
3112 * paths, direct syscalls) which close descriptors in ways that
3113 * we can't intercept, so try to recover when we notice that
3114 * that's happened
3116 swrap_remove_stale(ret);
3118 return ret;
3121 int open(const char *pathname, int flags, ...)
3123 va_list ap;
3124 int fd;
3126 va_start(ap, flags);
3127 fd = swrap_vopen(pathname, flags, ap);
3128 va_end(ap);
3130 return fd;
3133 /****************************************************************************
3134 * GETPEERNAME
3135 ***************************************************************************/
3137 static int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
3139 struct socket_info *si = find_socket_info(s);
3140 socklen_t len;
3142 if (!si) {
3143 return libc_getpeername(s, name, addrlen);
3146 if (si->peername.sa_socklen == 0)
3148 errno = ENOTCONN;
3149 return -1;
3152 len = MIN(*addrlen, si->peername.sa_socklen);
3153 if (len == 0) {
3154 return 0;
3157 memcpy(name, &si->peername.sa.ss, len);
3158 *addrlen = si->peername.sa_socklen;
3160 return 0;
3163 #ifdef HAVE_ACCEPT_PSOCKLEN_T
3164 int getpeername(int s, struct sockaddr *name, Psocklen_t addrlen)
3165 #else
3166 int getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
3167 #endif
3169 return swrap_getpeername(s, name, (socklen_t *)addrlen);
3172 /****************************************************************************
3173 * GETSOCKNAME
3174 ***************************************************************************/
3176 static int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
3178 struct socket_info *si = find_socket_info(s);
3179 socklen_t len;
3181 if (!si) {
3182 return libc_getsockname(s, name, addrlen);
3185 len = MIN(*addrlen, si->myname.sa_socklen);
3186 if (len == 0) {
3187 return 0;
3190 memcpy(name, &si->myname.sa.ss, len);
3191 *addrlen = si->myname.sa_socklen;
3193 return 0;
3196 #ifdef HAVE_ACCEPT_PSOCKLEN_T
3197 int getsockname(int s, struct sockaddr *name, Psocklen_t addrlen)
3198 #else
3199 int getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
3200 #endif
3202 return swrap_getsockname(s, name, (socklen_t *)addrlen);
3205 /****************************************************************************
3206 * GETSOCKOPT
3207 ***************************************************************************/
3209 #ifndef SO_PROTOCOL
3210 # ifdef SO_PROTOTYPE /* The Solaris name */
3211 # define SO_PROTOCOL SO_PROTOTYPE
3212 # endif /* SO_PROTOTYPE */
3213 #endif /* SO_PROTOCOL */
3215 static int swrap_getsockopt(int s, int level, int optname,
3216 void *optval, socklen_t *optlen)
3218 struct socket_info *si = find_socket_info(s);
3220 if (!si) {
3221 return libc_getsockopt(s,
3222 level,
3223 optname,
3224 optval,
3225 optlen);
3228 if (level == SOL_SOCKET) {
3229 switch (optname) {
3230 #ifdef SO_DOMAIN
3231 case SO_DOMAIN:
3232 if (optval == NULL || optlen == NULL ||
3233 *optlen < (socklen_t)sizeof(int)) {
3234 errno = EINVAL;
3235 return -1;
3238 *optlen = sizeof(int);
3239 *(int *)optval = si->family;
3240 return 0;
3241 #endif /* SO_DOMAIN */
3243 #ifdef SO_PROTOCOL
3244 case SO_PROTOCOL:
3245 if (optval == NULL || optlen == NULL ||
3246 *optlen < (socklen_t)sizeof(int)) {
3247 errno = EINVAL;
3248 return -1;
3251 *optlen = sizeof(int);
3252 *(int *)optval = si->protocol;
3253 return 0;
3254 #endif /* SO_PROTOCOL */
3255 case SO_TYPE:
3256 if (optval == NULL || optlen == NULL ||
3257 *optlen < (socklen_t)sizeof(int)) {
3258 errno = EINVAL;
3259 return -1;
3262 *optlen = sizeof(int);
3263 *(int *)optval = si->type;
3264 return 0;
3265 default:
3266 return libc_getsockopt(s,
3267 level,
3268 optname,
3269 optval,
3270 optlen);
3274 errno = ENOPROTOOPT;
3275 return -1;
3278 #ifdef HAVE_ACCEPT_PSOCKLEN_T
3279 int getsockopt(int s, int level, int optname, void *optval, Psocklen_t optlen)
3280 #else
3281 int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
3282 #endif
3284 return swrap_getsockopt(s, level, optname, optval, (socklen_t *)optlen);
3287 /****************************************************************************
3288 * SETSOCKOPT
3289 ***************************************************************************/
3291 static int swrap_setsockopt(int s, int level, int optname,
3292 const void *optval, socklen_t optlen)
3294 struct socket_info *si = find_socket_info(s);
3296 if (!si) {
3297 return libc_setsockopt(s,
3298 level,
3299 optname,
3300 optval,
3301 optlen);
3304 if (level == SOL_SOCKET) {
3305 return libc_setsockopt(s,
3306 level,
3307 optname,
3308 optval,
3309 optlen);
3312 switch (si->family) {
3313 case AF_INET:
3314 if (level == IPPROTO_IP) {
3315 #ifdef IP_PKTINFO
3316 if (optname == IP_PKTINFO) {
3317 si->pktinfo = AF_INET;
3319 #endif /* IP_PKTINFO */
3321 return 0;
3322 #ifdef HAVE_IPV6
3323 case AF_INET6:
3324 if (level == IPPROTO_IPV6) {
3325 #ifdef IPV6_RECVPKTINFO
3326 if (optname == IPV6_RECVPKTINFO) {
3327 si->pktinfo = AF_INET6;
3329 #endif /* IPV6_PKTINFO */
3331 return 0;
3332 #endif
3333 default:
3334 errno = ENOPROTOOPT;
3335 return -1;
3339 int setsockopt(int s, int level, int optname,
3340 const void *optval, socklen_t optlen)
3342 return swrap_setsockopt(s, level, optname, optval, optlen);
3345 /****************************************************************************
3346 * IOCTL
3347 ***************************************************************************/
3349 static int swrap_vioctl(int s, unsigned long int r, va_list va)
3351 struct socket_info *si = find_socket_info(s);
3352 va_list ap;
3353 int value;
3354 int rc;
3356 if (!si) {
3357 return libc_vioctl(s, r, va);
3360 va_copy(ap, va);
3362 rc = libc_vioctl(s, r, va);
3364 switch (r) {
3365 case FIONREAD:
3366 value = *((int *)va_arg(ap, int *));
3368 if (rc == -1 && errno != EAGAIN && errno != ENOBUFS) {
3369 swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
3370 } else if (value == 0) { /* END OF FILE */
3371 swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
3373 break;
3376 va_end(ap);
3378 return rc;
3381 #ifdef HAVE_IOCTL_INT
3382 int ioctl(int s, int r, ...)
3383 #else
3384 int ioctl(int s, unsigned long int r, ...)
3385 #endif
3387 va_list va;
3388 int rc;
3390 va_start(va, r);
3392 rc = swrap_vioctl(s, (unsigned long int) r, va);
3394 va_end(va);
3396 return rc;
3399 /*****************
3400 * CMSG
3401 *****************/
3403 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
3405 #ifndef CMSG_ALIGN
3406 # ifdef _ALIGN /* BSD */
3407 #define CMSG_ALIGN _ALIGN
3408 # else
3409 #define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1))
3410 # endif /* _ALIGN */
3411 #endif /* CMSG_ALIGN */
3414 * @brief Add a cmsghdr to a msghdr.
3416 * This is an function to add any type of cmsghdr. It will operate on the
3417 * msg->msg_control and msg->msg_controllen you pass in by adapting them to
3418 * the buffer position after the added cmsg element. Hence, this function is
3419 * intended to be used with an intermediate msghdr and not on the original
3420 * one handed in by the client.
3422 * @param[in] msg The msghdr to which to add the cmsg.
3424 * @param[in] level The cmsg level to set.
3426 * @param[in] type The cmsg type to set.
3428 * @param[in] data The cmsg data to set.
3430 * @param[in] len the length of the data to set.
3432 static void swrap_msghdr_add_cmsghdr(struct msghdr *msg,
3433 int level,
3434 int type,
3435 const void *data,
3436 size_t len)
3438 size_t cmlen = CMSG_LEN(len);
3439 size_t cmspace = CMSG_SPACE(len);
3440 uint8_t cmbuf[cmspace];
3441 void *cast_ptr = (void *)cmbuf;
3442 struct cmsghdr *cm = (struct cmsghdr *)cast_ptr;
3443 uint8_t *p;
3445 memset(cmbuf, 0, cmspace);
3447 if (msg->msg_controllen < cmlen) {
3448 cmlen = msg->msg_controllen;
3449 msg->msg_flags |= MSG_CTRUNC;
3452 if (msg->msg_controllen < cmspace) {
3453 cmspace = msg->msg_controllen;
3457 * We copy the full input data into an intermediate cmsghdr first
3458 * in order to more easily cope with truncation.
3460 cm->cmsg_len = cmlen;
3461 cm->cmsg_level = level;
3462 cm->cmsg_type = type;
3463 memcpy(CMSG_DATA(cm), data, len);
3466 * We now copy the possibly truncated buffer.
3467 * We copy cmlen bytes, but consume cmspace bytes,
3468 * leaving the possible padding uninitialiazed.
3470 p = (uint8_t *)msg->msg_control;
3471 memcpy(p, cm, cmlen);
3472 p += cmspace;
3473 msg->msg_control = p;
3474 msg->msg_controllen -= cmspace;
3476 return;
3479 static int swrap_msghdr_add_pktinfo(struct socket_info *si,
3480 struct msghdr *msg)
3482 /* Add packet info */
3483 switch (si->pktinfo) {
3484 #if defined(IP_PKTINFO) && (defined(HAVE_STRUCT_IN_PKTINFO) || defined(IP_RECVDSTADDR))
3485 case AF_INET: {
3486 struct sockaddr_in *sin;
3487 #if defined(HAVE_STRUCT_IN_PKTINFO)
3488 struct in_pktinfo pkt;
3489 #elif defined(IP_RECVDSTADDR)
3490 struct in_addr pkt;
3491 #endif
3493 if (si->bindname.sa_socklen == sizeof(struct sockaddr_in)) {
3494 sin = &si->bindname.sa.in;
3495 } else {
3496 if (si->myname.sa_socklen != sizeof(struct sockaddr_in)) {
3497 return 0;
3499 sin = &si->myname.sa.in;
3502 ZERO_STRUCT(pkt);
3504 #if defined(HAVE_STRUCT_IN_PKTINFO)
3505 pkt.ipi_ifindex = socket_wrapper_default_iface();
3506 pkt.ipi_addr.s_addr = sin->sin_addr.s_addr;
3507 #elif defined(IP_RECVDSTADDR)
3508 pkt = sin->sin_addr;
3509 #endif
3511 swrap_msghdr_add_cmsghdr(msg, IPPROTO_IP, IP_PKTINFO,
3512 &pkt, sizeof(pkt));
3514 break;
3516 #endif /* IP_PKTINFO */
3517 #if defined(HAVE_IPV6)
3518 case AF_INET6: {
3519 #if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO)
3520 struct sockaddr_in6 *sin6;
3521 struct in6_pktinfo pkt6;
3523 if (si->bindname.sa_socklen == sizeof(struct sockaddr_in6)) {
3524 sin6 = &si->bindname.sa.in6;
3525 } else {
3526 if (si->myname.sa_socklen != sizeof(struct sockaddr_in6)) {
3527 return 0;
3529 sin6 = &si->myname.sa.in6;
3532 ZERO_STRUCT(pkt6);
3534 pkt6.ipi6_ifindex = socket_wrapper_default_iface();
3535 pkt6.ipi6_addr = sin6->sin6_addr;
3537 swrap_msghdr_add_cmsghdr(msg, IPPROTO_IPV6, IPV6_PKTINFO,
3538 &pkt6, sizeof(pkt6));
3539 #endif /* HAVE_STRUCT_IN6_PKTINFO */
3541 break;
3543 #endif /* IPV6_PKTINFO */
3544 default:
3545 return -1;
3548 return 0;
3551 static int swrap_msghdr_add_socket_info(struct socket_info *si,
3552 struct msghdr *omsg)
3554 int rc = 0;
3556 if (si->pktinfo > 0) {
3557 rc = swrap_msghdr_add_pktinfo(si, omsg);
3560 return rc;
3563 static int swrap_sendmsg_copy_cmsg(struct cmsghdr *cmsg,
3564 uint8_t **cm_data,
3565 size_t *cm_data_space);
3566 static int swrap_sendmsg_filter_cmsg_socket(struct cmsghdr *cmsg,
3567 uint8_t **cm_data,
3568 size_t *cm_data_space);
3570 static int swrap_sendmsg_filter_cmsghdr(struct msghdr *msg,
3571 uint8_t **cm_data,
3572 size_t *cm_data_space) {
3573 struct cmsghdr *cmsg;
3574 int rc = -1;
3576 /* Nothing to do */
3577 if (msg->msg_controllen == 0 || msg->msg_control == NULL) {
3578 return 0;
3581 for (cmsg = CMSG_FIRSTHDR(msg);
3582 cmsg != NULL;
3583 cmsg = CMSG_NXTHDR(msg, cmsg)) {
3584 switch (cmsg->cmsg_level) {
3585 case IPPROTO_IP:
3586 rc = swrap_sendmsg_filter_cmsg_socket(cmsg,
3587 cm_data,
3588 cm_data_space);
3589 break;
3590 default:
3591 rc = swrap_sendmsg_copy_cmsg(cmsg,
3592 cm_data,
3593 cm_data_space);
3594 break;
3598 return rc;
3601 static int swrap_sendmsg_copy_cmsg(struct cmsghdr *cmsg,
3602 uint8_t **cm_data,
3603 size_t *cm_data_space)
3605 size_t cmspace;
3606 uint8_t *p;
3608 cmspace =
3609 (*cm_data_space) +
3610 CMSG_SPACE(cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)));
3612 p = realloc((*cm_data), cmspace);
3613 if (p == NULL) {
3614 return -1;
3616 (*cm_data) = p;
3618 p = (*cm_data) + (*cm_data_space);
3619 *cm_data_space = cmspace;
3621 memcpy(p, cmsg, cmsg->cmsg_len);
3623 return 0;
3626 static int swrap_sendmsg_filter_cmsg_pktinfo(struct cmsghdr *cmsg,
3627 uint8_t **cm_data,
3628 size_t *cm_data_space);
3631 static int swrap_sendmsg_filter_cmsg_socket(struct cmsghdr *cmsg,
3632 uint8_t **cm_data,
3633 size_t *cm_data_space)
3635 int rc = -1;
3637 switch(cmsg->cmsg_type) {
3638 #ifdef IP_PKTINFO
3639 case IP_PKTINFO:
3640 rc = swrap_sendmsg_filter_cmsg_pktinfo(cmsg,
3641 cm_data,
3642 cm_data_space);
3643 break;
3644 #endif
3645 #ifdef IPV6_PKTINFO
3646 case IPV6_PKTINFO:
3647 rc = swrap_sendmsg_filter_cmsg_pktinfo(cmsg,
3648 cm_data,
3649 cm_data_space);
3650 break;
3651 #endif
3652 default:
3653 break;
3656 return rc;
3659 static int swrap_sendmsg_filter_cmsg_pktinfo(struct cmsghdr *cmsg,
3660 uint8_t **cm_data,
3661 size_t *cm_data_space)
3663 (void)cmsg; /* unused */
3664 (void)cm_data; /* unused */
3665 (void)cm_data_space; /* unused */
3668 * Passing a IP pktinfo to a unix socket might be rejected by the
3669 * Kernel, at least on FreeBSD. So skip this cmsg.
3671 return 0;
3673 #endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
3675 static ssize_t swrap_sendmsg_before(int fd,
3676 struct socket_info *si,
3677 struct msghdr *msg,
3678 struct iovec *tmp_iov,
3679 struct sockaddr_un *tmp_un,
3680 const struct sockaddr_un **to_un,
3681 const struct sockaddr **to,
3682 int *bcast)
3684 size_t i, len = 0;
3685 ssize_t ret;
3687 if (to_un) {
3688 *to_un = NULL;
3690 if (to) {
3691 *to = NULL;
3693 if (bcast) {
3694 *bcast = 0;
3697 switch (si->type) {
3698 case SOCK_STREAM:
3699 if (!si->connected) {
3700 errno = ENOTCONN;
3701 return -1;
3704 if (msg->msg_iovlen == 0) {
3705 break;
3708 for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
3709 size_t nlen;
3710 nlen = len + msg->msg_iov[i].iov_len;
3711 if (nlen > SOCKET_MAX_PACKET) {
3712 break;
3715 msg->msg_iovlen = i;
3716 if (msg->msg_iovlen == 0) {
3717 *tmp_iov = msg->msg_iov[0];
3718 tmp_iov->iov_len = MIN(tmp_iov->iov_len, SOCKET_MAX_PACKET);
3719 msg->msg_iov = tmp_iov;
3720 msg->msg_iovlen = 1;
3722 break;
3724 case SOCK_DGRAM:
3725 if (si->connected) {
3726 if (msg->msg_name) {
3727 errno = EISCONN;
3728 return -1;
3730 } else {
3731 const struct sockaddr *msg_name;
3732 msg_name = (const struct sockaddr *)msg->msg_name;
3734 if (msg_name == NULL) {
3735 errno = ENOTCONN;
3736 return -1;
3740 ret = sockaddr_convert_to_un(si, msg_name, msg->msg_namelen,
3741 tmp_un, 0, bcast);
3742 if (ret == -1) return -1;
3744 if (to_un) {
3745 *to_un = tmp_un;
3747 if (to) {
3748 *to = msg_name;
3750 msg->msg_name = tmp_un;
3751 msg->msg_namelen = sizeof(*tmp_un);
3754 if (si->bound == 0) {
3755 ret = swrap_auto_bind(fd, si, si->family);
3756 if (ret == -1) {
3757 if (errno == ENOTSOCK) {
3758 swrap_remove_stale(fd);
3759 return -ENOTSOCK;
3760 } else {
3761 SWRAP_LOG(SWRAP_LOG_ERROR, "swrap_sendmsg_before failed");
3762 return -1;
3767 if (!si->defer_connect) {
3768 break;
3771 ret = sockaddr_convert_to_un(si,
3772 &si->peername.sa.s,
3773 si->peername.sa_socklen,
3774 tmp_un,
3776 NULL);
3777 if (ret == -1) return -1;
3779 ret = libc_connect(fd,
3780 (struct sockaddr *)(void *)tmp_un,
3781 sizeof(*tmp_un));
3783 /* to give better errors */
3784 if (ret == -1 && errno == ENOENT) {
3785 errno = EHOSTUNREACH;
3788 if (ret == -1) {
3789 return ret;
3792 si->defer_connect = 0;
3793 break;
3794 default:
3795 errno = EHOSTUNREACH;
3796 return -1;
3799 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
3800 if (msg->msg_controllen > 0 && msg->msg_control != NULL) {
3801 uint8_t *cmbuf = NULL;
3802 size_t cmlen = 0;
3804 ret = swrap_sendmsg_filter_cmsghdr(msg, &cmbuf, &cmlen);
3805 if (ret < 0) {
3806 free(cmbuf);
3807 return -1;
3810 if (cmlen == 0) {
3811 msg->msg_controllen = 0;
3812 msg->msg_control = NULL;
3813 } else if (cmlen < msg->msg_controllen && cmbuf != NULL) {
3814 memcpy(msg->msg_control, cmbuf, cmlen);
3815 msg->msg_controllen = cmlen;
3817 free(cmbuf);
3819 #endif
3821 return 0;
3824 static void swrap_sendmsg_after(int fd,
3825 struct socket_info *si,
3826 struct msghdr *msg,
3827 const struct sockaddr *to,
3828 ssize_t ret)
3830 int saved_errno = errno;
3831 size_t i, len = 0;
3832 uint8_t *buf;
3833 off_t ofs = 0;
3834 size_t avail = 0;
3835 size_t remain;
3837 /* to give better errors */
3838 if (ret == -1) {
3839 if (saved_errno == ENOENT) {
3840 saved_errno = EHOSTUNREACH;
3841 } else if (saved_errno == ENOTSOCK) {
3842 /* If the fd is not a socket, remove it */
3843 swrap_remove_stale(fd);
3847 for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
3848 avail += msg->msg_iov[i].iov_len;
3851 if (ret == -1) {
3852 remain = MIN(80, avail);
3853 } else {
3854 remain = ret;
3857 /* we capture it as one single packet */
3858 buf = (uint8_t *)malloc(remain);
3859 if (!buf) {
3860 /* we just not capture the packet */
3861 errno = saved_errno;
3862 return;
3865 for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
3866 size_t this_time = MIN(remain, (size_t)msg->msg_iov[i].iov_len);
3867 memcpy(buf + ofs,
3868 msg->msg_iov[i].iov_base,
3869 this_time);
3870 ofs += this_time;
3871 remain -= this_time;
3873 len = ofs;
3875 switch (si->type) {
3876 case SOCK_STREAM:
3877 if (ret == -1) {
3878 swrap_pcap_dump_packet(si, NULL, SWRAP_SEND, buf, len);
3879 swrap_pcap_dump_packet(si, NULL, SWRAP_SEND_RST, NULL, 0);
3880 } else {
3881 swrap_pcap_dump_packet(si, NULL, SWRAP_SEND, buf, len);
3883 break;
3885 case SOCK_DGRAM:
3886 if (si->connected) {
3887 to = &si->peername.sa.s;
3889 if (ret == -1) {
3890 swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
3891 swrap_pcap_dump_packet(si, to, SWRAP_SENDTO_UNREACH, buf, len);
3892 } else {
3893 swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
3895 break;
3898 free(buf);
3899 errno = saved_errno;
3902 static int swrap_recvmsg_before(int fd,
3903 struct socket_info *si,
3904 struct msghdr *msg,
3905 struct iovec *tmp_iov)
3907 size_t i, len = 0;
3908 ssize_t ret;
3910 (void)fd; /* unused */
3912 switch (si->type) {
3913 case SOCK_STREAM:
3914 if (!si->connected) {
3915 errno = ENOTCONN;
3916 return -1;
3919 if (msg->msg_iovlen == 0) {
3920 break;
3923 for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
3924 size_t nlen;
3925 nlen = len + msg->msg_iov[i].iov_len;
3926 if (nlen > SOCKET_MAX_PACKET) {
3927 break;
3930 msg->msg_iovlen = i;
3931 if (msg->msg_iovlen == 0) {
3932 *tmp_iov = msg->msg_iov[0];
3933 tmp_iov->iov_len = MIN(tmp_iov->iov_len, SOCKET_MAX_PACKET);
3934 msg->msg_iov = tmp_iov;
3935 msg->msg_iovlen = 1;
3937 break;
3939 case SOCK_DGRAM:
3940 if (msg->msg_name == NULL) {
3941 errno = EINVAL;
3942 return -1;
3945 if (msg->msg_iovlen == 0) {
3946 break;
3949 if (si->bound == 0) {
3950 ret = swrap_auto_bind(fd, si, si->family);
3951 if (ret == -1) {
3953 * When attempting to read or write to a
3954 * descriptor, if an underlying autobind fails
3955 * because it's not a socket, stop intercepting
3956 * uses of that descriptor.
3958 if (errno == ENOTSOCK) {
3959 swrap_remove_stale(fd);
3960 return -ENOTSOCK;
3961 } else {
3962 SWRAP_LOG(SWRAP_LOG_ERROR,
3963 "swrap_recvmsg_before failed");
3964 return -1;
3968 break;
3969 default:
3970 errno = EHOSTUNREACH;
3971 return -1;
3974 return 0;
3977 static int swrap_recvmsg_after(int fd,
3978 struct socket_info *si,
3979 struct msghdr *msg,
3980 const struct sockaddr_un *un_addr,
3981 socklen_t un_addrlen,
3982 ssize_t ret)
3984 int saved_errno = errno;
3985 size_t i;
3986 uint8_t *buf = NULL;
3987 off_t ofs = 0;
3988 size_t avail = 0;
3989 size_t remain;
3990 int rc;
3992 /* to give better errors */
3993 if (ret == -1) {
3994 if (saved_errno == ENOENT) {
3995 saved_errno = EHOSTUNREACH;
3996 } else if (saved_errno == ENOTSOCK) {
3997 /* If the fd is not a socket, remove it */
3998 swrap_remove_stale(fd);
4002 for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
4003 avail += msg->msg_iov[i].iov_len;
4006 if (avail == 0) {
4007 rc = 0;
4008 goto done;
4011 if (ret == -1) {
4012 remain = MIN(80, avail);
4013 } else {
4014 remain = ret;
4017 /* we capture it as one single packet */
4018 buf = (uint8_t *)malloc(remain);
4019 if (buf == NULL) {
4020 /* we just not capture the packet */
4021 errno = saved_errno;
4022 return -1;
4025 for (i = 0; i < (size_t)msg->msg_iovlen; i++) {
4026 size_t this_time = MIN(remain, (size_t)msg->msg_iov[i].iov_len);
4027 memcpy(buf + ofs,
4028 msg->msg_iov[i].iov_base,
4029 this_time);
4030 ofs += this_time;
4031 remain -= this_time;
4034 switch (si->type) {
4035 case SOCK_STREAM:
4036 if (ret == -1 && saved_errno != EAGAIN && saved_errno != ENOBUFS) {
4037 swrap_pcap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
4038 } else if (ret == 0) { /* END OF FILE */
4039 swrap_pcap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
4040 } else if (ret > 0) {
4041 swrap_pcap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
4043 break;
4045 case SOCK_DGRAM:
4046 if (ret == -1) {
4047 break;
4050 if (un_addr != NULL) {
4051 rc = sockaddr_convert_from_un(si,
4052 un_addr,
4053 un_addrlen,
4054 si->family,
4055 msg->msg_name,
4056 &msg->msg_namelen);
4057 if (rc == -1) {
4058 goto done;
4061 swrap_pcap_dump_packet(si,
4062 msg->msg_name,
4063 SWRAP_RECVFROM,
4064 buf,
4065 ret);
4066 } else {
4067 swrap_pcap_dump_packet(si,
4068 msg->msg_name,
4069 SWRAP_RECV,
4070 buf,
4071 ret);
4074 break;
4077 rc = 0;
4078 done:
4079 free(buf);
4080 errno = saved_errno;
4082 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4083 if (rc == 0 &&
4084 msg->msg_controllen > 0 &&
4085 msg->msg_control != NULL) {
4086 rc = swrap_msghdr_add_socket_info(si, msg);
4087 if (rc < 0) {
4088 return -1;
4091 #endif
4093 return rc;
4096 /****************************************************************************
4097 * RECVFROM
4098 ***************************************************************************/
4100 static ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags,
4101 struct sockaddr *from, socklen_t *fromlen)
4103 struct swrap_address from_addr = {
4104 .sa_socklen = sizeof(struct sockaddr_un),
4106 ssize_t ret;
4107 struct socket_info *si = find_socket_info(s);
4108 struct swrap_address saddr = {
4109 .sa_socklen = sizeof(struct sockaddr_storage),
4111 struct msghdr msg;
4112 struct iovec tmp;
4113 int tret;
4115 if (!si) {
4116 return libc_recvfrom(s,
4117 buf,
4118 len,
4119 flags,
4120 from,
4121 fromlen);
4124 tmp.iov_base = buf;
4125 tmp.iov_len = len;
4127 ZERO_STRUCT(msg);
4128 if (from != NULL && fromlen != NULL) {
4129 msg.msg_name = from; /* optional address */
4130 msg.msg_namelen = *fromlen; /* size of address */
4131 } else {
4132 msg.msg_name = &saddr.sa.s; /* optional address */
4133 msg.msg_namelen = saddr.sa_socklen; /* size of address */
4135 msg.msg_iov = &tmp; /* scatter/gather array */
4136 msg.msg_iovlen = 1; /* # elements in msg_iov */
4137 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4138 msg.msg_control = NULL; /* ancillary data, see below */
4139 msg.msg_controllen = 0; /* ancillary data buffer len */
4140 msg.msg_flags = 0; /* flags on received message */
4141 #endif
4143 tret = swrap_recvmsg_before(s, si, &msg, &tmp);
4144 if (tret < 0) {
4145 return -1;
4148 buf = msg.msg_iov[0].iov_base;
4149 len = msg.msg_iov[0].iov_len;
4151 ret = libc_recvfrom(s,
4152 buf,
4153 len,
4154 flags,
4155 &from_addr.sa.s,
4156 &from_addr.sa_socklen);
4157 if (ret == -1) {
4158 return ret;
4161 tret = swrap_recvmsg_after(s,
4163 &msg,
4164 &from_addr.sa.un,
4165 from_addr.sa_socklen,
4166 ret);
4167 if (tret != 0) {
4168 return tret;
4171 if (from != NULL && fromlen != NULL) {
4172 *fromlen = msg.msg_namelen;
4175 return ret;
4178 #ifdef HAVE_ACCEPT_PSOCKLEN_T
4179 ssize_t recvfrom(int s, void *buf, size_t len, int flags,
4180 struct sockaddr *from, Psocklen_t fromlen)
4181 #else
4182 ssize_t recvfrom(int s, void *buf, size_t len, int flags,
4183 struct sockaddr *from, socklen_t *fromlen)
4184 #endif
4186 return swrap_recvfrom(s, buf, len, flags, from, (socklen_t *)fromlen);
4189 /****************************************************************************
4190 * SENDTO
4191 ***************************************************************************/
4193 static ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags,
4194 const struct sockaddr *to, socklen_t tolen)
4196 struct msghdr msg;
4197 struct iovec tmp;
4198 struct swrap_address un_addr = {
4199 .sa_socklen = sizeof(struct sockaddr_un),
4201 const struct sockaddr_un *to_un = NULL;
4202 ssize_t ret;
4203 int rc;
4204 struct socket_info *si = find_socket_info(s);
4205 int bcast = 0;
4207 if (!si) {
4208 return libc_sendto(s, buf, len, flags, to, tolen);
4211 tmp.iov_base = discard_const_p(char, buf);
4212 tmp.iov_len = len;
4214 ZERO_STRUCT(msg);
4215 msg.msg_name = discard_const_p(struct sockaddr, to); /* optional address */
4216 msg.msg_namelen = tolen; /* size of address */
4217 msg.msg_iov = &tmp; /* scatter/gather array */
4218 msg.msg_iovlen = 1; /* # elements in msg_iov */
4219 #if HAVE_STRUCT_MSGHDR_MSG_CONTROL
4220 msg.msg_control = NULL; /* ancillary data, see below */
4221 msg.msg_controllen = 0; /* ancillary data buffer len */
4222 msg.msg_flags = 0; /* flags on received message */
4223 #endif
4225 rc = swrap_sendmsg_before(s,
4227 &msg,
4228 &tmp,
4229 &un_addr.sa.un,
4230 &to_un,
4231 &to,
4232 &bcast);
4233 if (rc < 0) {
4234 return -1;
4237 buf = msg.msg_iov[0].iov_base;
4238 len = msg.msg_iov[0].iov_len;
4240 if (bcast) {
4241 struct stat st;
4242 unsigned int iface;
4243 unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
4244 char type;
4246 type = SOCKET_TYPE_CHAR_UDP;
4248 for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
4249 snprintf(un_addr.sa.un.sun_path,
4250 sizeof(un_addr.sa.un.sun_path),
4251 "%s/"SOCKET_FORMAT,
4252 socket_wrapper_dir(), type, iface, prt);
4253 if (stat(un_addr.sa.un.sun_path, &st) != 0) continue;
4255 /* ignore the any errors in broadcast sends */
4256 libc_sendto(s,
4257 buf,
4258 len,
4259 flags,
4260 &un_addr.sa.s,
4261 un_addr.sa_socklen);
4264 swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
4266 return len;
4269 ret = libc_sendto(s,
4270 buf,
4271 len,
4272 flags,
4273 (struct sockaddr *)msg.msg_name,
4274 msg.msg_namelen);
4276 swrap_sendmsg_after(s, si, &msg, to, ret);
4278 return ret;
4281 ssize_t sendto(int s, const void *buf, size_t len, int flags,
4282 const struct sockaddr *to, socklen_t tolen)
4284 return swrap_sendto(s, buf, len, flags, to, tolen);
4287 /****************************************************************************
4288 * READV
4289 ***************************************************************************/
4291 static ssize_t swrap_recv(int s, void *buf, size_t len, int flags)
4293 struct socket_info *si;
4294 struct msghdr msg;
4295 struct swrap_address saddr = {
4296 .sa_socklen = sizeof(struct sockaddr_storage),
4298 struct iovec tmp;
4299 ssize_t ret;
4300 int tret;
4302 si = find_socket_info(s);
4303 if (si == NULL) {
4304 return libc_recv(s, buf, len, flags);
4307 tmp.iov_base = buf;
4308 tmp.iov_len = len;
4310 ZERO_STRUCT(msg);
4311 msg.msg_name = &saddr.sa.s; /* optional address */
4312 msg.msg_namelen = saddr.sa_socklen; /* size of address */
4313 msg.msg_iov = &tmp; /* scatter/gather array */
4314 msg.msg_iovlen = 1; /* # elements in msg_iov */
4315 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4316 msg.msg_control = NULL; /* ancillary data, see below */
4317 msg.msg_controllen = 0; /* ancillary data buffer len */
4318 msg.msg_flags = 0; /* flags on received message */
4319 #endif
4321 tret = swrap_recvmsg_before(s, si, &msg, &tmp);
4322 if (tret < 0) {
4323 return -1;
4326 buf = msg.msg_iov[0].iov_base;
4327 len = msg.msg_iov[0].iov_len;
4329 ret = libc_recv(s, buf, len, flags);
4331 tret = swrap_recvmsg_after(s, si, &msg, NULL, 0, ret);
4332 if (tret != 0) {
4333 return tret;
4336 return ret;
4339 ssize_t recv(int s, void *buf, size_t len, int flags)
4341 return swrap_recv(s, buf, len, flags);
4344 /****************************************************************************
4345 * READ
4346 ***************************************************************************/
4348 static ssize_t swrap_read(int s, void *buf, size_t len)
4350 struct socket_info *si;
4351 struct msghdr msg;
4352 struct iovec tmp;
4353 struct swrap_address saddr = {
4354 .sa_socklen = sizeof(struct sockaddr_storage),
4356 ssize_t ret;
4357 int tret;
4359 si = find_socket_info(s);
4360 if (si == NULL) {
4361 return libc_read(s, buf, len);
4364 tmp.iov_base = buf;
4365 tmp.iov_len = len;
4367 ZERO_STRUCT(msg);
4368 msg.msg_name = &saddr.sa.ss; /* optional address */
4369 msg.msg_namelen = saddr.sa_socklen; /* size of address */
4370 msg.msg_iov = &tmp; /* scatter/gather array */
4371 msg.msg_iovlen = 1; /* # elements in msg_iov */
4372 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4373 msg.msg_control = NULL; /* ancillary data, see below */
4374 msg.msg_controllen = 0; /* ancillary data buffer len */
4375 msg.msg_flags = 0; /* flags on received message */
4376 #endif
4378 tret = swrap_recvmsg_before(s, si, &msg, &tmp);
4379 if (tret < 0) {
4380 if (tret == -ENOTSOCK) {
4381 return libc_read(s, buf, len);
4383 return -1;
4386 buf = msg.msg_iov[0].iov_base;
4387 len = msg.msg_iov[0].iov_len;
4389 ret = libc_read(s, buf, len);
4391 tret = swrap_recvmsg_after(s, si, &msg, NULL, 0, ret);
4392 if (tret != 0) {
4393 return tret;
4396 return ret;
4399 ssize_t read(int s, void *buf, size_t len)
4401 return swrap_read(s, buf, len);
4404 /****************************************************************************
4405 * SEND
4406 ***************************************************************************/
4408 static ssize_t swrap_send(int s, const void *buf, size_t len, int flags)
4410 struct msghdr msg;
4411 struct iovec tmp;
4412 struct sockaddr_un un_addr;
4413 ssize_t ret;
4414 int rc;
4415 struct socket_info *si = find_socket_info(s);
4417 if (!si) {
4418 return libc_send(s, buf, len, flags);
4421 tmp.iov_base = discard_const_p(char, buf);
4422 tmp.iov_len = len;
4424 ZERO_STRUCT(msg);
4425 msg.msg_name = NULL; /* optional address */
4426 msg.msg_namelen = 0; /* size of address */
4427 msg.msg_iov = &tmp; /* scatter/gather array */
4428 msg.msg_iovlen = 1; /* # elements in msg_iov */
4429 #if HAVE_STRUCT_MSGHDR_MSG_CONTROL
4430 msg.msg_control = NULL; /* ancillary data, see below */
4431 msg.msg_controllen = 0; /* ancillary data buffer len */
4432 msg.msg_flags = 0; /* flags on received message */
4433 #endif
4435 rc = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, NULL, NULL, NULL);
4436 if (rc < 0) {
4437 return -1;
4440 buf = msg.msg_iov[0].iov_base;
4441 len = msg.msg_iov[0].iov_len;
4443 ret = libc_send(s, buf, len, flags);
4445 swrap_sendmsg_after(s, si, &msg, NULL, ret);
4447 return ret;
4450 ssize_t send(int s, const void *buf, size_t len, int flags)
4452 return swrap_send(s, buf, len, flags);
4455 /****************************************************************************
4456 * RECVMSG
4457 ***************************************************************************/
4459 static ssize_t swrap_recvmsg(int s, struct msghdr *omsg, int flags)
4461 struct swrap_address from_addr = {
4462 .sa_socklen = sizeof(struct sockaddr_un),
4464 struct socket_info *si;
4465 struct msghdr msg;
4466 struct iovec tmp;
4467 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4468 size_t msg_ctrllen_filled;
4469 size_t msg_ctrllen_left;
4470 #endif
4472 ssize_t ret;
4473 int rc;
4475 si = find_socket_info(s);
4476 if (si == NULL) {
4477 return libc_recvmsg(s, omsg, flags);
4480 tmp.iov_base = NULL;
4481 tmp.iov_len = 0;
4483 ZERO_STRUCT(msg);
4484 msg.msg_name = &from_addr.sa; /* optional address */
4485 msg.msg_namelen = from_addr.sa_socklen; /* size of address */
4486 msg.msg_iov = omsg->msg_iov; /* scatter/gather array */
4487 msg.msg_iovlen = omsg->msg_iovlen; /* # elements in msg_iov */
4488 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4489 msg_ctrllen_filled = 0;
4490 msg_ctrllen_left = omsg->msg_controllen;
4492 msg.msg_control = omsg->msg_control; /* ancillary data, see below */
4493 msg.msg_controllen = omsg->msg_controllen; /* ancillary data buffer len */
4494 msg.msg_flags = omsg->msg_flags; /* flags on received message */
4495 #endif
4497 rc = swrap_recvmsg_before(s, si, &msg, &tmp);
4498 if (rc < 0) {
4499 return -1;
4502 ret = libc_recvmsg(s, &msg, flags);
4504 msg.msg_name = omsg->msg_name;
4505 msg.msg_namelen = omsg->msg_namelen;
4507 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4508 msg_ctrllen_filled += msg.msg_controllen;
4509 msg_ctrllen_left -= msg.msg_controllen;
4511 if (omsg->msg_control != NULL) {
4512 uint8_t *p;
4514 p = omsg->msg_control;
4515 p += msg_ctrllen_filled;
4517 msg.msg_control = p;
4518 msg.msg_controllen = msg_ctrllen_left;
4519 } else {
4520 msg.msg_control = NULL;
4521 msg.msg_controllen = 0;
4523 #endif
4525 rc = swrap_recvmsg_after(s,
4527 &msg,
4528 &from_addr.sa.un,
4529 from_addr.sa_socklen,
4530 ret);
4531 if (rc != 0) {
4532 return rc;
4535 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4536 if (omsg->msg_control != NULL) {
4537 /* msg.msg_controllen = space left */
4538 msg_ctrllen_left = msg.msg_controllen;
4539 msg_ctrllen_filled = omsg->msg_controllen - msg_ctrllen_left;
4542 /* Update the original message length */
4543 omsg->msg_controllen = msg_ctrllen_filled;
4544 omsg->msg_flags = msg.msg_flags;
4545 #endif
4546 omsg->msg_iovlen = msg.msg_iovlen;
4548 return ret;
4551 ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
4553 return swrap_recvmsg(sockfd, msg, flags);
4556 /****************************************************************************
4557 * SENDMSG
4558 ***************************************************************************/
4560 static ssize_t swrap_sendmsg(int s, const struct msghdr *omsg, int flags)
4562 struct msghdr msg;
4563 struct iovec tmp;
4564 struct sockaddr_un un_addr;
4565 const struct sockaddr_un *to_un = NULL;
4566 const struct sockaddr *to = NULL;
4567 ssize_t ret;
4568 int rc;
4569 struct socket_info *si = find_socket_info(s);
4570 int bcast = 0;
4572 if (!si) {
4573 return libc_sendmsg(s, omsg, flags);
4576 ZERO_STRUCT(un_addr);
4578 tmp.iov_base = NULL;
4579 tmp.iov_len = 0;
4581 ZERO_STRUCT(msg);
4582 msg.msg_name = omsg->msg_name; /* optional address */
4583 msg.msg_namelen = omsg->msg_namelen; /* size of address */
4584 msg.msg_iov = omsg->msg_iov; /* scatter/gather array */
4585 msg.msg_iovlen = omsg->msg_iovlen; /* # elements in msg_iov */
4586 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4587 if (msg.msg_controllen > 0 && msg.msg_control != NULL) {
4588 /* omsg is a const so use a local buffer for modifications */
4589 uint8_t cmbuf[omsg->msg_controllen];
4591 memcpy(cmbuf, omsg->msg_control, omsg->msg_controllen);
4593 msg.msg_control = cmbuf; /* ancillary data, see below */
4594 msg.msg_controllen = omsg->msg_controllen; /* ancillary data buffer len */
4596 msg.msg_flags = omsg->msg_flags; /* flags on received message */
4597 #endif
4599 rc = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, &to_un, &to, &bcast);
4600 if (rc < 0) {
4601 return -1;
4604 if (bcast) {
4605 struct stat st;
4606 unsigned int iface;
4607 unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
4608 char type;
4609 size_t i, len = 0;
4610 uint8_t *buf;
4611 off_t ofs = 0;
4612 size_t avail = 0;
4613 size_t remain;
4615 for (i = 0; i < (size_t)msg.msg_iovlen; i++) {
4616 avail += msg.msg_iov[i].iov_len;
4619 len = avail;
4620 remain = avail;
4622 /* we capture it as one single packet */
4623 buf = (uint8_t *)malloc(remain);
4624 if (!buf) {
4625 return -1;
4628 for (i = 0; i < (size_t)msg.msg_iovlen; i++) {
4629 size_t this_time = MIN(remain, (size_t)msg.msg_iov[i].iov_len);
4630 memcpy(buf + ofs,
4631 msg.msg_iov[i].iov_base,
4632 this_time);
4633 ofs += this_time;
4634 remain -= this_time;
4637 type = SOCKET_TYPE_CHAR_UDP;
4639 for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
4640 snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
4641 socket_wrapper_dir(), type, iface, prt);
4642 if (stat(un_addr.sun_path, &st) != 0) continue;
4644 msg.msg_name = &un_addr; /* optional address */
4645 msg.msg_namelen = sizeof(un_addr); /* size of address */
4647 /* ignore the any errors in broadcast sends */
4648 libc_sendmsg(s, &msg, flags);
4651 swrap_pcap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
4652 free(buf);
4654 return len;
4657 ret = libc_sendmsg(s, &msg, flags);
4659 swrap_sendmsg_after(s, si, &msg, to, ret);
4661 return ret;
4664 ssize_t sendmsg(int s, const struct msghdr *omsg, int flags)
4666 return swrap_sendmsg(s, omsg, flags);
4669 /****************************************************************************
4670 * READV
4671 ***************************************************************************/
4673 static ssize_t swrap_readv(int s, const struct iovec *vector, int count)
4675 struct socket_info *si;
4676 struct msghdr msg;
4677 struct iovec tmp;
4678 struct swrap_address saddr = {
4679 .sa_socklen = sizeof(struct sockaddr_storage)
4681 ssize_t ret;
4682 int rc;
4684 si = find_socket_info(s);
4685 if (si == NULL) {
4686 return libc_readv(s, vector, count);
4689 tmp.iov_base = NULL;
4690 tmp.iov_len = 0;
4692 ZERO_STRUCT(msg);
4693 msg.msg_name = &saddr.sa.s; /* optional address */
4694 msg.msg_namelen = saddr.sa_socklen; /* size of address */
4695 msg.msg_iov = discard_const_p(struct iovec, vector); /* scatter/gather array */
4696 msg.msg_iovlen = count; /* # elements in msg_iov */
4697 #ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
4698 msg.msg_control = NULL; /* ancillary data, see below */
4699 msg.msg_controllen = 0; /* ancillary data buffer len */
4700 msg.msg_flags = 0; /* flags on received message */
4701 #endif
4703 rc = swrap_recvmsg_before(s, si, &msg, &tmp);
4704 if (rc < 0) {
4705 if (rc == -ENOTSOCK) {
4706 return libc_readv(s, vector, count);
4708 return -1;
4711 ret = libc_readv(s, msg.msg_iov, msg.msg_iovlen);
4713 rc = swrap_recvmsg_after(s, si, &msg, NULL, 0, ret);
4714 if (rc != 0) {
4715 return rc;
4718 return ret;
4721 ssize_t readv(int s, const struct iovec *vector, int count)
4723 return swrap_readv(s, vector, count);
4726 /****************************************************************************
4727 * WRITEV
4728 ***************************************************************************/
4730 static ssize_t swrap_writev(int s, const struct iovec *vector, int count)
4732 struct msghdr msg;
4733 struct iovec tmp;
4734 struct sockaddr_un un_addr;
4735 ssize_t ret;
4736 int rc;
4737 struct socket_info *si = find_socket_info(s);
4739 if (!si) {
4740 return libc_writev(s, vector, count);
4743 tmp.iov_base = NULL;
4744 tmp.iov_len = 0;
4746 ZERO_STRUCT(msg);
4747 msg.msg_name = NULL; /* optional address */
4748 msg.msg_namelen = 0; /* size of address */
4749 msg.msg_iov = discard_const_p(struct iovec, vector); /* scatter/gather array */
4750 msg.msg_iovlen = count; /* # elements in msg_iov */
4751 #if HAVE_STRUCT_MSGHDR_MSG_CONTROL
4752 msg.msg_control = NULL; /* ancillary data, see below */
4753 msg.msg_controllen = 0; /* ancillary data buffer len */
4754 msg.msg_flags = 0; /* flags on received message */
4755 #endif
4757 rc = swrap_sendmsg_before(s, si, &msg, &tmp, &un_addr, NULL, NULL, NULL);
4758 if (rc < 0) {
4759 if (rc == -ENOTSOCK) {
4760 return libc_readv(s, vector, count);
4762 return -1;
4765 ret = libc_writev(s, msg.msg_iov, msg.msg_iovlen);
4767 swrap_sendmsg_after(s, si, &msg, NULL, ret);
4769 return ret;
4772 ssize_t writev(int s, const struct iovec *vector, int count)
4774 return swrap_writev(s, vector, count);
4777 /****************************
4778 * CLOSE
4779 ***************************/
4781 static int swrap_close(int fd)
4783 struct socket_info *si = find_socket_info(fd);
4784 struct socket_info_fd *fi;
4785 int ret;
4787 if (!si) {
4788 return libc_close(fd);
4791 for (fi = si->fds; fi; fi = fi->next) {
4792 if (fi->fd == fd) {
4793 SWRAP_DLIST_REMOVE(si->fds, fi);
4794 free(fi);
4795 break;
4799 if (si->fds) {
4800 /* there are still references left */
4801 return libc_close(fd);
4804 SWRAP_DLIST_REMOVE(sockets, si);
4806 if (si->myname.sa_socklen > 0 && si->peername.sa_socklen > 0) {
4807 swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_SEND, NULL, 0);
4810 ret = libc_close(fd);
4812 if (si->myname.sa_socklen > 0 && si->peername.sa_socklen > 0) {
4813 swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_RECV, NULL, 0);
4814 swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_ACK, NULL, 0);
4817 if (si->un_addr.sun_path[0] != '\0') {
4818 unlink(si->un_addr.sun_path);
4820 free(si);
4822 return ret;
4825 int close(int fd)
4827 return swrap_close(fd);
4830 /****************************
4831 * DUP
4832 ***************************/
4834 static int swrap_dup(int fd)
4836 struct socket_info *si;
4837 struct socket_info_fd *fi;
4839 si = find_socket_info(fd);
4841 if (!si) {
4842 return libc_dup(fd);
4845 fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
4846 if (fi == NULL) {
4847 errno = ENOMEM;
4848 return -1;
4851 fi->fd = libc_dup(fd);
4852 if (fi->fd == -1) {
4853 int saved_errno = errno;
4854 free(fi);
4855 errno = saved_errno;
4856 return -1;
4859 /* Make sure we don't have an entry for the fd */
4860 swrap_remove_stale(fi->fd);
4862 SWRAP_DLIST_ADD(si->fds, fi);
4863 return fi->fd;
4866 int dup(int fd)
4868 return swrap_dup(fd);
4871 /****************************
4872 * DUP2
4873 ***************************/
4875 static int swrap_dup2(int fd, int newfd)
4877 struct socket_info *si;
4878 struct socket_info_fd *fi;
4880 si = find_socket_info(fd);
4882 if (!si) {
4883 return libc_dup2(fd, newfd);
4886 if (find_socket_info(newfd)) {
4887 /* dup2() does an implicit close of newfd, which we
4888 * need to emulate */
4889 swrap_close(newfd);
4892 fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
4893 if (fi == NULL) {
4894 errno = ENOMEM;
4895 return -1;
4898 fi->fd = libc_dup2(fd, newfd);
4899 if (fi->fd == -1) {
4900 int saved_errno = errno;
4901 free(fi);
4902 errno = saved_errno;
4903 return -1;
4906 /* Make sure we don't have an entry for the fd */
4907 swrap_remove_stale(fi->fd);
4909 SWRAP_DLIST_ADD(si->fds, fi);
4910 return fi->fd;
4913 int dup2(int fd, int newfd)
4915 return swrap_dup2(fd, newfd);
4918 /****************************
4919 * DUP2
4920 ***************************/
4922 #ifdef HAVE_EVENTFD
4923 static int swrap_eventfd(int count, int flags)
4925 int fd;
4927 fd = libc_eventfd(count, flags);
4928 if (fd != -1) {
4929 swrap_remove_stale(fd);
4932 return fd;
4935 int eventfd(int count, int flags)
4937 return swrap_eventfd(count, flags);
4939 #endif
4941 /****************************
4942 * DESTRUCTOR
4943 ***************************/
4946 * This function is called when the library is unloaded and makes sure that
4947 * sockets get closed and the unix file for the socket are unlinked.
4949 void swrap_destructor(void)
4951 struct socket_info *s = sockets;
4953 while (s != NULL) {
4954 struct socket_info_fd *f = s->fds;
4955 if (f != NULL) {
4956 swrap_close(f->fd);
4958 s = sockets;