s4-provision: Extract dns account creation as separate ldif
[Samba.git] / lib / socket_wrapper / socket_wrapper.c
blob946980963edce71d1cf399bcecc240ba9af99e41
1 /*
2 * Copyright (C) Jelmer Vernooij 2005,2008 <jelmer@samba.org>
3 * Copyright (C) Stefan Metzmacher 2006-2009 <metze@samba.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the author nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
37 Socket wrapper library. Passes all socket communication over
38 unix domain sockets if the environment variable SOCKET_WRAPPER_DIR
39 is set.
42 #ifdef _SAMBA_BUILD_
44 #define SOCKET_WRAPPER_NOT_REPLACE
45 #include "../replace/replace.h"
46 #include "system/network.h"
47 #include "system/filesys.h"
48 #include "system/time.h"
50 #else /* _SAMBA_BUILD_ */
52 #include <sys/types.h>
53 #include <sys/time.h>
54 #include <sys/stat.h>
55 #include <sys/socket.h>
56 #include <sys/ioctl.h>
57 #include <sys/filio.h>
58 #include <errno.h>
59 #include <sys/un.h>
60 #include <netinet/in.h>
61 #include <netinet/tcp.h>
62 #include <fcntl.h>
63 #include <stdlib.h>
64 #include <unistd.h>
65 #include <string.h>
66 #include <stdio.h>
67 #include <stdint.h>
69 #endif
71 #ifndef _PUBLIC_
72 #define _PUBLIC_
73 #endif
75 #define SWRAP_DLIST_ADD(list,item) do { \
76 if (!(list)) { \
77 (item)->prev = NULL; \
78 (item)->next = NULL; \
79 (list) = (item); \
80 } else { \
81 (item)->prev = NULL; \
82 (item)->next = (list); \
83 (list)->prev = (item); \
84 (list) = (item); \
85 } \
86 } while (0)
88 #define SWRAP_DLIST_REMOVE(list,item) do { \
89 if ((list) == (item)) { \
90 (list) = (item)->next; \
91 if (list) { \
92 (list)->prev = NULL; \
93 } \
94 } else { \
95 if ((item)->prev) { \
96 (item)->prev->next = (item)->next; \
97 } \
98 if ((item)->next) { \
99 (item)->next->prev = (item)->prev; \
102 (item)->prev = NULL; \
103 (item)->next = NULL; \
104 } while (0)
106 /* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support
107 * for now */
108 #define REWRITE_CALLS
110 #ifdef REWRITE_CALLS
111 #define real_accept accept
112 #define real_connect connect
113 #define real_bind bind
114 #define real_listen listen
115 #define real_getpeername getpeername
116 #define real_getsockname getsockname
117 #define real_getsockopt getsockopt
118 #define real_setsockopt setsockopt
119 #define real_recvfrom recvfrom
120 #define real_sendto sendto
121 #define real_sendmsg sendmsg
122 #define real_ioctl ioctl
123 #define real_recv recv
124 #define real_read read
125 #define real_send send
126 #define real_readv readv
127 #define real_writev writev
128 #define real_socket socket
129 #define real_close close
130 #define real_dup dup
131 #define real_dup2 dup2
132 #endif
134 #ifdef HAVE_GETTIMEOFDAY_TZ
135 #define swrapGetTimeOfDay(tval) gettimeofday(tval,NULL)
136 #else
137 #define swrapGetTimeOfDay(tval) gettimeofday(tval)
138 #endif
140 /* we need to use a very terse format here as IRIX 6.4 silently
141 truncates names to 16 chars, so if we use a longer name then we
142 can't tell which port a packet came from with recvfrom()
144 with this format we have 8 chars left for the directory name
146 #define SOCKET_FORMAT "%c%02X%04X"
147 #define SOCKET_TYPE_CHAR_TCP 'T'
148 #define SOCKET_TYPE_CHAR_UDP 'U'
149 #define SOCKET_TYPE_CHAR_TCP_V6 'X'
150 #define SOCKET_TYPE_CHAR_UDP_V6 'Y'
152 /* This limit is to avoid broadcast sendto() needing to stat too many
153 * files. It may be raised (with a performance cost) to up to 254
154 * without changing the format above */
155 #define MAX_WRAPPED_INTERFACES 32
157 #ifdef HAVE_IPV6
159 * FD00::5357:5FXX
161 static const struct in6_addr *swrap_ipv6(void)
163 static struct in6_addr v;
164 static int initialized;
165 int ret;
167 if (initialized) {
168 return &v;
170 initialized = 1;
172 ret = inet_pton(AF_INET6, "FD00::5357:5F00", &v);
173 if (ret <= 0) {
174 abort();
177 return &v;
179 #endif
181 static struct sockaddr *sockaddr_dup(const void *data, socklen_t len)
183 struct sockaddr *ret = (struct sockaddr *)malloc(len);
184 memcpy(ret, data, len);
185 return ret;
188 static void set_port(int family, int prt, struct sockaddr *addr)
190 switch (family) {
191 case AF_INET:
192 ((struct sockaddr_in *)addr)->sin_port = htons(prt);
193 break;
194 #ifdef HAVE_IPV6
195 case AF_INET6:
196 ((struct sockaddr_in6 *)addr)->sin6_port = htons(prt);
197 break;
198 #endif
202 static size_t socket_length(int family)
204 switch (family) {
205 case AF_INET:
206 return sizeof(struct sockaddr_in);
207 #ifdef HAVE_IPV6
208 case AF_INET6:
209 return sizeof(struct sockaddr_in6);
210 #endif
212 return 0;
217 struct socket_info
219 int fd;
221 int family;
222 int type;
223 int protocol;
224 int bound;
225 int bcast;
226 int is_server;
227 int connected;
228 int defer_connect;
230 char *tmp_path;
232 struct sockaddr *myname;
233 socklen_t myname_len;
235 struct sockaddr *peername;
236 socklen_t peername_len;
238 struct {
239 unsigned long pck_snd;
240 unsigned long pck_rcv;
241 } io;
243 struct socket_info *prev, *next;
246 static struct socket_info *sockets;
248 const char *socket_wrapper_dir(void)
250 const char *s = getenv("SOCKET_WRAPPER_DIR");
251 if (s == NULL) {
252 return NULL;
254 if (strncmp(s, "./", 2) == 0) {
255 s += 2;
257 return s;
260 unsigned int socket_wrapper_default_iface(void)
262 const char *s = getenv("SOCKET_WRAPPER_DEFAULT_IFACE");
263 if (s) {
264 unsigned int iface;
265 if (sscanf(s, "%u", &iface) == 1) {
266 if (iface >= 1 && iface <= MAX_WRAPPED_INTERFACES) {
267 return iface;
272 return 1;/* 127.0.0.1 */
275 static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, socklen_t *len)
277 unsigned int iface;
278 unsigned int prt;
279 const char *p;
280 char type;
282 p = strrchr(un->sun_path, '/');
283 if (p) p++; else p = un->sun_path;
285 if (sscanf(p, SOCKET_FORMAT, &type, &iface, &prt) != 3) {
286 errno = EINVAL;
287 return -1;
290 if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) {
291 errno = EINVAL;
292 return -1;
295 if (prt > 0xFFFF) {
296 errno = EINVAL;
297 return -1;
300 switch(type) {
301 case SOCKET_TYPE_CHAR_TCP:
302 case SOCKET_TYPE_CHAR_UDP: {
303 struct sockaddr_in *in2 = (struct sockaddr_in *)(void *)in;
305 if ((*len) < sizeof(*in2)) {
306 errno = EINVAL;
307 return -1;
310 memset(in2, 0, sizeof(*in2));
311 in2->sin_family = AF_INET;
312 in2->sin_addr.s_addr = htonl((127<<24) | iface);
313 in2->sin_port = htons(prt);
315 *len = sizeof(*in2);
316 break;
318 #ifdef HAVE_IPV6
319 case SOCKET_TYPE_CHAR_TCP_V6:
320 case SOCKET_TYPE_CHAR_UDP_V6: {
321 struct sockaddr_in6 *in2 = (struct sockaddr_in6 *)(void *)in;
323 if ((*len) < sizeof(*in2)) {
324 errno = EINVAL;
325 return -1;
328 memset(in2, 0, sizeof(*in2));
329 in2->sin6_family = AF_INET6;
330 in2->sin6_addr = *swrap_ipv6();
331 in2->sin6_addr.s6_addr[15] = iface;
332 in2->sin6_port = htons(prt);
334 *len = sizeof(*in2);
335 break;
337 #endif
338 default:
339 errno = EINVAL;
340 return -1;
343 return 0;
346 static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un,
347 int *bcast)
349 char type = '\0';
350 unsigned int prt;
351 unsigned int iface;
352 int is_bcast = 0;
354 if (bcast) *bcast = 0;
356 switch (inaddr->sa_family) {
357 case AF_INET: {
358 const struct sockaddr_in *in =
359 (const struct sockaddr_in *)(const void *)inaddr;
360 unsigned int addr = ntohl(in->sin_addr.s_addr);
361 char u_type = '\0';
362 char b_type = '\0';
363 char a_type = '\0';
365 switch (si->type) {
366 case SOCK_STREAM:
367 u_type = SOCKET_TYPE_CHAR_TCP;
368 break;
369 case SOCK_DGRAM:
370 u_type = SOCKET_TYPE_CHAR_UDP;
371 a_type = SOCKET_TYPE_CHAR_UDP;
372 b_type = SOCKET_TYPE_CHAR_UDP;
373 break;
376 prt = ntohs(in->sin_port);
377 if (a_type && addr == 0xFFFFFFFF) {
378 /* 255.255.255.255 only udp */
379 is_bcast = 2;
380 type = a_type;
381 iface = socket_wrapper_default_iface();
382 } else if (b_type && addr == 0x7FFFFFFF) {
383 /* 127.255.255.255 only udp */
384 is_bcast = 1;
385 type = b_type;
386 iface = socket_wrapper_default_iface();
387 } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
388 /* 127.0.0.X */
389 is_bcast = 0;
390 type = u_type;
391 iface = (addr & 0x000000FF);
392 } else {
393 errno = ENETUNREACH;
394 return -1;
396 if (bcast) *bcast = is_bcast;
397 break;
399 #ifdef HAVE_IPV6
400 case AF_INET6: {
401 const struct sockaddr_in6 *in =
402 (const struct sockaddr_in6 *)(const void *)inaddr;
403 struct in6_addr cmp1, cmp2;
405 switch (si->type) {
406 case SOCK_STREAM:
407 type = SOCKET_TYPE_CHAR_TCP_V6;
408 break;
409 case SOCK_DGRAM:
410 type = SOCKET_TYPE_CHAR_UDP_V6;
411 break;
414 /* XXX no multicast/broadcast */
416 prt = ntohs(in->sin6_port);
418 cmp1 = *swrap_ipv6();
419 cmp2 = in->sin6_addr;
420 cmp2.s6_addr[15] = 0;
421 if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) {
422 iface = in->sin6_addr.s6_addr[15];
423 } else {
424 errno = ENETUNREACH;
425 return -1;
428 break;
430 #endif
431 default:
432 errno = ENETUNREACH;
433 return -1;
436 if (prt == 0) {
437 errno = EINVAL;
438 return -1;
441 if (is_bcast) {
442 snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL",
443 socket_wrapper_dir());
444 /* the caller need to do more processing */
445 return 0;
448 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
449 socket_wrapper_dir(), type, iface, prt);
451 return 0;
454 static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un,
455 int *bcast)
457 char type = '\0';
458 unsigned int prt;
459 unsigned int iface;
460 struct stat st;
461 int is_bcast = 0;
463 if (bcast) *bcast = 0;
465 switch (si->family) {
466 case AF_INET: {
467 const struct sockaddr_in *in =
468 (const struct sockaddr_in *)(const void *)inaddr;
469 unsigned int addr = ntohl(in->sin_addr.s_addr);
470 char u_type = '\0';
471 char d_type = '\0';
472 char b_type = '\0';
473 char a_type = '\0';
475 prt = ntohs(in->sin_port);
477 switch (si->type) {
478 case SOCK_STREAM:
479 u_type = SOCKET_TYPE_CHAR_TCP;
480 d_type = SOCKET_TYPE_CHAR_TCP;
481 break;
482 case SOCK_DGRAM:
483 u_type = SOCKET_TYPE_CHAR_UDP;
484 d_type = SOCKET_TYPE_CHAR_UDP;
485 a_type = SOCKET_TYPE_CHAR_UDP;
486 b_type = SOCKET_TYPE_CHAR_UDP;
487 break;
490 if (addr == 0) {
491 /* 0.0.0.0 */
492 is_bcast = 0;
493 type = d_type;
494 iface = socket_wrapper_default_iface();
495 } else if (a_type && addr == 0xFFFFFFFF) {
496 /* 255.255.255.255 only udp */
497 is_bcast = 2;
498 type = a_type;
499 iface = socket_wrapper_default_iface();
500 } else if (b_type && addr == 0x7FFFFFFF) {
501 /* 127.255.255.255 only udp */
502 is_bcast = 1;
503 type = b_type;
504 iface = socket_wrapper_default_iface();
505 } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
506 /* 127.0.0.X */
507 is_bcast = 0;
508 type = u_type;
509 iface = (addr & 0x000000FF);
510 } else {
511 errno = EADDRNOTAVAIL;
512 return -1;
514 break;
516 #ifdef HAVE_IPV6
517 case AF_INET6: {
518 const struct sockaddr_in6 *in =
519 (const struct sockaddr_in6 *)(const void *)inaddr;
520 struct in6_addr cmp1, cmp2;
522 switch (si->type) {
523 case SOCK_STREAM:
524 type = SOCKET_TYPE_CHAR_TCP_V6;
525 break;
526 case SOCK_DGRAM:
527 type = SOCKET_TYPE_CHAR_UDP_V6;
528 break;
531 /* XXX no multicast/broadcast */
533 prt = ntohs(in->sin6_port);
535 cmp1 = *swrap_ipv6();
536 cmp2 = in->sin6_addr;
537 cmp2.s6_addr[15] = 0;
538 if (IN6_IS_ADDR_UNSPECIFIED(&in->sin6_addr)) {
539 iface = socket_wrapper_default_iface();
540 } else if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) {
541 iface = in->sin6_addr.s6_addr[15];
542 } else {
543 errno = EADDRNOTAVAIL;
544 return -1;
547 break;
549 #endif
550 default:
551 errno = EADDRNOTAVAIL;
552 return -1;
556 if (bcast) *bcast = is_bcast;
558 if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) {
559 errno = EINVAL;
560 return -1;
563 if (prt == 0) {
564 /* handle auto-allocation of ephemeral ports */
565 for (prt = 5001; prt < 10000; prt++) {
566 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
567 socket_wrapper_dir(), type, iface, prt);
568 if (stat(un->sun_path, &st) == 0) continue;
570 set_port(si->family, prt, si->myname);
571 break;
573 if (prt == 10000) {
574 errno = ENFILE;
575 return -1;
579 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
580 socket_wrapper_dir(), type, iface, prt);
581 return 0;
584 static struct socket_info *find_socket_info(int fd)
586 struct socket_info *i;
587 for (i = sockets; i; i = i->next) {
588 if (i->fd == fd)
589 return i;
592 return NULL;
595 static int sockaddr_convert_to_un(struct socket_info *si, const struct sockaddr *in_addr, socklen_t in_len,
596 struct sockaddr_un *out_addr, int alloc_sock, int *bcast)
598 struct sockaddr *out = (struct sockaddr *)(void *)out_addr;
599 if (!out_addr)
600 return 0;
602 out->sa_family = AF_UNIX;
603 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
604 out->sa_len = sizeof(*out_addr);
605 #endif
607 switch (in_addr->sa_family) {
608 case AF_INET:
609 #ifdef HAVE_IPV6
610 case AF_INET6:
611 #endif
612 switch (si->type) {
613 case SOCK_STREAM:
614 case SOCK_DGRAM:
615 break;
616 default:
617 errno = ESOCKTNOSUPPORT;
618 return -1;
620 if (alloc_sock) {
621 return convert_in_un_alloc(si, in_addr, out_addr, bcast);
622 } else {
623 return convert_in_un_remote(si, in_addr, out_addr, bcast);
625 default:
626 break;
629 errno = EAFNOSUPPORT;
630 return -1;
633 static int sockaddr_convert_from_un(const struct socket_info *si,
634 const struct sockaddr_un *in_addr,
635 socklen_t un_addrlen,
636 int family,
637 struct sockaddr *out_addr,
638 socklen_t *out_addrlen)
640 int ret;
642 if (out_addr == NULL || out_addrlen == NULL)
643 return 0;
645 if (un_addrlen == 0) {
646 *out_addrlen = 0;
647 return 0;
650 switch (family) {
651 case AF_INET:
652 #ifdef HAVE_IPV6
653 case AF_INET6:
654 #endif
655 switch (si->type) {
656 case SOCK_STREAM:
657 case SOCK_DGRAM:
658 break;
659 default:
660 errno = ESOCKTNOSUPPORT;
661 return -1;
663 ret = convert_un_in(in_addr, out_addr, out_addrlen);
664 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
665 out_addr->sa_len = *out_addrlen;
666 #endif
667 return ret;
668 default:
669 break;
672 errno = EAFNOSUPPORT;
673 return -1;
676 enum swrap_packet_type {
677 SWRAP_CONNECT_SEND,
678 SWRAP_CONNECT_UNREACH,
679 SWRAP_CONNECT_RECV,
680 SWRAP_CONNECT_ACK,
681 SWRAP_ACCEPT_SEND,
682 SWRAP_ACCEPT_RECV,
683 SWRAP_ACCEPT_ACK,
684 SWRAP_RECVFROM,
685 SWRAP_SENDTO,
686 SWRAP_SENDTO_UNREACH,
687 SWRAP_PENDING_RST,
688 SWRAP_RECV,
689 SWRAP_RECV_RST,
690 SWRAP_SEND,
691 SWRAP_SEND_RST,
692 SWRAP_CLOSE_SEND,
693 SWRAP_CLOSE_RECV,
694 SWRAP_CLOSE_ACK,
697 struct swrap_file_hdr {
698 uint32_t magic;
699 uint16_t version_major;
700 uint16_t version_minor;
701 int32_t timezone;
702 uint32_t sigfigs;
703 uint32_t frame_max_len;
704 #define SWRAP_FRAME_LENGTH_MAX 0xFFFF
705 uint32_t link_type;
707 #define SWRAP_FILE_HDR_SIZE 24
709 struct swrap_packet_frame {
710 uint32_t seconds;
711 uint32_t micro_seconds;
712 uint32_t recorded_length;
713 uint32_t full_length;
715 #define SWRAP_PACKET_FRAME_SIZE 16
717 union swrap_packet_ip {
718 struct {
719 uint8_t ver_hdrlen;
720 uint8_t tos;
721 uint16_t packet_length;
722 uint16_t identification;
723 uint8_t flags;
724 uint8_t fragment;
725 uint8_t ttl;
726 uint8_t protocol;
727 uint16_t hdr_checksum;
728 uint32_t src_addr;
729 uint32_t dest_addr;
730 } v4;
731 #define SWRAP_PACKET_IP_V4_SIZE 20
732 struct {
733 uint8_t ver_prio;
734 uint8_t flow_label_high;
735 uint16_t flow_label_low;
736 uint16_t payload_length;
737 uint8_t next_header;
738 uint8_t hop_limit;
739 uint8_t src_addr[16];
740 uint8_t dest_addr[16];
741 } v6;
742 #define SWRAP_PACKET_IP_V6_SIZE 40
744 #define SWRAP_PACKET_IP_SIZE 40
746 union swrap_packet_payload {
747 struct {
748 uint16_t source_port;
749 uint16_t dest_port;
750 uint32_t seq_num;
751 uint32_t ack_num;
752 uint8_t hdr_length;
753 uint8_t control;
754 uint16_t window;
755 uint16_t checksum;
756 uint16_t urg;
757 } tcp;
758 #define SWRAP_PACKET_PAYLOAD_TCP_SIZE 20
759 struct {
760 uint16_t source_port;
761 uint16_t dest_port;
762 uint16_t length;
763 uint16_t checksum;
764 } udp;
765 #define SWRAP_PACKET_PAYLOAD_UDP_SIZE 8
766 struct {
767 uint8_t type;
768 uint8_t code;
769 uint16_t checksum;
770 uint32_t unused;
771 } icmp4;
772 #define SWRAP_PACKET_PAYLOAD_ICMP4_SIZE 8
773 struct {
774 uint8_t type;
775 uint8_t code;
776 uint16_t checksum;
777 uint32_t unused;
778 } icmp6;
779 #define SWRAP_PACKET_PAYLOAD_ICMP6_SIZE 8
781 #define SWRAP_PACKET_PAYLOAD_SIZE 20
783 #define SWRAP_PACKET_MIN_ALLOC \
784 (SWRAP_PACKET_FRAME_SIZE + \
785 SWRAP_PACKET_IP_SIZE + \
786 SWRAP_PACKET_PAYLOAD_SIZE)
788 static const char *socket_wrapper_pcap_file(void)
790 static int initialized = 0;
791 static const char *s = NULL;
792 static const struct swrap_file_hdr h;
793 static const struct swrap_packet_frame f;
794 static const union swrap_packet_ip i;
795 static const union swrap_packet_payload p;
797 if (initialized == 1) {
798 return s;
800 initialized = 1;
803 * TODO: don't use the structs use plain buffer offsets
804 * and PUSH_U8(), PUSH_U16() and PUSH_U32()
806 * for now make sure we disable PCAP support
807 * if the struct has alignment!
809 if (sizeof(h) != SWRAP_FILE_HDR_SIZE) {
810 return NULL;
812 if (sizeof(f) != SWRAP_PACKET_FRAME_SIZE) {
813 return NULL;
815 if (sizeof(i) != SWRAP_PACKET_IP_SIZE) {
816 return NULL;
818 if (sizeof(i.v4) != SWRAP_PACKET_IP_V4_SIZE) {
819 return NULL;
821 if (sizeof(i.v6) != SWRAP_PACKET_IP_V6_SIZE) {
822 return NULL;
824 if (sizeof(p) != SWRAP_PACKET_PAYLOAD_SIZE) {
825 return NULL;
827 if (sizeof(p.tcp) != SWRAP_PACKET_PAYLOAD_TCP_SIZE) {
828 return NULL;
830 if (sizeof(p.udp) != SWRAP_PACKET_PAYLOAD_UDP_SIZE) {
831 return NULL;
833 if (sizeof(p.icmp4) != SWRAP_PACKET_PAYLOAD_ICMP4_SIZE) {
834 return NULL;
836 if (sizeof(p.icmp6) != SWRAP_PACKET_PAYLOAD_ICMP6_SIZE) {
837 return NULL;
840 s = getenv("SOCKET_WRAPPER_PCAP_FILE");
841 if (s == NULL) {
842 return NULL;
844 if (strncmp(s, "./", 2) == 0) {
845 s += 2;
847 return s;
850 static uint8_t *swrap_packet_init(struct timeval *tval,
851 const struct sockaddr *src,
852 const struct sockaddr *dest,
853 int socket_type,
854 const uint8_t *payload,
855 size_t payload_len,
856 unsigned long tcp_seqno,
857 unsigned long tcp_ack,
858 unsigned char tcp_ctl,
859 int unreachable,
860 size_t *_packet_len)
862 uint8_t *base;
863 uint8_t *buf;
864 struct swrap_packet_frame *frame;
865 union swrap_packet_ip *ip;
866 union swrap_packet_payload *pay;
867 size_t packet_len;
868 size_t alloc_len;
869 size_t nonwire_len = sizeof(*frame);
870 size_t wire_hdr_len = 0;
871 size_t wire_len = 0;
872 size_t ip_hdr_len = 0;
873 size_t icmp_hdr_len = 0;
874 size_t icmp_truncate_len = 0;
875 uint8_t protocol = 0, icmp_protocol = 0;
876 const struct sockaddr_in *src_in = NULL;
877 const struct sockaddr_in *dest_in = NULL;
878 #ifdef HAVE_IPV6
879 const struct sockaddr_in6 *src_in6 = NULL;
880 const struct sockaddr_in6 *dest_in6 = NULL;
881 #endif
882 uint16_t src_port;
883 uint16_t dest_port;
885 switch (src->sa_family) {
886 case AF_INET:
887 src_in = (const struct sockaddr_in *)src;
888 dest_in = (const struct sockaddr_in *)dest;
889 src_port = src_in->sin_port;
890 dest_port = dest_in->sin_port;
891 ip_hdr_len = sizeof(ip->v4);
892 break;
893 #ifdef HAVE_IPV6
894 case AF_INET6:
895 src_in6 = (const struct sockaddr_in6 *)src;
896 dest_in6 = (const struct sockaddr_in6 *)dest;
897 src_port = src_in6->sin6_port;
898 dest_port = dest_in6->sin6_port;
899 ip_hdr_len = sizeof(ip->v6);
900 break;
901 #endif
902 default:
903 return NULL;
906 switch (socket_type) {
907 case SOCK_STREAM:
908 protocol = 0x06; /* TCP */
909 wire_hdr_len = ip_hdr_len + sizeof(pay->tcp);
910 wire_len = wire_hdr_len + payload_len;
911 break;
913 case SOCK_DGRAM:
914 protocol = 0x11; /* UDP */
915 wire_hdr_len = ip_hdr_len + sizeof(pay->udp);
916 wire_len = wire_hdr_len + payload_len;
917 break;
919 default:
920 return NULL;
923 if (unreachable) {
924 icmp_protocol = protocol;
925 switch (src->sa_family) {
926 case AF_INET:
927 protocol = 0x01; /* ICMPv4 */
928 icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp4);
929 break;
930 #ifdef HAVE_IPV6
931 case AF_INET6:
932 protocol = 0x3A; /* ICMPv6 */
933 icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp6);
934 break;
935 #endif
937 if (wire_len > 64 ) {
938 icmp_truncate_len = wire_len - 64;
940 wire_hdr_len += icmp_hdr_len;
941 wire_len += icmp_hdr_len;
944 packet_len = nonwire_len + wire_len;
945 alloc_len = packet_len;
946 if (alloc_len < SWRAP_PACKET_MIN_ALLOC) {
947 alloc_len = SWRAP_PACKET_MIN_ALLOC;
950 base = (uint8_t *)malloc(alloc_len);
951 if (!base) return NULL;
953 buf = base;
955 frame = (struct swrap_packet_frame *)buf;
956 frame->seconds = tval->tv_sec;
957 frame->micro_seconds = tval->tv_usec;
958 frame->recorded_length = wire_len - icmp_truncate_len;
959 frame->full_length = wire_len - icmp_truncate_len;
960 buf += SWRAP_PACKET_FRAME_SIZE;
962 ip = (union swrap_packet_ip *)buf;
963 switch (src->sa_family) {
964 case AF_INET:
965 ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
966 ip->v4.tos = 0x00;
967 ip->v4.packet_length = htons(wire_len - icmp_truncate_len);
968 ip->v4.identification = htons(0xFFFF);
969 ip->v4.flags = 0x40; /* BIT 1 set - means don't fraqment */
970 ip->v4.fragment = htons(0x0000);
971 ip->v4.ttl = 0xFF;
972 ip->v4.protocol = protocol;
973 ip->v4.hdr_checksum = htons(0x0000);
974 ip->v4.src_addr = src_in->sin_addr.s_addr;
975 ip->v4.dest_addr = dest_in->sin_addr.s_addr;
976 buf += SWRAP_PACKET_IP_V4_SIZE;
977 break;
978 #ifdef HAVE_IPV6
979 case AF_INET6:
980 ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */
981 ip->v6.flow_label_high = 0x00;
982 ip->v6.flow_label_low = 0x0000;
983 ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */
984 ip->v6.next_header = protocol;
985 memcpy(ip->v6.src_addr, src_in6->sin6_addr.s6_addr, 16);
986 memcpy(ip->v6.dest_addr, dest_in6->sin6_addr.s6_addr, 16);
987 buf += SWRAP_PACKET_IP_V6_SIZE;
988 break;
989 #endif
992 if (unreachable) {
993 pay = (union swrap_packet_payload *)buf;
994 switch (src->sa_family) {
995 case AF_INET:
996 pay->icmp4.type = 0x03; /* destination unreachable */
997 pay->icmp4.code = 0x01; /* host unreachable */
998 pay->icmp4.checksum = htons(0x0000);
999 pay->icmp4.unused = htonl(0x00000000);
1000 buf += SWRAP_PACKET_PAYLOAD_ICMP4_SIZE;
1002 /* set the ip header in the ICMP payload */
1003 ip = (union swrap_packet_ip *)buf;
1004 ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
1005 ip->v4.tos = 0x00;
1006 ip->v4.packet_length = htons(wire_len - icmp_hdr_len);
1007 ip->v4.identification = htons(0xFFFF);
1008 ip->v4.flags = 0x40; /* BIT 1 set - means don't fraqment */
1009 ip->v4.fragment = htons(0x0000);
1010 ip->v4.ttl = 0xFF;
1011 ip->v4.protocol = icmp_protocol;
1012 ip->v4.hdr_checksum = htons(0x0000);
1013 ip->v4.src_addr = dest_in->sin_addr.s_addr;
1014 ip->v4.dest_addr = src_in->sin_addr.s_addr;
1015 buf += SWRAP_PACKET_IP_V4_SIZE;
1017 src_port = dest_in->sin_port;
1018 dest_port = src_in->sin_port;
1019 break;
1020 #ifdef HAVE_IPV6
1021 case AF_INET6:
1022 pay->icmp6.type = 0x01; /* destination unreachable */
1023 pay->icmp6.code = 0x03; /* address unreachable */
1024 pay->icmp6.checksum = htons(0x0000);
1025 pay->icmp6.unused = htonl(0x00000000);
1026 buf += SWRAP_PACKET_PAYLOAD_ICMP6_SIZE;
1028 /* set the ip header in the ICMP payload */
1029 ip = (union swrap_packet_ip *)buf;
1030 ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */
1031 ip->v6.flow_label_high = 0x00;
1032 ip->v6.flow_label_low = 0x0000;
1033 ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */
1034 ip->v6.next_header = protocol;
1035 memcpy(ip->v6.src_addr, dest_in6->sin6_addr.s6_addr, 16);
1036 memcpy(ip->v6.dest_addr, src_in6->sin6_addr.s6_addr, 16);
1037 buf += SWRAP_PACKET_IP_V6_SIZE;
1039 src_port = dest_in6->sin6_port;
1040 dest_port = src_in6->sin6_port;
1041 break;
1042 #endif
1046 pay = (union swrap_packet_payload *)buf;
1048 switch (socket_type) {
1049 case SOCK_STREAM:
1050 pay->tcp.source_port = src_port;
1051 pay->tcp.dest_port = dest_port;
1052 pay->tcp.seq_num = htonl(tcp_seqno);
1053 pay->tcp.ack_num = htonl(tcp_ack);
1054 pay->tcp.hdr_length = 0x50; /* 5 * 32 bit words */
1055 pay->tcp.control = tcp_ctl;
1056 pay->tcp.window = htons(0x7FFF);
1057 pay->tcp.checksum = htons(0x0000);
1058 pay->tcp.urg = htons(0x0000);
1059 buf += SWRAP_PACKET_PAYLOAD_TCP_SIZE;
1061 break;
1063 case SOCK_DGRAM:
1064 pay->udp.source_port = src_port;
1065 pay->udp.dest_port = dest_port;
1066 pay->udp.length = htons(8 + payload_len);
1067 pay->udp.checksum = htons(0x0000);
1068 buf += SWRAP_PACKET_PAYLOAD_UDP_SIZE;
1070 break;
1073 if (payload && payload_len > 0) {
1074 memcpy(buf, payload, payload_len);
1077 *_packet_len = packet_len - icmp_truncate_len;
1078 return base;
1081 static int swrap_get_pcap_fd(const char *fname)
1083 static int fd = -1;
1085 if (fd != -1) return fd;
1087 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0644);
1088 if (fd != -1) {
1089 struct swrap_file_hdr file_hdr;
1090 file_hdr.magic = 0xA1B2C3D4;
1091 file_hdr.version_major = 0x0002;
1092 file_hdr.version_minor = 0x0004;
1093 file_hdr.timezone = 0x00000000;
1094 file_hdr.sigfigs = 0x00000000;
1095 file_hdr.frame_max_len = SWRAP_FRAME_LENGTH_MAX;
1096 file_hdr.link_type = 0x0065; /* 101 RAW IP */
1098 if (write(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) {
1099 close(fd);
1100 fd = -1;
1102 return fd;
1105 fd = open(fname, O_WRONLY|O_APPEND, 0644);
1107 return fd;
1110 static uint8_t *swrap_marshall_packet(struct socket_info *si,
1111 const struct sockaddr *addr,
1112 enum swrap_packet_type type,
1113 const void *buf, size_t len,
1114 size_t *packet_len)
1116 const struct sockaddr *src_addr;
1117 const struct sockaddr *dest_addr;
1118 unsigned long tcp_seqno = 0;
1119 unsigned long tcp_ack = 0;
1120 unsigned char tcp_ctl = 0;
1121 int unreachable = 0;
1123 struct timeval tv;
1125 switch (si->family) {
1126 case AF_INET:
1127 break;
1128 #ifdef HAVE_IPV6
1129 case AF_INET6:
1130 break;
1131 #endif
1132 default:
1133 return NULL;
1136 switch (type) {
1137 case SWRAP_CONNECT_SEND:
1138 if (si->type != SOCK_STREAM) return NULL;
1140 src_addr = si->myname;
1141 dest_addr = addr;
1143 tcp_seqno = si->io.pck_snd;
1144 tcp_ack = si->io.pck_rcv;
1145 tcp_ctl = 0x02; /* SYN */
1147 si->io.pck_snd += 1;
1149 break;
1151 case SWRAP_CONNECT_RECV:
1152 if (si->type != SOCK_STREAM) return NULL;
1154 dest_addr = si->myname;
1155 src_addr = addr;
1157 tcp_seqno = si->io.pck_rcv;
1158 tcp_ack = si->io.pck_snd;
1159 tcp_ctl = 0x12; /** SYN,ACK */
1161 si->io.pck_rcv += 1;
1163 break;
1165 case SWRAP_CONNECT_UNREACH:
1166 if (si->type != SOCK_STREAM) return NULL;
1168 dest_addr = si->myname;
1169 src_addr = addr;
1171 /* Unreachable: resend the data of SWRAP_CONNECT_SEND */
1172 tcp_seqno = si->io.pck_snd - 1;
1173 tcp_ack = si->io.pck_rcv;
1174 tcp_ctl = 0x02; /* SYN */
1175 unreachable = 1;
1177 break;
1179 case SWRAP_CONNECT_ACK:
1180 if (si->type != SOCK_STREAM) return NULL;
1182 src_addr = si->myname;
1183 dest_addr = addr;
1185 tcp_seqno = si->io.pck_snd;
1186 tcp_ack = si->io.pck_rcv;
1187 tcp_ctl = 0x10; /* ACK */
1189 break;
1191 case SWRAP_ACCEPT_SEND:
1192 if (si->type != SOCK_STREAM) return NULL;
1194 dest_addr = si->myname;
1195 src_addr = addr;
1197 tcp_seqno = si->io.pck_rcv;
1198 tcp_ack = si->io.pck_snd;
1199 tcp_ctl = 0x02; /* SYN */
1201 si->io.pck_rcv += 1;
1203 break;
1205 case SWRAP_ACCEPT_RECV:
1206 if (si->type != SOCK_STREAM) return NULL;
1208 src_addr = si->myname;
1209 dest_addr = addr;
1211 tcp_seqno = si->io.pck_snd;
1212 tcp_ack = si->io.pck_rcv;
1213 tcp_ctl = 0x12; /* SYN,ACK */
1215 si->io.pck_snd += 1;
1217 break;
1219 case SWRAP_ACCEPT_ACK:
1220 if (si->type != SOCK_STREAM) return NULL;
1222 dest_addr = si->myname;
1223 src_addr = addr;
1225 tcp_seqno = si->io.pck_rcv;
1226 tcp_ack = si->io.pck_snd;
1227 tcp_ctl = 0x10; /* ACK */
1229 break;
1231 case SWRAP_SEND:
1232 src_addr = si->myname;
1233 dest_addr = si->peername;
1235 tcp_seqno = si->io.pck_snd;
1236 tcp_ack = si->io.pck_rcv;
1237 tcp_ctl = 0x18; /* PSH,ACK */
1239 si->io.pck_snd += len;
1241 break;
1243 case SWRAP_SEND_RST:
1244 dest_addr = si->myname;
1245 src_addr = si->peername;
1247 if (si->type == SOCK_DGRAM) {
1248 return swrap_marshall_packet(si, si->peername,
1249 SWRAP_SENDTO_UNREACH,
1250 buf, len, packet_len);
1253 tcp_seqno = si->io.pck_rcv;
1254 tcp_ack = si->io.pck_snd;
1255 tcp_ctl = 0x14; /** RST,ACK */
1257 break;
1259 case SWRAP_PENDING_RST:
1260 dest_addr = si->myname;
1261 src_addr = si->peername;
1263 if (si->type == SOCK_DGRAM) {
1264 return NULL;
1267 tcp_seqno = si->io.pck_rcv;
1268 tcp_ack = si->io.pck_snd;
1269 tcp_ctl = 0x14; /* RST,ACK */
1271 break;
1273 case SWRAP_RECV:
1274 dest_addr = si->myname;
1275 src_addr = si->peername;
1277 tcp_seqno = si->io.pck_rcv;
1278 tcp_ack = si->io.pck_snd;
1279 tcp_ctl = 0x18; /* PSH,ACK */
1281 si->io.pck_rcv += len;
1283 break;
1285 case SWRAP_RECV_RST:
1286 dest_addr = si->myname;
1287 src_addr = si->peername;
1289 if (si->type == SOCK_DGRAM) {
1290 return NULL;
1293 tcp_seqno = si->io.pck_rcv;
1294 tcp_ack = si->io.pck_snd;
1295 tcp_ctl = 0x14; /* RST,ACK */
1297 break;
1299 case SWRAP_SENDTO:
1300 src_addr = si->myname;
1301 dest_addr = addr;
1303 si->io.pck_snd += len;
1305 break;
1307 case SWRAP_SENDTO_UNREACH:
1308 dest_addr = si->myname;
1309 src_addr = addr;
1311 unreachable = 1;
1313 break;
1315 case SWRAP_RECVFROM:
1316 dest_addr = si->myname;
1317 src_addr = addr;
1319 si->io.pck_rcv += len;
1321 break;
1323 case SWRAP_CLOSE_SEND:
1324 if (si->type != SOCK_STREAM) return NULL;
1326 src_addr = si->myname;
1327 dest_addr = si->peername;
1329 tcp_seqno = si->io.pck_snd;
1330 tcp_ack = si->io.pck_rcv;
1331 tcp_ctl = 0x11; /* FIN, ACK */
1333 si->io.pck_snd += 1;
1335 break;
1337 case SWRAP_CLOSE_RECV:
1338 if (si->type != SOCK_STREAM) return NULL;
1340 dest_addr = si->myname;
1341 src_addr = si->peername;
1343 tcp_seqno = si->io.pck_rcv;
1344 tcp_ack = si->io.pck_snd;
1345 tcp_ctl = 0x11; /* FIN,ACK */
1347 si->io.pck_rcv += 1;
1349 break;
1351 case SWRAP_CLOSE_ACK:
1352 if (si->type != SOCK_STREAM) return NULL;
1354 src_addr = si->myname;
1355 dest_addr = si->peername;
1357 tcp_seqno = si->io.pck_snd;
1358 tcp_ack = si->io.pck_rcv;
1359 tcp_ctl = 0x10; /* ACK */
1361 break;
1362 default:
1363 return NULL;
1366 swrapGetTimeOfDay(&tv);
1368 return swrap_packet_init(&tv, src_addr, dest_addr, si->type,
1369 (const uint8_t *)buf, len,
1370 tcp_seqno, tcp_ack, tcp_ctl, unreachable,
1371 packet_len);
1374 static void swrap_dump_packet(struct socket_info *si,
1375 const struct sockaddr *addr,
1376 enum swrap_packet_type type,
1377 const void *buf, size_t len)
1379 const char *file_name;
1380 uint8_t *packet;
1381 size_t packet_len = 0;
1382 int fd;
1384 file_name = socket_wrapper_pcap_file();
1385 if (!file_name) {
1386 return;
1389 packet = swrap_marshall_packet(si, addr, type, buf, len, &packet_len);
1390 if (!packet) {
1391 return;
1394 fd = swrap_get_pcap_fd(file_name);
1395 if (fd != -1) {
1396 if (write(fd, packet, packet_len) != packet_len) {
1397 free(packet);
1398 return;
1402 free(packet);
1405 _PUBLIC_ int swrap_socket(int family, int type, int protocol)
1407 struct socket_info *si;
1408 int fd;
1409 int real_type = type;
1410 #ifdef SOCK_CLOEXEC
1411 real_type &= ~SOCK_CLOEXEC;
1412 #endif
1413 #ifdef SOCK_NONBLOCK
1414 real_type &= ~SOCK_NONBLOCK;
1415 #endif
1417 if (!socket_wrapper_dir()) {
1418 return real_socket(family, type, protocol);
1421 switch (family) {
1422 case AF_INET:
1423 #ifdef HAVE_IPV6
1424 case AF_INET6:
1425 #endif
1426 break;
1427 case AF_UNIX:
1428 return real_socket(family, type, protocol);
1429 default:
1430 errno = EAFNOSUPPORT;
1431 return -1;
1434 switch (real_type) {
1435 case SOCK_STREAM:
1436 break;
1437 case SOCK_DGRAM:
1438 break;
1439 default:
1440 errno = EPROTONOSUPPORT;
1441 return -1;
1444 switch (protocol) {
1445 case 0:
1446 break;
1447 case 6:
1448 if (real_type == SOCK_STREAM) {
1449 break;
1451 /*fall through*/
1452 case 17:
1453 if (real_type == SOCK_DGRAM) {
1454 break;
1456 /*fall through*/
1457 default:
1458 errno = EPROTONOSUPPORT;
1459 return -1;
1462 /* We must call real_socket with type, from the caller, not the version we removed
1463 SOCK_CLOEXEC and SOCK_NONBLOCK from */
1464 fd = real_socket(AF_UNIX, type, 0);
1466 if (fd == -1) return -1;
1468 si = (struct socket_info *)calloc(1, sizeof(struct socket_info));
1470 si->family = family;
1472 /* however, the rest of the socket_wrapper code expects just
1473 * the type, not the flags */
1474 si->type = real_type;
1475 si->protocol = protocol;
1476 si->fd = fd;
1478 SWRAP_DLIST_ADD(sockets, si);
1480 return si->fd;
1483 _PUBLIC_ int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1485 struct socket_info *parent_si, *child_si;
1486 int fd;
1487 struct sockaddr_un un_addr;
1488 socklen_t un_addrlen = sizeof(un_addr);
1489 struct sockaddr_un un_my_addr;
1490 socklen_t un_my_addrlen = sizeof(un_my_addr);
1491 struct sockaddr *my_addr;
1492 socklen_t my_addrlen, len;
1493 int ret;
1495 parent_si = find_socket_info(s);
1496 if (!parent_si) {
1497 return real_accept(s, addr, addrlen);
1501 * assume out sockaddr have the same size as the in parent
1502 * socket family
1504 my_addrlen = socket_length(parent_si->family);
1505 if (my_addrlen <= 0) {
1506 errno = EINVAL;
1507 return -1;
1510 my_addr = (struct sockaddr *)malloc(my_addrlen);
1511 if (my_addr == NULL) {
1512 return -1;
1515 memset(&un_addr, 0, sizeof(un_addr));
1516 memset(&un_my_addr, 0, sizeof(un_my_addr));
1518 ret = real_accept(s, (struct sockaddr *)(void *)&un_addr, &un_addrlen);
1519 if (ret == -1) {
1520 free(my_addr);
1521 return ret;
1524 fd = ret;
1526 len = my_addrlen;
1527 ret = sockaddr_convert_from_un(parent_si, &un_addr, un_addrlen,
1528 parent_si->family, my_addr, &len);
1529 if (ret == -1) {
1530 free(my_addr);
1531 close(fd);
1532 return ret;
1535 child_si = (struct socket_info *)malloc(sizeof(struct socket_info));
1536 memset(child_si, 0, sizeof(*child_si));
1538 child_si->fd = fd;
1539 child_si->family = parent_si->family;
1540 child_si->type = parent_si->type;
1541 child_si->protocol = parent_si->protocol;
1542 child_si->bound = 1;
1543 child_si->is_server = 1;
1544 child_si->connected = 1;
1546 child_si->peername_len = len;
1547 child_si->peername = sockaddr_dup(my_addr, len);
1549 if (addr != NULL && addrlen != NULL) {
1550 size_t copy_len = MIN(*addrlen, len);
1551 if (copy_len > 0) {
1552 memcpy(addr, my_addr, copy_len);
1554 *addrlen = len;
1557 ret = real_getsockname(fd, (struct sockaddr *)(void *)&un_my_addr,
1558 &un_my_addrlen);
1559 if (ret == -1) {
1560 free(child_si);
1561 close(fd);
1562 return ret;
1565 len = my_addrlen;
1566 ret = sockaddr_convert_from_un(child_si, &un_my_addr, un_my_addrlen,
1567 child_si->family, my_addr, &len);
1568 if (ret == -1) {
1569 free(child_si);
1570 free(my_addr);
1571 close(fd);
1572 return ret;
1575 child_si->myname_len = len;
1576 child_si->myname = sockaddr_dup(my_addr, len);
1577 free(my_addr);
1579 SWRAP_DLIST_ADD(sockets, child_si);
1581 swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0);
1582 swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_RECV, NULL, 0);
1583 swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_ACK, NULL, 0);
1585 return fd;
1588 static int autobind_start_init;
1589 static int autobind_start;
1591 /* using sendto() or connect() on an unbound socket would give the
1592 recipient no way to reply, as unlike UDP and TCP, a unix domain
1593 socket can't auto-assign emphemeral port numbers, so we need to
1594 assign it here.
1595 Note: this might change the family from ipv6 to ipv4
1597 static int swrap_auto_bind(struct socket_info *si, int family)
1599 struct sockaddr_un un_addr;
1600 int i;
1601 char type;
1602 int ret;
1603 int port;
1604 struct stat st;
1606 if (autobind_start_init != 1) {
1607 autobind_start_init = 1;
1608 autobind_start = getpid();
1609 autobind_start %= 50000;
1610 autobind_start += 10000;
1613 un_addr.sun_family = AF_UNIX;
1615 switch (family) {
1616 case AF_INET: {
1617 struct sockaddr_in in;
1619 switch (si->type) {
1620 case SOCK_STREAM:
1621 type = SOCKET_TYPE_CHAR_TCP;
1622 break;
1623 case SOCK_DGRAM:
1624 type = SOCKET_TYPE_CHAR_UDP;
1625 break;
1626 default:
1627 errno = ESOCKTNOSUPPORT;
1628 return -1;
1631 memset(&in, 0, sizeof(in));
1632 in.sin_family = AF_INET;
1633 in.sin_addr.s_addr = htonl(127<<24 |
1634 socket_wrapper_default_iface());
1636 si->myname_len = sizeof(in);
1637 si->myname = sockaddr_dup(&in, si->myname_len);
1638 break;
1640 #ifdef HAVE_IPV6
1641 case AF_INET6: {
1642 struct sockaddr_in6 in6;
1644 if (si->family != family) {
1645 errno = ENETUNREACH;
1646 return -1;
1649 switch (si->type) {
1650 case SOCK_STREAM:
1651 type = SOCKET_TYPE_CHAR_TCP_V6;
1652 break;
1653 case SOCK_DGRAM:
1654 type = SOCKET_TYPE_CHAR_UDP_V6;
1655 break;
1656 default:
1657 errno = ESOCKTNOSUPPORT;
1658 return -1;
1661 memset(&in6, 0, sizeof(in6));
1662 in6.sin6_family = AF_INET6;
1663 in6.sin6_addr = *swrap_ipv6();
1664 in6.sin6_addr.s6_addr[15] = socket_wrapper_default_iface();
1665 si->myname_len = sizeof(in6);
1666 si->myname = sockaddr_dup(&in6, si->myname_len);
1667 break;
1669 #endif
1670 default:
1671 errno = ESOCKTNOSUPPORT;
1672 return -1;
1675 if (autobind_start > 60000) {
1676 autobind_start = 10000;
1679 for (i=0;i<1000;i++) {
1680 port = autobind_start + i;
1681 snprintf(un_addr.sun_path, sizeof(un_addr.sun_path),
1682 "%s/"SOCKET_FORMAT, socket_wrapper_dir(),
1683 type, socket_wrapper_default_iface(), port);
1684 if (stat(un_addr.sun_path, &st) == 0) continue;
1686 ret = real_bind(si->fd, (struct sockaddr *)(void *)&un_addr,
1687 sizeof(un_addr));
1688 if (ret == -1) return ret;
1690 si->tmp_path = strdup(un_addr.sun_path);
1691 si->bound = 1;
1692 autobind_start = port + 1;
1693 break;
1695 if (i == 1000) {
1696 errno = ENFILE;
1697 return -1;
1700 si->family = family;
1701 set_port(si->family, port, si->myname);
1703 return 0;
1707 _PUBLIC_ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen)
1709 int ret;
1710 struct sockaddr_un un_addr;
1711 struct socket_info *si = find_socket_info(s);
1712 int bcast = 0;
1714 if (!si) {
1715 return real_connect(s, serv_addr, addrlen);
1718 if (si->bound == 0) {
1719 ret = swrap_auto_bind(si, serv_addr->sa_family);
1720 if (ret == -1) return -1;
1723 if (si->family != serv_addr->sa_family) {
1724 errno = EINVAL;
1725 return -1;
1728 ret = sockaddr_convert_to_un(si, serv_addr,
1729 addrlen, &un_addr, 0, &bcast);
1730 if (ret == -1) return -1;
1732 if (bcast) {
1733 errno = ENETUNREACH;
1734 return -1;
1737 if (si->type == SOCK_DGRAM) {
1738 si->defer_connect = 1;
1739 ret = 0;
1740 } else {
1741 swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0);
1743 ret = real_connect(s, (struct sockaddr *)(void *)&un_addr,
1744 sizeof(struct sockaddr_un));
1747 /* to give better errors */
1748 if (ret == -1 && errno == ENOENT) {
1749 errno = EHOSTUNREACH;
1752 if (ret == 0) {
1753 si->peername_len = addrlen;
1754 si->peername = sockaddr_dup(serv_addr, addrlen);
1755 si->connected = 1;
1757 swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0);
1758 swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0);
1759 } else {
1760 swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_UNREACH, NULL, 0);
1763 return ret;
1766 _PUBLIC_ int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
1768 int ret;
1769 struct sockaddr_un un_addr;
1770 struct socket_info *si = find_socket_info(s);
1772 if (!si) {
1773 return real_bind(s, myaddr, addrlen);
1776 si->myname_len = addrlen;
1777 si->myname = sockaddr_dup(myaddr, addrlen);
1779 ret = sockaddr_convert_to_un(si, myaddr, addrlen, &un_addr, 1, &si->bcast);
1780 if (ret == -1) return -1;
1782 unlink(un_addr.sun_path);
1784 ret = real_bind(s, (struct sockaddr *)(void *)&un_addr,
1785 sizeof(struct sockaddr_un));
1787 if (ret == 0) {
1788 si->bound = 1;
1791 return ret;
1794 _PUBLIC_ int swrap_listen(int s, int backlog)
1796 int ret;
1797 struct socket_info *si = find_socket_info(s);
1799 if (!si) {
1800 return real_listen(s, backlog);
1803 ret = real_listen(s, backlog);
1805 return ret;
1808 _PUBLIC_ int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
1810 struct socket_info *si = find_socket_info(s);
1812 if (!si) {
1813 return real_getpeername(s, name, addrlen);
1816 if (!si->peername)
1818 errno = ENOTCONN;
1819 return -1;
1822 memcpy(name, si->peername, si->peername_len);
1823 *addrlen = si->peername_len;
1825 return 0;
1828 _PUBLIC_ int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
1830 struct socket_info *si = find_socket_info(s);
1832 if (!si) {
1833 return real_getsockname(s, name, addrlen);
1836 memcpy(name, si->myname, si->myname_len);
1837 *addrlen = si->myname_len;
1839 return 0;
1842 _PUBLIC_ int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
1844 struct socket_info *si = find_socket_info(s);
1846 if (!si) {
1847 return real_getsockopt(s, level, optname, optval, optlen);
1850 if (level == SOL_SOCKET) {
1851 return real_getsockopt(s, level, optname, optval, optlen);
1854 errno = ENOPROTOOPT;
1855 return -1;
1858 _PUBLIC_ int swrap_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
1860 struct socket_info *si = find_socket_info(s);
1862 if (!si) {
1863 return real_setsockopt(s, level, optname, optval, optlen);
1866 if (level == SOL_SOCKET) {
1867 return real_setsockopt(s, level, optname, optval, optlen);
1870 switch (si->family) {
1871 case AF_INET:
1872 return 0;
1873 #ifdef HAVE_IPV6
1874 case AF_INET6:
1875 return 0;
1876 #endif
1877 default:
1878 errno = ENOPROTOOPT;
1879 return -1;
1883 _PUBLIC_ int swrap_ioctl(int s, int r, void *p)
1885 int ret;
1886 struct socket_info *si = find_socket_info(s);
1887 int value;
1889 if (!si) {
1890 return real_ioctl(s, r, p);
1893 ret = real_ioctl(s, r, p);
1895 switch (r) {
1896 case FIONREAD:
1897 value = *((int *)p);
1898 if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
1899 swrap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
1900 } else if (value == 0) { /* END OF FILE */
1901 swrap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
1903 break;
1906 return ret;
1909 static ssize_t swrap_sendmsg_before(struct socket_info *si,
1910 struct msghdr *msg,
1911 struct iovec *tmp_iov,
1912 struct sockaddr_un *tmp_un,
1913 const struct sockaddr_un **to_un,
1914 const struct sockaddr **to,
1915 int *bcast)
1917 size_t i, len = 0;
1918 ssize_t ret;
1920 if (to_un) {
1921 *to_un = NULL;
1923 if (to) {
1924 *to = NULL;
1926 if (bcast) {
1927 *bcast = 0;
1930 switch (si->type) {
1931 case SOCK_STREAM:
1932 if (!si->connected) {
1933 errno = ENOTCONN;
1934 return -1;
1937 if (msg->msg_iovlen == 0) {
1938 break;
1942 * cut down to 1500 byte packets for stream sockets,
1943 * which makes it easier to format PCAP capture files
1944 * (as the caller will simply continue from here)
1947 for (i=0; i < msg->msg_iovlen; i++) {
1948 size_t nlen;
1949 nlen = len + msg->msg_iov[i].iov_len;
1950 if (nlen > 1500) {
1951 break;
1954 msg->msg_iovlen = i;
1955 if (msg->msg_iovlen == 0) {
1956 *tmp_iov = msg->msg_iov[0];
1957 tmp_iov->iov_len = MIN(tmp_iov->iov_len, 1500);
1958 msg->msg_iov = tmp_iov;
1959 msg->msg_iovlen = 1;
1961 break;
1963 case SOCK_DGRAM:
1964 if (si->connected) {
1965 if (msg->msg_name) {
1966 errno = EISCONN;
1967 return -1;
1969 } else {
1970 const struct sockaddr *msg_name;
1971 msg_name = (const struct sockaddr *)msg->msg_name;
1973 if (msg_name == NULL) {
1974 errno = ENOTCONN;
1975 return -1;
1979 ret = sockaddr_convert_to_un(si, msg_name, msg->msg_namelen,
1980 tmp_un, 0, bcast);
1981 if (ret == -1) return -1;
1983 if (to_un) {
1984 *to_un = tmp_un;
1986 if (to) {
1987 *to = msg_name;
1989 msg->msg_name = tmp_un;
1990 msg->msg_namelen = sizeof(*tmp_un);
1993 if (si->bound == 0) {
1994 ret = swrap_auto_bind(si, si->family);
1995 if (ret == -1) return -1;
1998 if (!si->defer_connect) {
1999 break;
2002 ret = sockaddr_convert_to_un(si, si->peername, si->peername_len,
2003 tmp_un, 0, NULL);
2004 if (ret == -1) return -1;
2006 ret = real_connect(si->fd, (struct sockaddr *)(void *)tmp_un,
2007 sizeof(*tmp_un));
2009 /* to give better errors */
2010 if (ret == -1 && errno == ENOENT) {
2011 errno = EHOSTUNREACH;
2014 if (ret == -1) {
2015 return ret;
2018 si->defer_connect = 0;
2019 break;
2020 default:
2021 errno = EHOSTUNREACH;
2022 return -1;
2025 return 0;
2028 static void swrap_sendmsg_after(struct socket_info *si,
2029 struct msghdr *msg,
2030 const struct sockaddr *to,
2031 ssize_t ret)
2033 int saved_errno = errno;
2034 size_t i, len = 0;
2035 uint8_t *buf;
2036 off_t ofs = 0;
2037 size_t avail = 0;
2038 size_t remain;
2040 /* to give better errors */
2041 if (ret == -1 && saved_errno == ENOENT) {
2042 saved_errno = EHOSTUNREACH;
2045 for (i=0; i < msg->msg_iovlen; i++) {
2046 avail += msg->msg_iov[i].iov_len;
2049 if (ret == -1) {
2050 remain = MIN(80, avail);
2051 } else {
2052 remain = ret;
2055 /* we capture it as one single packet */
2056 buf = (uint8_t *)malloc(remain);
2057 if (!buf) {
2058 /* we just not capture the packet */
2059 errno = saved_errno;
2060 return;
2063 for (i=0; i < msg->msg_iovlen; i++) {
2064 size_t this_time = MIN(remain, msg->msg_iov[i].iov_len);
2065 memcpy(buf + ofs,
2066 msg->msg_iov[i].iov_base,
2067 this_time);
2068 ofs += this_time;
2069 remain -= this_time;
2071 len = ofs;
2073 switch (si->type) {
2074 case SOCK_STREAM:
2075 if (ret == -1) {
2076 swrap_dump_packet(si, NULL, SWRAP_SEND, buf, len);
2077 swrap_dump_packet(si, NULL, SWRAP_SEND_RST, NULL, 0);
2078 } else {
2079 swrap_dump_packet(si, NULL, SWRAP_SEND, buf, len);
2081 break;
2083 case SOCK_DGRAM:
2084 if (si->connected) {
2085 to = si->peername;
2087 if (ret == -1) {
2088 swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
2089 swrap_dump_packet(si, to, SWRAP_SENDTO_UNREACH, buf, len);
2090 } else {
2091 swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
2093 break;
2096 free(buf);
2097 errno = saved_errno;
2100 _PUBLIC_ ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
2102 struct sockaddr_un un_addr;
2103 socklen_t un_addrlen = sizeof(un_addr);
2104 int ret;
2105 struct socket_info *si = find_socket_info(s);
2106 struct sockaddr_storage ss;
2107 socklen_t ss_len = sizeof(ss);
2109 if (!si) {
2110 return real_recvfrom(s, buf, len, flags, from, fromlen);
2113 if (!from) {
2114 from = (struct sockaddr *)(void *)&ss;
2115 fromlen = &ss_len;
2118 if (si->type == SOCK_STREAM) {
2119 /* cut down to 1500 byte packets for stream sockets,
2120 * which makes it easier to format PCAP capture files
2121 * (as the caller will simply continue from here) */
2122 len = MIN(len, 1500);
2125 /* irix 6.4 forgets to null terminate the sun_path string :-( */
2126 memset(&un_addr, 0, sizeof(un_addr));
2127 ret = real_recvfrom(s, buf, len, flags,
2128 (struct sockaddr *)(void *)&un_addr, &un_addrlen);
2129 if (ret == -1)
2130 return ret;
2132 if (sockaddr_convert_from_un(si, &un_addr, un_addrlen,
2133 si->family, from, fromlen) == -1) {
2134 return -1;
2137 swrap_dump_packet(si, from, SWRAP_RECVFROM, buf, ret);
2139 return ret;
2143 _PUBLIC_ ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
2145 struct msghdr msg;
2146 struct iovec tmp;
2147 struct sockaddr_un un_addr;
2148 const struct sockaddr_un *to_un = NULL;
2149 ssize_t ret;
2150 struct socket_info *si = find_socket_info(s);
2151 int bcast = 0;
2153 if (!si) {
2154 return real_sendto(s, buf, len, flags, to, tolen);
2157 tmp.iov_base = discard_const_p(char, buf);
2158 tmp.iov_len = len;
2160 ZERO_STRUCT(msg);
2161 msg.msg_name = discard_const_p(struct sockaddr, to); /* optional address */
2162 msg.msg_namelen = tolen; /* size of address */
2163 msg.msg_iov = &tmp; /* scatter/gather array */
2164 msg.msg_iovlen = 1; /* # elements in msg_iov */
2165 #if 0 /* not available on solaris */
2166 msg.msg_control = NULL; /* ancillary data, see below */
2167 msg.msg_controllen = 0; /* ancillary data buffer len */
2168 msg.msg_flags = 0; /* flags on received message */
2169 #endif
2171 ret = swrap_sendmsg_before(si, &msg, &tmp, &un_addr, &to_un, &to, &bcast);
2172 if (ret == -1) return -1;
2174 buf = msg.msg_iov[0].iov_base;
2175 len = msg.msg_iov[0].iov_len;
2177 if (bcast) {
2178 struct stat st;
2179 unsigned int iface;
2180 unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
2181 char type;
2183 type = SOCKET_TYPE_CHAR_UDP;
2185 for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
2186 snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
2187 socket_wrapper_dir(), type, iface, prt);
2188 if (stat(un_addr.sun_path, &st) != 0) continue;
2190 /* ignore the any errors in broadcast sends */
2191 real_sendto(s, buf, len, flags,
2192 (struct sockaddr *)(void *)&un_addr,
2193 sizeof(un_addr));
2196 swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
2198 return len;
2201 ret = real_sendto(s, buf, len, flags, msg.msg_name, msg.msg_namelen);
2203 swrap_sendmsg_after(si, &msg, to, ret);
2205 return ret;
2208 _PUBLIC_ ssize_t swrap_recv(int s, void *buf, size_t len, int flags)
2210 int ret;
2211 struct socket_info *si = find_socket_info(s);
2213 if (!si) {
2214 return real_recv(s, buf, len, flags);
2217 if (si->type == SOCK_STREAM) {
2218 /* cut down to 1500 byte packets for stream sockets,
2219 * which makes it easier to format PCAP capture files
2220 * (as the caller will simply continue from here) */
2221 len = MIN(len, 1500);
2224 ret = real_recv(s, buf, len, flags);
2225 if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
2226 swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
2227 } else if (ret == 0) { /* END OF FILE */
2228 swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
2229 } else if (ret > 0) {
2230 swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
2233 return ret;
2236 _PUBLIC_ ssize_t swrap_read(int s, void *buf, size_t len)
2238 int ret;
2239 struct socket_info *si = find_socket_info(s);
2241 if (!si) {
2242 return real_read(s, buf, len);
2245 if (si->type == SOCK_STREAM) {
2246 /* cut down to 1500 byte packets for stream sockets,
2247 * which makes it easier to format PCAP capture files
2248 * (as the caller will simply continue from here) */
2249 len = MIN(len, 1500);
2252 ret = real_read(s, buf, len);
2253 if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
2254 swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
2255 } else if (ret == 0) { /* END OF FILE */
2256 swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
2257 } else if (ret > 0) {
2258 swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
2261 return ret;
2265 _PUBLIC_ ssize_t swrap_send(int s, const void *buf, size_t len, int flags)
2267 struct msghdr msg;
2268 struct iovec tmp;
2269 struct sockaddr_un un_addr;
2270 ssize_t ret;
2271 struct socket_info *si = find_socket_info(s);
2273 if (!si) {
2274 return real_send(s, buf, len, flags);
2277 tmp.iov_base = discard_const_p(char, buf);
2278 tmp.iov_len = len;
2280 ZERO_STRUCT(msg);
2281 msg.msg_name = NULL; /* optional address */
2282 msg.msg_namelen = 0; /* size of address */
2283 msg.msg_iov = &tmp; /* scatter/gather array */
2284 msg.msg_iovlen = 1; /* # elements in msg_iov */
2285 #if 0 /* not available on solaris */
2286 msg.msg_control = NULL; /* ancillary data, see below */
2287 msg.msg_controllen = 0; /* ancillary data buffer len */
2288 msg.msg_flags = 0; /* flags on received message */
2289 #endif
2291 ret = swrap_sendmsg_before(si, &msg, &tmp, &un_addr, NULL, NULL, NULL);
2292 if (ret == -1) return -1;
2294 buf = msg.msg_iov[0].iov_base;
2295 len = msg.msg_iov[0].iov_len;
2297 ret = real_send(s, buf, len, flags);
2299 swrap_sendmsg_after(si, &msg, NULL, ret);
2301 return ret;
2304 _PUBLIC_ ssize_t swrap_sendmsg(int s, const struct msghdr *omsg, int flags)
2306 struct msghdr msg;
2307 struct iovec tmp;
2308 struct sockaddr_un un_addr;
2309 const struct sockaddr_un *to_un = NULL;
2310 const struct sockaddr *to = NULL;
2311 ssize_t ret;
2312 struct socket_info *si = find_socket_info(s);
2313 int bcast = 0;
2315 if (!si) {
2316 return real_sendmsg(s, omsg, flags);
2319 tmp.iov_base = NULL;
2320 tmp.iov_len = 0;
2322 msg = *omsg;
2323 #if 0
2324 msg.msg_name = omsg->msg_name; /* optional address */
2325 msg.msg_namelen = omsg->msg_namelen; /* size of address */
2326 msg.msg_iov = omsg->msg_iov; /* scatter/gather array */
2327 msg.msg_iovlen = omsg->msg_iovlen; /* # elements in msg_iov */
2328 /* the following is not available on solaris */
2329 msg.msg_control = omsg->msg_control; /* ancillary data, see below */
2330 msg.msg_controllen = omsg->msg_controllen; /* ancillary data buffer len */
2331 msg.msg_flags = omsg->msg_flags; /* flags on received message */
2332 #endif
2334 ret = swrap_sendmsg_before(si, &msg, &tmp, &un_addr, &to_un, &to, &bcast);
2335 if (ret == -1) return -1;
2337 if (bcast) {
2338 struct stat st;
2339 unsigned int iface;
2340 unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
2341 char type;
2342 size_t i, len = 0;
2343 uint8_t *buf;
2344 off_t ofs = 0;
2345 size_t avail = 0;
2346 size_t remain;
2348 for (i=0; i < msg.msg_iovlen; i++) {
2349 avail += msg.msg_iov[i].iov_len;
2352 len = avail;
2353 remain = avail;
2355 /* we capture it as one single packet */
2356 buf = (uint8_t *)malloc(remain);
2357 if (!buf) {
2358 return -1;
2361 for (i=0; i < msg.msg_iovlen; i++) {
2362 size_t this_time = MIN(remain, msg.msg_iov[i].iov_len);
2363 memcpy(buf + ofs,
2364 msg.msg_iov[i].iov_base,
2365 this_time);
2366 ofs += this_time;
2367 remain -= this_time;
2370 type = SOCKET_TYPE_CHAR_UDP;
2372 for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
2373 snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
2374 socket_wrapper_dir(), type, iface, prt);
2375 if (stat(un_addr.sun_path, &st) != 0) continue;
2377 msg.msg_name = &un_addr; /* optional address */
2378 msg.msg_namelen = sizeof(un_addr); /* size of address */
2380 /* ignore the any errors in broadcast sends */
2381 real_sendmsg(s, &msg, flags);
2384 swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
2385 free(buf);
2387 return len;
2390 ret = real_sendmsg(s, &msg, flags);
2392 swrap_sendmsg_after(si, &msg, to, ret);
2394 return ret;
2397 int swrap_readv(int s, const struct iovec *vector, size_t count)
2399 int ret;
2400 struct socket_info *si = find_socket_info(s);
2401 struct iovec v;
2403 if (!si) {
2404 return real_readv(s, vector, count);
2407 if (!si->connected) {
2408 errno = ENOTCONN;
2409 return -1;
2412 if (si->type == SOCK_STREAM && count > 0) {
2413 /* cut down to 1500 byte packets for stream sockets,
2414 * which makes it easier to format PCAP capture files
2415 * (as the caller will simply continue from here) */
2416 size_t i, len = 0;
2418 for (i=0; i < count; i++) {
2419 size_t nlen;
2420 nlen = len + vector[i].iov_len;
2421 if (nlen > 1500) {
2422 break;
2425 count = i;
2426 if (count == 0) {
2427 v = vector[0];
2428 v.iov_len = MIN(v.iov_len, 1500);
2429 vector = &v;
2430 count = 1;
2434 ret = real_readv(s, vector, count);
2435 if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
2436 swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
2437 } else if (ret == 0) { /* END OF FILE */
2438 swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
2439 } else if (ret > 0) {
2440 uint8_t *buf;
2441 off_t ofs = 0;
2442 size_t i;
2443 size_t remain = ret;
2445 /* we capture it as one single packet */
2446 buf = (uint8_t *)malloc(ret);
2447 if (!buf) {
2448 /* we just not capture the packet */
2449 errno = 0;
2450 return ret;
2453 for (i=0; i < count; i++) {
2454 size_t this_time = MIN(remain, vector[i].iov_len);
2455 memcpy(buf + ofs,
2456 vector[i].iov_base,
2457 this_time);
2458 ofs += this_time;
2459 remain -= this_time;
2462 swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
2463 free(buf);
2466 return ret;
2469 int swrap_writev(int s, const struct iovec *vector, size_t count)
2471 struct msghdr msg;
2472 struct iovec tmp;
2473 struct sockaddr_un un_addr;
2474 ssize_t ret;
2475 struct socket_info *si = find_socket_info(s);
2477 if (!si) {
2478 return real_writev(s, vector, count);
2481 tmp.iov_base = NULL;
2482 tmp.iov_len = 0;
2484 ZERO_STRUCT(msg);
2485 msg.msg_name = NULL; /* optional address */
2486 msg.msg_namelen = 0; /* size of address */
2487 msg.msg_iov = discard_const_p(struct iovec, vector); /* scatter/gather array */
2488 msg.msg_iovlen = count; /* # elements in msg_iov */
2489 #if 0 /* not available on solaris */
2490 msg.msg_control = NULL; /* ancillary data, see below */
2491 msg.msg_controllen = 0; /* ancillary data buffer len */
2492 msg.msg_flags = 0; /* flags on received message */
2493 #endif
2495 ret = swrap_sendmsg_before(si, &msg, &tmp, &un_addr, NULL, NULL, NULL);
2496 if (ret == -1) return -1;
2498 ret = real_writev(s, msg.msg_iov, msg.msg_iovlen);
2500 swrap_sendmsg_after(si, &msg, NULL, ret);
2502 return ret;
2505 _PUBLIC_ int swrap_close(int fd)
2507 struct socket_info *si = find_socket_info(fd);
2508 int ret;
2510 if (!si) {
2511 return real_close(fd);
2514 SWRAP_DLIST_REMOVE(sockets, si);
2516 if (si->myname && si->peername) {
2517 swrap_dump_packet(si, NULL, SWRAP_CLOSE_SEND, NULL, 0);
2520 ret = real_close(fd);
2522 if (si->myname && si->peername) {
2523 swrap_dump_packet(si, NULL, SWRAP_CLOSE_RECV, NULL, 0);
2524 swrap_dump_packet(si, NULL, SWRAP_CLOSE_ACK, NULL, 0);
2527 if (si->myname) free(si->myname);
2528 if (si->peername) free(si->peername);
2529 if (si->tmp_path) {
2530 unlink(si->tmp_path);
2531 free(si->tmp_path);
2533 free(si);
2535 return ret;
2538 _PUBLIC_ int swrap_dup(int fd)
2540 struct socket_info *si, *si2;
2541 int fd2;
2543 si = find_socket_info(fd);
2545 if (!si) {
2546 return real_dup(fd);
2549 if (si->tmp_path) {
2550 /* we would need reference counting to handle this */
2551 errno = EINVAL;
2552 return -1;
2555 fd2 = real_dup(fd);
2556 if (fd2 == -1) {
2557 return -1;
2560 si2 = (struct socket_info *)malloc(sizeof(struct socket_info));
2561 if (si2 == NULL) {
2562 real_close(fd2);
2563 errno = ENOMEM;
2564 return -1;
2567 /* copy the whole structure, then duplicate pointer elements */
2568 *si2 = *si;
2570 si2->fd = fd2;
2572 if (si2->myname) {
2573 si2->myname = sockaddr_dup(si2->myname, si2->myname_len);
2574 if (si2->myname == NULL) {
2575 real_close(fd2);
2576 errno = ENOMEM;
2577 return -1;
2581 if (si2->peername) {
2582 si2->peername = sockaddr_dup(si2->peername, si2->peername_len);
2583 if (si2->peername == NULL) {
2584 real_close(fd2);
2585 errno = ENOMEM;
2586 return -1;
2590 SWRAP_DLIST_ADD(sockets, si2);
2591 return fd2;
2594 _PUBLIC_ int swrap_dup2(int fd, int newfd)
2596 struct socket_info *si, *si2;
2597 int fd2;
2599 si = find_socket_info(fd);
2601 if (!si) {
2602 return real_dup2(fd, newfd);
2605 if (si->tmp_path) {
2606 /* we would need reference counting to handle this */
2607 errno = EINVAL;
2608 return -1;
2611 if (find_socket_info(newfd)) {
2612 /* dup2() does an implicit close of newfd, which we
2613 * need to emulate */
2614 swrap_close(newfd);
2617 fd2 = real_dup2(fd, newfd);
2618 if (fd2 == -1) {
2619 return -1;
2622 si2 = (struct socket_info *)malloc(sizeof(struct socket_info));
2623 if (si2 == NULL) {
2624 real_close(fd2);
2625 errno = ENOMEM;
2626 return -1;
2629 /* copy the whole structure, then duplicate pointer elements */
2630 *si2 = *si;
2632 si2->fd = fd2;
2634 if (si2->myname) {
2635 si2->myname = sockaddr_dup(si2->myname, si2->myname_len);
2636 if (si2->myname == NULL) {
2637 real_close(fd2);
2638 errno = ENOMEM;
2639 return -1;
2643 if (si2->peername) {
2644 si2->peername = sockaddr_dup(si2->peername, si2->peername_len);
2645 if (si2->peername == NULL) {
2646 real_close(fd2);
2647 errno = ENOMEM;
2648 return -1;
2652 SWRAP_DLIST_ADD(sockets, si2);
2653 return fd2;