s3-libgpo/gpo_filesync.c: return on read error
[Samba/gebeck_regimport.git] / lib / socket_wrapper / socket_wrapper.c
blob2b526262bd78f26aee0ed7cb3534fd9e12ae696f
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 #endif
132 #ifdef HAVE_GETTIMEOFDAY_TZ
133 #define swrapGetTimeOfDay(tval) gettimeofday(tval,NULL)
134 #else
135 #define swrapGetTimeOfDay(tval) gettimeofday(tval)
136 #endif
138 /* we need to use a very terse format here as IRIX 6.4 silently
139 truncates names to 16 chars, so if we use a longer name then we
140 can't tell which port a packet came from with recvfrom()
142 with this format we have 8 chars left for the directory name
144 #define SOCKET_FORMAT "%c%02X%04X"
145 #define SOCKET_TYPE_CHAR_TCP 'T'
146 #define SOCKET_TYPE_CHAR_UDP 'U'
147 #define SOCKET_TYPE_CHAR_TCP_V6 'X'
148 #define SOCKET_TYPE_CHAR_UDP_V6 'Y'
150 /* This limit is to avoid broadcast sendto() needing to stat too many
151 * files. It may be raised (with a performance cost) to up to 254
152 * without changing the format above */
153 #define MAX_WRAPPED_INTERFACES 32
155 #ifdef HAVE_IPV6
157 * FD00::5357:5FXX
159 static const struct in6_addr *swrap_ipv6(void)
161 static struct in6_addr v;
162 static int initialized;
163 int ret;
165 if (initialized) {
166 return &v;
168 initialized = 1;
170 ret = inet_pton(AF_INET6, "FD00::5357:5F00", &v);
171 if (ret <= 0) {
172 abort();
175 return &v;
177 #endif
179 static struct sockaddr *sockaddr_dup(const void *data, socklen_t len)
181 struct sockaddr *ret = (struct sockaddr *)malloc(len);
182 memcpy(ret, data, len);
183 return ret;
186 static void set_port(int family, int prt, struct sockaddr *addr)
188 switch (family) {
189 case AF_INET:
190 ((struct sockaddr_in *)addr)->sin_port = htons(prt);
191 break;
192 #ifdef HAVE_IPV6
193 case AF_INET6:
194 ((struct sockaddr_in6 *)addr)->sin6_port = htons(prt);
195 break;
196 #endif
200 static size_t socket_length(int family)
202 switch (family) {
203 case AF_INET:
204 return sizeof(struct sockaddr_in);
205 #ifdef HAVE_IPV6
206 case AF_INET6:
207 return sizeof(struct sockaddr_in6);
208 #endif
210 return 0;
215 struct socket_info
217 int fd;
219 int family;
220 int type;
221 int protocol;
222 int bound;
223 int bcast;
224 int is_server;
225 int connected;
226 int defer_connect;
228 char *path;
229 char *tmp_path;
231 struct sockaddr *myname;
232 socklen_t myname_len;
234 struct sockaddr *peername;
235 socklen_t peername_len;
237 struct {
238 unsigned long pck_snd;
239 unsigned long pck_rcv;
240 } io;
242 struct socket_info *prev, *next;
245 static struct socket_info *sockets;
247 const char *socket_wrapper_dir(void)
249 const char *s = getenv("SOCKET_WRAPPER_DIR");
250 if (s == NULL) {
251 return NULL;
253 if (strncmp(s, "./", 2) == 0) {
254 s += 2;
256 return s;
259 unsigned int socket_wrapper_default_iface(void)
261 const char *s = getenv("SOCKET_WRAPPER_DEFAULT_IFACE");
262 if (s) {
263 unsigned int iface;
264 if (sscanf(s, "%u", &iface) == 1) {
265 if (iface >= 1 && iface <= MAX_WRAPPED_INTERFACES) {
266 return iface;
271 return 1;/* 127.0.0.1 */
274 static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, socklen_t *len)
276 unsigned int iface;
277 unsigned int prt;
278 const char *p;
279 char type;
281 p = strrchr(un->sun_path, '/');
282 if (p) p++; else p = un->sun_path;
284 if (sscanf(p, SOCKET_FORMAT, &type, &iface, &prt) != 3) {
285 errno = EINVAL;
286 return -1;
289 if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) {
290 errno = EINVAL;
291 return -1;
294 if (prt > 0xFFFF) {
295 errno = EINVAL;
296 return -1;
299 switch(type) {
300 case SOCKET_TYPE_CHAR_TCP:
301 case SOCKET_TYPE_CHAR_UDP: {
302 struct sockaddr_in *in2 = (struct sockaddr_in *)(void *)in;
304 if ((*len) < sizeof(*in2)) {
305 errno = EINVAL;
306 return -1;
309 memset(in2, 0, sizeof(*in2));
310 in2->sin_family = AF_INET;
311 in2->sin_addr.s_addr = htonl((127<<24) | iface);
312 in2->sin_port = htons(prt);
314 *len = sizeof(*in2);
315 break;
317 #ifdef HAVE_IPV6
318 case SOCKET_TYPE_CHAR_TCP_V6:
319 case SOCKET_TYPE_CHAR_UDP_V6: {
320 struct sockaddr_in6 *in2 = (struct sockaddr_in6 *)(void *)in;
322 if ((*len) < sizeof(*in2)) {
323 errno = EINVAL;
324 return -1;
327 memset(in2, 0, sizeof(*in2));
328 in2->sin6_family = AF_INET6;
329 in2->sin6_addr = *swrap_ipv6();
330 in2->sin6_addr.s6_addr[15] = iface;
331 in2->sin6_port = htons(prt);
333 *len = sizeof(*in2);
334 break;
336 #endif
337 default:
338 errno = EINVAL;
339 return -1;
342 return 0;
345 static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un,
346 int *bcast)
348 char type = '\0';
349 unsigned int prt;
350 unsigned int iface;
351 int is_bcast = 0;
353 if (bcast) *bcast = 0;
355 switch (inaddr->sa_family) {
356 case AF_INET: {
357 const struct sockaddr_in *in =
358 (const struct sockaddr_in *)(const void *)inaddr;
359 unsigned int addr = ntohl(in->sin_addr.s_addr);
360 char u_type = '\0';
361 char b_type = '\0';
362 char a_type = '\0';
364 switch (si->type) {
365 case SOCK_STREAM:
366 u_type = SOCKET_TYPE_CHAR_TCP;
367 break;
368 case SOCK_DGRAM:
369 u_type = SOCKET_TYPE_CHAR_UDP;
370 a_type = SOCKET_TYPE_CHAR_UDP;
371 b_type = SOCKET_TYPE_CHAR_UDP;
372 break;
375 prt = ntohs(in->sin_port);
376 if (a_type && addr == 0xFFFFFFFF) {
377 /* 255.255.255.255 only udp */
378 is_bcast = 2;
379 type = a_type;
380 iface = socket_wrapper_default_iface();
381 } else if (b_type && addr == 0x7FFFFFFF) {
382 /* 127.255.255.255 only udp */
383 is_bcast = 1;
384 type = b_type;
385 iface = socket_wrapper_default_iface();
386 } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
387 /* 127.0.0.X */
388 is_bcast = 0;
389 type = u_type;
390 iface = (addr & 0x000000FF);
391 } else {
392 errno = ENETUNREACH;
393 return -1;
395 if (bcast) *bcast = is_bcast;
396 break;
398 #ifdef HAVE_IPV6
399 case AF_INET6: {
400 const struct sockaddr_in6 *in =
401 (const struct sockaddr_in6 *)(const void *)inaddr;
402 struct in6_addr cmp1, cmp2;
404 switch (si->type) {
405 case SOCK_STREAM:
406 type = SOCKET_TYPE_CHAR_TCP_V6;
407 break;
408 case SOCK_DGRAM:
409 type = SOCKET_TYPE_CHAR_UDP_V6;
410 break;
413 /* XXX no multicast/broadcast */
415 prt = ntohs(in->sin6_port);
417 cmp1 = *swrap_ipv6();
418 cmp2 = in->sin6_addr;
419 cmp2.s6_addr[15] = 0;
420 if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) {
421 iface = in->sin6_addr.s6_addr[15];
422 } else {
423 errno = ENETUNREACH;
424 return -1;
427 break;
429 #endif
430 default:
431 errno = ENETUNREACH;
432 return -1;
435 if (prt == 0) {
436 errno = EINVAL;
437 return -1;
440 if (is_bcast) {
441 snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL",
442 socket_wrapper_dir());
443 /* the caller need to do more processing */
444 return 0;
447 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
448 socket_wrapper_dir(), type, iface, prt);
450 return 0;
453 static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *inaddr, struct sockaddr_un *un,
454 int *bcast)
456 char type = '\0';
457 unsigned int prt;
458 unsigned int iface;
459 struct stat st;
460 int is_bcast = 0;
462 if (bcast) *bcast = 0;
464 switch (si->family) {
465 case AF_INET: {
466 const struct sockaddr_in *in =
467 (const struct sockaddr_in *)(const void *)inaddr;
468 unsigned int addr = ntohl(in->sin_addr.s_addr);
469 char u_type = '\0';
470 char d_type = '\0';
471 char b_type = '\0';
472 char a_type = '\0';
474 prt = ntohs(in->sin_port);
476 switch (si->type) {
477 case SOCK_STREAM:
478 u_type = SOCKET_TYPE_CHAR_TCP;
479 d_type = SOCKET_TYPE_CHAR_TCP;
480 break;
481 case SOCK_DGRAM:
482 u_type = SOCKET_TYPE_CHAR_UDP;
483 d_type = SOCKET_TYPE_CHAR_UDP;
484 a_type = SOCKET_TYPE_CHAR_UDP;
485 b_type = SOCKET_TYPE_CHAR_UDP;
486 break;
489 if (addr == 0) {
490 /* 0.0.0.0 */
491 is_bcast = 0;
492 type = d_type;
493 iface = socket_wrapper_default_iface();
494 } else if (a_type && addr == 0xFFFFFFFF) {
495 /* 255.255.255.255 only udp */
496 is_bcast = 2;
497 type = a_type;
498 iface = socket_wrapper_default_iface();
499 } else if (b_type && addr == 0x7FFFFFFF) {
500 /* 127.255.255.255 only udp */
501 is_bcast = 1;
502 type = b_type;
503 iface = socket_wrapper_default_iface();
504 } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
505 /* 127.0.0.X */
506 is_bcast = 0;
507 type = u_type;
508 iface = (addr & 0x000000FF);
509 } else {
510 errno = EADDRNOTAVAIL;
511 return -1;
513 break;
515 #ifdef HAVE_IPV6
516 case AF_INET6: {
517 const struct sockaddr_in6 *in =
518 (const struct sockaddr_in6 *)(const void *)inaddr;
519 struct in6_addr cmp1, cmp2;
521 switch (si->type) {
522 case SOCK_STREAM:
523 type = SOCKET_TYPE_CHAR_TCP_V6;
524 break;
525 case SOCK_DGRAM:
526 type = SOCKET_TYPE_CHAR_UDP_V6;
527 break;
530 /* XXX no multicast/broadcast */
532 prt = ntohs(in->sin6_port);
534 cmp1 = *swrap_ipv6();
535 cmp2 = in->sin6_addr;
536 cmp2.s6_addr[15] = 0;
537 if (IN6_IS_ADDR_UNSPECIFIED(&in->sin6_addr)) {
538 iface = socket_wrapper_default_iface();
539 } else if (IN6_ARE_ADDR_EQUAL(&cmp1, &cmp2)) {
540 iface = in->sin6_addr.s6_addr[15];
541 } else {
542 errno = EADDRNOTAVAIL;
543 return -1;
546 break;
548 #endif
549 default:
550 errno = EADDRNOTAVAIL;
551 return -1;
555 if (bcast) *bcast = is_bcast;
557 if (iface == 0 || iface > MAX_WRAPPED_INTERFACES) {
558 errno = EINVAL;
559 return -1;
562 if (prt == 0) {
563 /* handle auto-allocation of ephemeral ports */
564 for (prt = 5001; prt < 10000; prt++) {
565 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
566 socket_wrapper_dir(), type, iface, prt);
567 if (stat(un->sun_path, &st) == 0) continue;
569 set_port(si->family, prt, si->myname);
570 break;
572 if (prt == 10000) {
573 errno = ENFILE;
574 return -1;
578 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
579 socket_wrapper_dir(), type, iface, prt);
580 return 0;
583 static struct socket_info *find_socket_info(int fd)
585 struct socket_info *i;
586 for (i = sockets; i; i = i->next) {
587 if (i->fd == fd)
588 return i;
591 return NULL;
594 static int sockaddr_convert_to_un(struct socket_info *si, const struct sockaddr *in_addr, socklen_t in_len,
595 struct sockaddr_un *out_addr, int alloc_sock, int *bcast)
597 struct sockaddr *out = (struct sockaddr *)(void *)out_addr;
598 if (!out_addr)
599 return 0;
601 out->sa_family = AF_UNIX;
602 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
603 out->sa_len = sizeof(*out_addr);
604 #endif
606 switch (in_addr->sa_family) {
607 case AF_INET:
608 #ifdef HAVE_IPV6
609 case AF_INET6:
610 #endif
611 switch (si->type) {
612 case SOCK_STREAM:
613 case SOCK_DGRAM:
614 break;
615 default:
616 errno = ESOCKTNOSUPPORT;
617 return -1;
619 if (alloc_sock) {
620 return convert_in_un_alloc(si, in_addr, out_addr, bcast);
621 } else {
622 return convert_in_un_remote(si, in_addr, out_addr, bcast);
624 default:
625 break;
628 errno = EAFNOSUPPORT;
629 return -1;
632 static int sockaddr_convert_from_un(const struct socket_info *si,
633 const struct sockaddr_un *in_addr,
634 socklen_t un_addrlen,
635 int family,
636 struct sockaddr *out_addr,
637 socklen_t *out_addrlen)
639 int ret;
641 if (out_addr == NULL || out_addrlen == NULL)
642 return 0;
644 if (un_addrlen == 0) {
645 *out_addrlen = 0;
646 return 0;
649 switch (family) {
650 case AF_INET:
651 #ifdef HAVE_IPV6
652 case AF_INET6:
653 #endif
654 switch (si->type) {
655 case SOCK_STREAM:
656 case SOCK_DGRAM:
657 break;
658 default:
659 errno = ESOCKTNOSUPPORT;
660 return -1;
662 ret = convert_un_in(in_addr, out_addr, out_addrlen);
663 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
664 out_addr->sa_len = *out_addrlen;
665 #endif
666 return ret;
667 default:
668 break;
671 errno = EAFNOSUPPORT;
672 return -1;
675 enum swrap_packet_type {
676 SWRAP_CONNECT_SEND,
677 SWRAP_CONNECT_UNREACH,
678 SWRAP_CONNECT_RECV,
679 SWRAP_CONNECT_ACK,
680 SWRAP_ACCEPT_SEND,
681 SWRAP_ACCEPT_RECV,
682 SWRAP_ACCEPT_ACK,
683 SWRAP_RECVFROM,
684 SWRAP_SENDTO,
685 SWRAP_SENDTO_UNREACH,
686 SWRAP_PENDING_RST,
687 SWRAP_RECV,
688 SWRAP_RECV_RST,
689 SWRAP_SEND,
690 SWRAP_SEND_RST,
691 SWRAP_CLOSE_SEND,
692 SWRAP_CLOSE_RECV,
693 SWRAP_CLOSE_ACK,
696 struct swrap_file_hdr {
697 uint32_t magic;
698 uint16_t version_major;
699 uint16_t version_minor;
700 int32_t timezone;
701 uint32_t sigfigs;
702 uint32_t frame_max_len;
703 #define SWRAP_FRAME_LENGTH_MAX 0xFFFF
704 uint32_t link_type;
706 #define SWRAP_FILE_HDR_SIZE 24
708 struct swrap_packet_frame {
709 uint32_t seconds;
710 uint32_t micro_seconds;
711 uint32_t recorded_length;
712 uint32_t full_length;
714 #define SWRAP_PACKET_FRAME_SIZE 16
716 union swrap_packet_ip {
717 struct {
718 uint8_t ver_hdrlen;
719 uint8_t tos;
720 uint16_t packet_length;
721 uint16_t identification;
722 uint8_t flags;
723 uint8_t fragment;
724 uint8_t ttl;
725 uint8_t protocol;
726 uint16_t hdr_checksum;
727 uint32_t src_addr;
728 uint32_t dest_addr;
729 } v4;
730 #define SWRAP_PACKET_IP_V4_SIZE 20
731 struct {
732 uint8_t ver_prio;
733 uint8_t flow_label_high;
734 uint16_t flow_label_low;
735 uint16_t payload_length;
736 uint8_t next_header;
737 uint8_t hop_limit;
738 uint8_t src_addr[16];
739 uint8_t dest_addr[16];
740 } v6;
741 #define SWRAP_PACKET_IP_V6_SIZE 40
743 #define SWRAP_PACKET_IP_SIZE 40
745 union swrap_packet_payload {
746 struct {
747 uint16_t source_port;
748 uint16_t dest_port;
749 uint32_t seq_num;
750 uint32_t ack_num;
751 uint8_t hdr_length;
752 uint8_t control;
753 uint16_t window;
754 uint16_t checksum;
755 uint16_t urg;
756 } tcp;
757 #define SWRAP_PACKET_PAYLOAD_TCP_SIZE 20
758 struct {
759 uint16_t source_port;
760 uint16_t dest_port;
761 uint16_t length;
762 uint16_t checksum;
763 } udp;
764 #define SWRAP_PACKET_PAYLOAD_UDP_SIZE 8
765 struct {
766 uint8_t type;
767 uint8_t code;
768 uint16_t checksum;
769 uint32_t unused;
770 } icmp4;
771 #define SWRAP_PACKET_PAYLOAD_ICMP4_SIZE 8
772 struct {
773 uint8_t type;
774 uint8_t code;
775 uint16_t checksum;
776 uint32_t unused;
777 } icmp6;
778 #define SWRAP_PACKET_PAYLOAD_ICMP6_SIZE 8
780 #define SWRAP_PACKET_PAYLOAD_SIZE 20
782 #define SWRAP_PACKET_MIN_ALLOC \
783 (SWRAP_PACKET_FRAME_SIZE + \
784 SWRAP_PACKET_IP_SIZE + \
785 SWRAP_PACKET_PAYLOAD_SIZE)
787 static const char *socket_wrapper_pcap_file(void)
789 static int initialized = 0;
790 static const char *s = NULL;
791 static const struct swrap_file_hdr h;
792 static const struct swrap_packet_frame f;
793 static const union swrap_packet_ip i;
794 static const union swrap_packet_payload p;
796 if (initialized == 1) {
797 return s;
799 initialized = 1;
802 * TODO: don't use the structs use plain buffer offsets
803 * and PUSH_U8(), PUSH_U16() and PUSH_U32()
805 * for now make sure we disable PCAP support
806 * if the struct has alignment!
808 if (sizeof(h) != SWRAP_FILE_HDR_SIZE) {
809 return NULL;
811 if (sizeof(f) != SWRAP_PACKET_FRAME_SIZE) {
812 return NULL;
814 if (sizeof(i) != SWRAP_PACKET_IP_SIZE) {
815 return NULL;
817 if (sizeof(i.v4) != SWRAP_PACKET_IP_V4_SIZE) {
818 return NULL;
820 if (sizeof(i.v6) != SWRAP_PACKET_IP_V6_SIZE) {
821 return NULL;
823 if (sizeof(p) != SWRAP_PACKET_PAYLOAD_SIZE) {
824 return NULL;
826 if (sizeof(p.tcp) != SWRAP_PACKET_PAYLOAD_TCP_SIZE) {
827 return NULL;
829 if (sizeof(p.udp) != SWRAP_PACKET_PAYLOAD_UDP_SIZE) {
830 return NULL;
832 if (sizeof(p.icmp4) != SWRAP_PACKET_PAYLOAD_ICMP4_SIZE) {
833 return NULL;
835 if (sizeof(p.icmp6) != SWRAP_PACKET_PAYLOAD_ICMP6_SIZE) {
836 return NULL;
839 s = getenv("SOCKET_WRAPPER_PCAP_FILE");
840 if (s == NULL) {
841 return NULL;
843 if (strncmp(s, "./", 2) == 0) {
844 s += 2;
846 return s;
849 static uint8_t *swrap_packet_init(struct timeval *tval,
850 const struct sockaddr *src,
851 const struct sockaddr *dest,
852 int socket_type,
853 const uint8_t *payload,
854 size_t payload_len,
855 unsigned long tcp_seqno,
856 unsigned long tcp_ack,
857 unsigned char tcp_ctl,
858 int unreachable,
859 size_t *_packet_len)
861 uint8_t *base;
862 uint8_t *buf;
863 struct swrap_packet_frame *frame;
864 union swrap_packet_ip *ip;
865 union swrap_packet_payload *pay;
866 size_t packet_len;
867 size_t alloc_len;
868 size_t nonwire_len = sizeof(*frame);
869 size_t wire_hdr_len = 0;
870 size_t wire_len = 0;
871 size_t ip_hdr_len = 0;
872 size_t icmp_hdr_len = 0;
873 size_t icmp_truncate_len = 0;
874 uint8_t protocol = 0, icmp_protocol = 0;
875 const struct sockaddr_in *src_in = NULL;
876 const struct sockaddr_in *dest_in = NULL;
877 #ifdef HAVE_IPV6
878 const struct sockaddr_in6 *src_in6 = NULL;
879 const struct sockaddr_in6 *dest_in6 = NULL;
880 #endif
881 uint16_t src_port;
882 uint16_t dest_port;
884 switch (src->sa_family) {
885 case AF_INET:
886 src_in = (const struct sockaddr_in *)src;
887 dest_in = (const struct sockaddr_in *)dest;
888 src_port = src_in->sin_port;
889 dest_port = dest_in->sin_port;
890 ip_hdr_len = sizeof(ip->v4);
891 break;
892 #ifdef HAVE_IPV6
893 case AF_INET6:
894 src_in6 = (const struct sockaddr_in6 *)src;
895 dest_in6 = (const struct sockaddr_in6 *)dest;
896 src_port = src_in6->sin6_port;
897 dest_port = dest_in6->sin6_port;
898 ip_hdr_len = sizeof(ip->v6);
899 break;
900 #endif
901 default:
902 return NULL;
905 switch (socket_type) {
906 case SOCK_STREAM:
907 protocol = 0x06; /* TCP */
908 wire_hdr_len = ip_hdr_len + sizeof(pay->tcp);
909 wire_len = wire_hdr_len + payload_len;
910 break;
912 case SOCK_DGRAM:
913 protocol = 0x11; /* UDP */
914 wire_hdr_len = ip_hdr_len + sizeof(pay->udp);
915 wire_len = wire_hdr_len + payload_len;
916 break;
918 default:
919 return NULL;
922 if (unreachable) {
923 icmp_protocol = protocol;
924 switch (src->sa_family) {
925 case AF_INET:
926 protocol = 0x01; /* ICMPv4 */
927 icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp4);
928 break;
929 #ifdef HAVE_IPV6
930 case AF_INET6:
931 protocol = 0x3A; /* ICMPv6 */
932 icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp6);
933 break;
934 #endif
936 if (wire_len > 64 ) {
937 icmp_truncate_len = wire_len - 64;
939 wire_hdr_len += icmp_hdr_len;
940 wire_len += icmp_hdr_len;
943 packet_len = nonwire_len + wire_len;
944 alloc_len = packet_len;
945 if (alloc_len < SWRAP_PACKET_MIN_ALLOC) {
946 alloc_len = SWRAP_PACKET_MIN_ALLOC;
949 base = (uint8_t *)malloc(alloc_len);
950 if (!base) return NULL;
952 buf = base;
954 frame = (struct swrap_packet_frame *)buf;
955 frame->seconds = tval->tv_sec;
956 frame->micro_seconds = tval->tv_usec;
957 frame->recorded_length = wire_len - icmp_truncate_len;
958 frame->full_length = wire_len - icmp_truncate_len;
959 buf += SWRAP_PACKET_FRAME_SIZE;
961 ip = (union swrap_packet_ip *)buf;
962 switch (src->sa_family) {
963 case AF_INET:
964 ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
965 ip->v4.tos = 0x00;
966 ip->v4.packet_length = htons(wire_len - icmp_truncate_len);
967 ip->v4.identification = htons(0xFFFF);
968 ip->v4.flags = 0x40; /* BIT 1 set - means don't fraqment */
969 ip->v4.fragment = htons(0x0000);
970 ip->v4.ttl = 0xFF;
971 ip->v4.protocol = protocol;
972 ip->v4.hdr_checksum = htons(0x0000);
973 ip->v4.src_addr = src_in->sin_addr.s_addr;
974 ip->v4.dest_addr = dest_in->sin_addr.s_addr;
975 buf += SWRAP_PACKET_IP_V4_SIZE;
976 break;
977 #ifdef HAVE_IPV6
978 case AF_INET6:
979 ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */
980 ip->v6.flow_label_high = 0x00;
981 ip->v6.flow_label_low = 0x0000;
982 ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */
983 ip->v6.next_header = protocol;
984 memcpy(ip->v6.src_addr, src_in6->sin6_addr.s6_addr, 16);
985 memcpy(ip->v6.dest_addr, dest_in6->sin6_addr.s6_addr, 16);
986 buf += SWRAP_PACKET_IP_V6_SIZE;
987 break;
988 #endif
991 if (unreachable) {
992 pay = (union swrap_packet_payload *)buf;
993 switch (src->sa_family) {
994 case AF_INET:
995 pay->icmp4.type = 0x03; /* destination unreachable */
996 pay->icmp4.code = 0x01; /* host unreachable */
997 pay->icmp4.checksum = htons(0x0000);
998 pay->icmp4.unused = htonl(0x00000000);
999 buf += SWRAP_PACKET_PAYLOAD_ICMP4_SIZE;
1001 /* set the ip header in the ICMP payload */
1002 ip = (union swrap_packet_ip *)buf;
1003 ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
1004 ip->v4.tos = 0x00;
1005 ip->v4.packet_length = htons(wire_len - icmp_hdr_len);
1006 ip->v4.identification = htons(0xFFFF);
1007 ip->v4.flags = 0x40; /* BIT 1 set - means don't fraqment */
1008 ip->v4.fragment = htons(0x0000);
1009 ip->v4.ttl = 0xFF;
1010 ip->v4.protocol = icmp_protocol;
1011 ip->v4.hdr_checksum = htons(0x0000);
1012 ip->v4.src_addr = dest_in->sin_addr.s_addr;
1013 ip->v4.dest_addr = src_in->sin_addr.s_addr;
1014 buf += SWRAP_PACKET_IP_V4_SIZE;
1016 src_port = dest_in->sin_port;
1017 dest_port = src_in->sin_port;
1018 break;
1019 #ifdef HAVE_IPV6
1020 case AF_INET6:
1021 pay->icmp6.type = 0x01; /* destination unreachable */
1022 pay->icmp6.code = 0x03; /* address unreachable */
1023 pay->icmp6.checksum = htons(0x0000);
1024 pay->icmp6.unused = htonl(0x00000000);
1025 buf += SWRAP_PACKET_PAYLOAD_ICMP6_SIZE;
1027 /* set the ip header in the ICMP payload */
1028 ip = (union swrap_packet_ip *)buf;
1029 ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */
1030 ip->v6.flow_label_high = 0x00;
1031 ip->v6.flow_label_low = 0x0000;
1032 ip->v6.payload_length = htons(wire_len - icmp_truncate_len); /* TODO */
1033 ip->v6.next_header = protocol;
1034 memcpy(ip->v6.src_addr, dest_in6->sin6_addr.s6_addr, 16);
1035 memcpy(ip->v6.dest_addr, src_in6->sin6_addr.s6_addr, 16);
1036 buf += SWRAP_PACKET_IP_V6_SIZE;
1038 src_port = dest_in6->sin6_port;
1039 dest_port = src_in6->sin6_port;
1040 break;
1041 #endif
1045 pay = (union swrap_packet_payload *)buf;
1047 switch (socket_type) {
1048 case SOCK_STREAM:
1049 pay->tcp.source_port = src_port;
1050 pay->tcp.dest_port = dest_port;
1051 pay->tcp.seq_num = htonl(tcp_seqno);
1052 pay->tcp.ack_num = htonl(tcp_ack);
1053 pay->tcp.hdr_length = 0x50; /* 5 * 32 bit words */
1054 pay->tcp.control = tcp_ctl;
1055 pay->tcp.window = htons(0x7FFF);
1056 pay->tcp.checksum = htons(0x0000);
1057 pay->tcp.urg = htons(0x0000);
1058 buf += SWRAP_PACKET_PAYLOAD_TCP_SIZE;
1060 break;
1062 case SOCK_DGRAM:
1063 pay->udp.source_port = src_port;
1064 pay->udp.dest_port = dest_port;
1065 pay->udp.length = htons(8 + payload_len);
1066 pay->udp.checksum = htons(0x0000);
1067 buf += SWRAP_PACKET_PAYLOAD_UDP_SIZE;
1069 break;
1072 if (payload && payload_len > 0) {
1073 memcpy(buf, payload, payload_len);
1076 *_packet_len = packet_len - icmp_truncate_len;
1077 return base;
1080 static int swrap_get_pcap_fd(const char *fname)
1082 static int fd = -1;
1084 if (fd != -1) return fd;
1086 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0644);
1087 if (fd != -1) {
1088 struct swrap_file_hdr file_hdr;
1089 file_hdr.magic = 0xA1B2C3D4;
1090 file_hdr.version_major = 0x0002;
1091 file_hdr.version_minor = 0x0004;
1092 file_hdr.timezone = 0x00000000;
1093 file_hdr.sigfigs = 0x00000000;
1094 file_hdr.frame_max_len = SWRAP_FRAME_LENGTH_MAX;
1095 file_hdr.link_type = 0x0065; /* 101 RAW IP */
1097 if (write(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) {
1098 close(fd);
1099 fd = -1;
1101 return fd;
1104 fd = open(fname, O_WRONLY|O_APPEND, 0644);
1106 return fd;
1109 static uint8_t *swrap_marshall_packet(struct socket_info *si,
1110 const struct sockaddr *addr,
1111 enum swrap_packet_type type,
1112 const void *buf, size_t len,
1113 size_t *packet_len)
1115 const struct sockaddr *src_addr;
1116 const struct sockaddr *dest_addr;
1117 unsigned long tcp_seqno = 0;
1118 unsigned long tcp_ack = 0;
1119 unsigned char tcp_ctl = 0;
1120 int unreachable = 0;
1122 struct timeval tv;
1124 switch (si->family) {
1125 case AF_INET:
1126 break;
1127 #ifdef HAVE_IPV6
1128 case AF_INET6:
1129 break;
1130 #endif
1131 default:
1132 return NULL;
1135 switch (type) {
1136 case SWRAP_CONNECT_SEND:
1137 if (si->type != SOCK_STREAM) return NULL;
1139 src_addr = si->myname;
1140 dest_addr = addr;
1142 tcp_seqno = si->io.pck_snd;
1143 tcp_ack = si->io.pck_rcv;
1144 tcp_ctl = 0x02; /* SYN */
1146 si->io.pck_snd += 1;
1148 break;
1150 case SWRAP_CONNECT_RECV:
1151 if (si->type != SOCK_STREAM) return NULL;
1153 dest_addr = si->myname;
1154 src_addr = addr;
1156 tcp_seqno = si->io.pck_rcv;
1157 tcp_ack = si->io.pck_snd;
1158 tcp_ctl = 0x12; /** SYN,ACK */
1160 si->io.pck_rcv += 1;
1162 break;
1164 case SWRAP_CONNECT_UNREACH:
1165 if (si->type != SOCK_STREAM) return NULL;
1167 dest_addr = si->myname;
1168 src_addr = addr;
1170 /* Unreachable: resend the data of SWRAP_CONNECT_SEND */
1171 tcp_seqno = si->io.pck_snd - 1;
1172 tcp_ack = si->io.pck_rcv;
1173 tcp_ctl = 0x02; /* SYN */
1174 unreachable = 1;
1176 break;
1178 case SWRAP_CONNECT_ACK:
1179 if (si->type != SOCK_STREAM) return NULL;
1181 src_addr = si->myname;
1182 dest_addr = addr;
1184 tcp_seqno = si->io.pck_snd;
1185 tcp_ack = si->io.pck_rcv;
1186 tcp_ctl = 0x10; /* ACK */
1188 break;
1190 case SWRAP_ACCEPT_SEND:
1191 if (si->type != SOCK_STREAM) return NULL;
1193 dest_addr = si->myname;
1194 src_addr = addr;
1196 tcp_seqno = si->io.pck_rcv;
1197 tcp_ack = si->io.pck_snd;
1198 tcp_ctl = 0x02; /* SYN */
1200 si->io.pck_rcv += 1;
1202 break;
1204 case SWRAP_ACCEPT_RECV:
1205 if (si->type != SOCK_STREAM) return NULL;
1207 src_addr = si->myname;
1208 dest_addr = addr;
1210 tcp_seqno = si->io.pck_snd;
1211 tcp_ack = si->io.pck_rcv;
1212 tcp_ctl = 0x12; /* SYN,ACK */
1214 si->io.pck_snd += 1;
1216 break;
1218 case SWRAP_ACCEPT_ACK:
1219 if (si->type != SOCK_STREAM) return NULL;
1221 dest_addr = si->myname;
1222 src_addr = addr;
1224 tcp_seqno = si->io.pck_rcv;
1225 tcp_ack = si->io.pck_snd;
1226 tcp_ctl = 0x10; /* ACK */
1228 break;
1230 case SWRAP_SEND:
1231 src_addr = si->myname;
1232 dest_addr = si->peername;
1234 tcp_seqno = si->io.pck_snd;
1235 tcp_ack = si->io.pck_rcv;
1236 tcp_ctl = 0x18; /* PSH,ACK */
1238 si->io.pck_snd += len;
1240 break;
1242 case SWRAP_SEND_RST:
1243 dest_addr = si->myname;
1244 src_addr = si->peername;
1246 if (si->type == SOCK_DGRAM) {
1247 return swrap_marshall_packet(si, si->peername,
1248 SWRAP_SENDTO_UNREACH,
1249 buf, len, packet_len);
1252 tcp_seqno = si->io.pck_rcv;
1253 tcp_ack = si->io.pck_snd;
1254 tcp_ctl = 0x14; /** RST,ACK */
1256 break;
1258 case SWRAP_PENDING_RST:
1259 dest_addr = si->myname;
1260 src_addr = si->peername;
1262 if (si->type == SOCK_DGRAM) {
1263 return NULL;
1266 tcp_seqno = si->io.pck_rcv;
1267 tcp_ack = si->io.pck_snd;
1268 tcp_ctl = 0x14; /* RST,ACK */
1270 break;
1272 case SWRAP_RECV:
1273 dest_addr = si->myname;
1274 src_addr = si->peername;
1276 tcp_seqno = si->io.pck_rcv;
1277 tcp_ack = si->io.pck_snd;
1278 tcp_ctl = 0x18; /* PSH,ACK */
1280 si->io.pck_rcv += len;
1282 break;
1284 case SWRAP_RECV_RST:
1285 dest_addr = si->myname;
1286 src_addr = si->peername;
1288 if (si->type == SOCK_DGRAM) {
1289 return NULL;
1292 tcp_seqno = si->io.pck_rcv;
1293 tcp_ack = si->io.pck_snd;
1294 tcp_ctl = 0x14; /* RST,ACK */
1296 break;
1298 case SWRAP_SENDTO:
1299 src_addr = si->myname;
1300 dest_addr = addr;
1302 si->io.pck_snd += len;
1304 break;
1306 case SWRAP_SENDTO_UNREACH:
1307 dest_addr = si->myname;
1308 src_addr = addr;
1310 unreachable = 1;
1312 break;
1314 case SWRAP_RECVFROM:
1315 dest_addr = si->myname;
1316 src_addr = addr;
1318 si->io.pck_rcv += len;
1320 break;
1322 case SWRAP_CLOSE_SEND:
1323 if (si->type != SOCK_STREAM) return NULL;
1325 src_addr = si->myname;
1326 dest_addr = si->peername;
1328 tcp_seqno = si->io.pck_snd;
1329 tcp_ack = si->io.pck_rcv;
1330 tcp_ctl = 0x11; /* FIN, ACK */
1332 si->io.pck_snd += 1;
1334 break;
1336 case SWRAP_CLOSE_RECV:
1337 if (si->type != SOCK_STREAM) return NULL;
1339 dest_addr = si->myname;
1340 src_addr = si->peername;
1342 tcp_seqno = si->io.pck_rcv;
1343 tcp_ack = si->io.pck_snd;
1344 tcp_ctl = 0x11; /* FIN,ACK */
1346 si->io.pck_rcv += 1;
1348 break;
1350 case SWRAP_CLOSE_ACK:
1351 if (si->type != SOCK_STREAM) return NULL;
1353 src_addr = si->myname;
1354 dest_addr = si->peername;
1356 tcp_seqno = si->io.pck_snd;
1357 tcp_ack = si->io.pck_rcv;
1358 tcp_ctl = 0x10; /* ACK */
1360 break;
1361 default:
1362 return NULL;
1365 swrapGetTimeOfDay(&tv);
1367 return swrap_packet_init(&tv, src_addr, dest_addr, si->type,
1368 (const uint8_t *)buf, len,
1369 tcp_seqno, tcp_ack, tcp_ctl, unreachable,
1370 packet_len);
1373 static void swrap_dump_packet(struct socket_info *si,
1374 const struct sockaddr *addr,
1375 enum swrap_packet_type type,
1376 const void *buf, size_t len)
1378 const char *file_name;
1379 uint8_t *packet;
1380 size_t packet_len = 0;
1381 int fd;
1383 file_name = socket_wrapper_pcap_file();
1384 if (!file_name) {
1385 return;
1388 packet = swrap_marshall_packet(si, addr, type, buf, len, &packet_len);
1389 if (!packet) {
1390 return;
1393 fd = swrap_get_pcap_fd(file_name);
1394 if (fd != -1) {
1395 if (write(fd, packet, packet_len) != packet_len) {
1396 free(packet);
1397 return;
1401 free(packet);
1404 _PUBLIC_ int swrap_socket(int family, int type, int protocol)
1406 struct socket_info *si;
1407 int fd;
1408 int real_type = type;
1409 #ifdef SOCK_CLOEXEC
1410 real_type &= ~SOCK_CLOEXEC;
1411 #endif
1412 #ifdef SOCK_NONBLOCK
1413 real_type &= ~SOCK_NONBLOCK;
1414 #endif
1416 if (!socket_wrapper_dir()) {
1417 return real_socket(family, type, protocol);
1420 switch (family) {
1421 case AF_INET:
1422 #ifdef HAVE_IPV6
1423 case AF_INET6:
1424 #endif
1425 break;
1426 case AF_UNIX:
1427 return real_socket(family, type, protocol);
1428 default:
1429 errno = EAFNOSUPPORT;
1430 return -1;
1433 switch (real_type) {
1434 case SOCK_STREAM:
1435 break;
1436 case SOCK_DGRAM:
1437 break;
1438 default:
1439 errno = EPROTONOSUPPORT;
1440 return -1;
1443 switch (protocol) {
1444 case 0:
1445 break;
1446 case 6:
1447 if (real_type == SOCK_STREAM) {
1448 break;
1450 /*fall through*/
1451 case 17:
1452 if (real_type == SOCK_DGRAM) {
1453 break;
1455 /*fall through*/
1456 default:
1457 errno = EPROTONOSUPPORT;
1458 return -1;
1461 /* We must call real_socket with type, from the caller, not the version we removed
1462 SOCK_CLOEXEC and SOCK_NONBLOCK from */
1463 fd = real_socket(AF_UNIX, type, 0);
1465 if (fd == -1) return -1;
1467 si = (struct socket_info *)calloc(1, sizeof(struct socket_info));
1469 si->family = family;
1471 /* however, the rest of the socket_wrapper code expects just
1472 * the type, not the flags */
1473 si->type = real_type;
1474 si->protocol = protocol;
1475 si->fd = fd;
1477 SWRAP_DLIST_ADD(sockets, si);
1479 return si->fd;
1482 _PUBLIC_ int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
1484 struct socket_info *parent_si, *child_si;
1485 int fd;
1486 struct sockaddr_un un_addr;
1487 socklen_t un_addrlen = sizeof(un_addr);
1488 struct sockaddr_un un_my_addr;
1489 socklen_t un_my_addrlen = sizeof(un_my_addr);
1490 struct sockaddr *my_addr;
1491 socklen_t my_addrlen, len;
1492 int ret;
1494 parent_si = find_socket_info(s);
1495 if (!parent_si) {
1496 return real_accept(s, addr, addrlen);
1500 * assume out sockaddr have the same size as the in parent
1501 * socket family
1503 my_addrlen = socket_length(parent_si->family);
1504 if (my_addrlen <= 0) {
1505 errno = EINVAL;
1506 return -1;
1509 my_addr = (struct sockaddr *)malloc(my_addrlen);
1510 if (my_addr == NULL) {
1511 return -1;
1514 memset(&un_addr, 0, sizeof(un_addr));
1515 memset(&un_my_addr, 0, sizeof(un_my_addr));
1517 ret = real_accept(s, (struct sockaddr *)(void *)&un_addr, &un_addrlen);
1518 if (ret == -1) {
1519 free(my_addr);
1520 return ret;
1523 fd = ret;
1525 len = my_addrlen;
1526 ret = sockaddr_convert_from_un(parent_si, &un_addr, un_addrlen,
1527 parent_si->family, my_addr, &len);
1528 if (ret == -1) {
1529 free(my_addr);
1530 close(fd);
1531 return ret;
1534 child_si = (struct socket_info *)malloc(sizeof(struct socket_info));
1535 memset(child_si, 0, sizeof(*child_si));
1537 child_si->fd = fd;
1538 child_si->family = parent_si->family;
1539 child_si->type = parent_si->type;
1540 child_si->protocol = parent_si->protocol;
1541 child_si->bound = 1;
1542 child_si->is_server = 1;
1543 child_si->connected = 1;
1545 child_si->peername_len = len;
1546 child_si->peername = sockaddr_dup(my_addr, len);
1548 if (addr != NULL && addrlen != NULL) {
1549 size_t copy_len = MIN(*addrlen, len);
1550 if (copy_len > 0) {
1551 memcpy(addr, my_addr, copy_len);
1553 *addrlen = len;
1556 ret = real_getsockname(fd, (struct sockaddr *)(void *)&un_my_addr,
1557 &un_my_addrlen);
1558 if (ret == -1) {
1559 free(child_si);
1560 close(fd);
1561 return ret;
1564 len = my_addrlen;
1565 ret = sockaddr_convert_from_un(child_si, &un_my_addr, un_my_addrlen,
1566 child_si->family, my_addr, &len);
1567 if (ret == -1) {
1568 free(child_si);
1569 free(my_addr);
1570 close(fd);
1571 return ret;
1574 child_si->myname_len = len;
1575 child_si->myname = sockaddr_dup(my_addr, len);
1576 free(my_addr);
1578 SWRAP_DLIST_ADD(sockets, child_si);
1580 swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0);
1581 swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_RECV, NULL, 0);
1582 swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_ACK, NULL, 0);
1584 return fd;
1587 static int autobind_start_init;
1588 static int autobind_start;
1590 /* using sendto() or connect() on an unbound socket would give the
1591 recipient no way to reply, as unlike UDP and TCP, a unix domain
1592 socket can't auto-assign emphemeral port numbers, so we need to
1593 assign it here.
1594 Note: this might change the family from ipv6 to ipv4
1596 static int swrap_auto_bind(struct socket_info *si, int family)
1598 struct sockaddr_un un_addr;
1599 int i;
1600 char type;
1601 int ret;
1602 int port;
1603 struct stat st;
1605 if (autobind_start_init != 1) {
1606 autobind_start_init = 1;
1607 autobind_start = getpid();
1608 autobind_start %= 50000;
1609 autobind_start += 10000;
1612 un_addr.sun_family = AF_UNIX;
1614 switch (family) {
1615 case AF_INET: {
1616 struct sockaddr_in in;
1618 switch (si->type) {
1619 case SOCK_STREAM:
1620 type = SOCKET_TYPE_CHAR_TCP;
1621 break;
1622 case SOCK_DGRAM:
1623 type = SOCKET_TYPE_CHAR_UDP;
1624 break;
1625 default:
1626 errno = ESOCKTNOSUPPORT;
1627 return -1;
1630 memset(&in, 0, sizeof(in));
1631 in.sin_family = AF_INET;
1632 in.sin_addr.s_addr = htonl(127<<24 |
1633 socket_wrapper_default_iface());
1635 si->myname_len = sizeof(in);
1636 si->myname = sockaddr_dup(&in, si->myname_len);
1637 break;
1639 #ifdef HAVE_IPV6
1640 case AF_INET6: {
1641 struct sockaddr_in6 in6;
1643 if (si->family != family) {
1644 errno = ENETUNREACH;
1645 return -1;
1648 switch (si->type) {
1649 case SOCK_STREAM:
1650 type = SOCKET_TYPE_CHAR_TCP_V6;
1651 break;
1652 case SOCK_DGRAM:
1653 type = SOCKET_TYPE_CHAR_UDP_V6;
1654 break;
1655 default:
1656 errno = ESOCKTNOSUPPORT;
1657 return -1;
1660 memset(&in6, 0, sizeof(in6));
1661 in6.sin6_family = AF_INET6;
1662 in6.sin6_addr = *swrap_ipv6();
1663 in6.sin6_addr.s6_addr[15] = socket_wrapper_default_iface();
1664 si->myname_len = sizeof(in6);
1665 si->myname = sockaddr_dup(&in6, si->myname_len);
1666 break;
1668 #endif
1669 default:
1670 errno = ESOCKTNOSUPPORT;
1671 return -1;
1674 if (autobind_start > 60000) {
1675 autobind_start = 10000;
1678 for (i=0;i<1000;i++) {
1679 port = autobind_start + i;
1680 snprintf(un_addr.sun_path, sizeof(un_addr.sun_path),
1681 "%s/"SOCKET_FORMAT, socket_wrapper_dir(),
1682 type, socket_wrapper_default_iface(), port);
1683 if (stat(un_addr.sun_path, &st) == 0) continue;
1685 ret = real_bind(si->fd, (struct sockaddr *)(void *)&un_addr,
1686 sizeof(un_addr));
1687 if (ret == -1) return ret;
1689 si->tmp_path = strdup(un_addr.sun_path);
1690 si->bound = 1;
1691 autobind_start = port + 1;
1692 break;
1694 if (i == 1000) {
1695 errno = ENFILE;
1696 return -1;
1699 si->family = family;
1700 set_port(si->family, port, si->myname);
1702 return 0;
1706 _PUBLIC_ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen)
1708 int ret;
1709 struct sockaddr_un un_addr;
1710 struct socket_info *si = find_socket_info(s);
1711 int bcast = 0;
1713 if (!si) {
1714 return real_connect(s, serv_addr, addrlen);
1717 if (si->bound == 0) {
1718 ret = swrap_auto_bind(si, serv_addr->sa_family);
1719 if (ret == -1) return -1;
1722 if (si->family != serv_addr->sa_family) {
1723 errno = EINVAL;
1724 return -1;
1727 ret = sockaddr_convert_to_un(si, serv_addr,
1728 addrlen, &un_addr, 0, &bcast);
1729 if (ret == -1) return -1;
1731 if (bcast) {
1732 errno = ENETUNREACH;
1733 return -1;
1736 if (si->type == SOCK_DGRAM) {
1737 si->defer_connect = 1;
1738 ret = 0;
1739 } else {
1740 swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0);
1742 ret = real_connect(s, (struct sockaddr *)(void *)&un_addr,
1743 sizeof(struct sockaddr_un));
1746 /* to give better errors */
1747 if (ret == -1 && errno == ENOENT) {
1748 errno = EHOSTUNREACH;
1751 if (ret == 0) {
1752 si->peername_len = addrlen;
1753 si->peername = sockaddr_dup(serv_addr, addrlen);
1754 si->connected = 1;
1756 swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0);
1757 swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0);
1758 } else {
1759 swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_UNREACH, NULL, 0);
1762 return ret;
1765 _PUBLIC_ int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
1767 int ret;
1768 struct sockaddr_un un_addr;
1769 struct socket_info *si = find_socket_info(s);
1771 if (!si) {
1772 return real_bind(s, myaddr, addrlen);
1775 si->myname_len = addrlen;
1776 si->myname = sockaddr_dup(myaddr, addrlen);
1778 ret = sockaddr_convert_to_un(si, myaddr, addrlen, &un_addr, 1, &si->bcast);
1779 if (ret == -1) return -1;
1781 unlink(un_addr.sun_path);
1783 ret = real_bind(s, (struct sockaddr *)(void *)&un_addr,
1784 sizeof(struct sockaddr_un));
1786 if (ret == 0) {
1787 si->bound = 1;
1790 return ret;
1793 _PUBLIC_ int swrap_listen(int s, int backlog)
1795 int ret;
1796 struct socket_info *si = find_socket_info(s);
1798 if (!si) {
1799 return real_listen(s, backlog);
1802 ret = real_listen(s, backlog);
1804 return ret;
1807 _PUBLIC_ int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
1809 struct socket_info *si = find_socket_info(s);
1811 if (!si) {
1812 return real_getpeername(s, name, addrlen);
1815 if (!si->peername)
1817 errno = ENOTCONN;
1818 return -1;
1821 memcpy(name, si->peername, si->peername_len);
1822 *addrlen = si->peername_len;
1824 return 0;
1827 _PUBLIC_ int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
1829 struct socket_info *si = find_socket_info(s);
1831 if (!si) {
1832 return real_getsockname(s, name, addrlen);
1835 memcpy(name, si->myname, si->myname_len);
1836 *addrlen = si->myname_len;
1838 return 0;
1841 _PUBLIC_ int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
1843 struct socket_info *si = find_socket_info(s);
1845 if (!si) {
1846 return real_getsockopt(s, level, optname, optval, optlen);
1849 if (level == SOL_SOCKET) {
1850 return real_getsockopt(s, level, optname, optval, optlen);
1853 errno = ENOPROTOOPT;
1854 return -1;
1857 _PUBLIC_ int swrap_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
1859 struct socket_info *si = find_socket_info(s);
1861 if (!si) {
1862 return real_setsockopt(s, level, optname, optval, optlen);
1865 if (level == SOL_SOCKET) {
1866 return real_setsockopt(s, level, optname, optval, optlen);
1869 switch (si->family) {
1870 case AF_INET:
1871 return 0;
1872 #ifdef HAVE_IPV6
1873 case AF_INET6:
1874 return 0;
1875 #endif
1876 default:
1877 errno = ENOPROTOOPT;
1878 return -1;
1882 _PUBLIC_ int swrap_ioctl(int s, int r, void *p)
1884 int ret;
1885 struct socket_info *si = find_socket_info(s);
1886 int value;
1888 if (!si) {
1889 return real_ioctl(s, r, p);
1892 ret = real_ioctl(s, r, p);
1894 switch (r) {
1895 case FIONREAD:
1896 value = *((int *)p);
1897 if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
1898 swrap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
1899 } else if (value == 0) { /* END OF FILE */
1900 swrap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
1902 break;
1905 return ret;
1908 static ssize_t swrap_sendmsg_before(struct socket_info *si,
1909 struct msghdr *msg,
1910 struct iovec *tmp_iov,
1911 struct sockaddr_un *tmp_un,
1912 const struct sockaddr_un **to_un,
1913 const struct sockaddr **to,
1914 int *bcast)
1916 size_t i, len = 0;
1917 ssize_t ret;
1919 if (to_un) {
1920 *to_un = NULL;
1922 if (to) {
1923 *to = NULL;
1925 if (bcast) {
1926 *bcast = 0;
1929 switch (si->type) {
1930 case SOCK_STREAM:
1931 if (!si->connected) {
1932 errno = ENOTCONN;
1933 return -1;
1936 if (msg->msg_iovlen == 0) {
1937 break;
1941 * cut down to 1500 byte packets for stream sockets,
1942 * which makes it easier to format PCAP capture files
1943 * (as the caller will simply continue from here)
1946 for (i=0; i < msg->msg_iovlen; i++) {
1947 size_t nlen;
1948 nlen = len + msg->msg_iov[i].iov_len;
1949 if (nlen > 1500) {
1950 break;
1953 msg->msg_iovlen = i;
1954 if (msg->msg_iovlen == 0) {
1955 *tmp_iov = msg->msg_iov[0];
1956 tmp_iov->iov_len = MIN(tmp_iov->iov_len, 1500);
1957 msg->msg_iov = tmp_iov;
1958 msg->msg_iovlen = 1;
1960 break;
1962 case SOCK_DGRAM:
1963 if (si->connected) {
1964 if (msg->msg_name) {
1965 errno = EISCONN;
1966 return -1;
1968 } else {
1969 const struct sockaddr *msg_name;
1970 msg_name = (const struct sockaddr *)msg->msg_name;
1972 if (msg_name == NULL) {
1973 errno = ENOTCONN;
1974 return -1;
1978 ret = sockaddr_convert_to_un(si, msg_name, msg->msg_namelen,
1979 tmp_un, 0, bcast);
1980 if (ret == -1) return -1;
1982 if (to_un) {
1983 *to_un = tmp_un;
1985 if (to) {
1986 *to = msg_name;
1988 msg->msg_name = tmp_un;
1989 msg->msg_namelen = sizeof(*tmp_un);
1992 if (si->bound == 0) {
1993 ret = swrap_auto_bind(si, si->family);
1994 if (ret == -1) return -1;
1997 if (!si->defer_connect) {
1998 break;
2001 ret = sockaddr_convert_to_un(si, si->peername, si->peername_len,
2002 tmp_un, 0, NULL);
2003 if (ret == -1) return -1;
2005 ret = real_connect(si->fd, (struct sockaddr *)(void *)tmp_un,
2006 sizeof(*tmp_un));
2008 /* to give better errors */
2009 if (ret == -1 && errno == ENOENT) {
2010 errno = EHOSTUNREACH;
2013 if (ret == -1) {
2014 return ret;
2017 si->defer_connect = 0;
2018 break;
2019 default:
2020 errno = EHOSTUNREACH;
2021 return -1;
2024 return 0;
2027 static void swrap_sendmsg_after(struct socket_info *si,
2028 struct msghdr *msg,
2029 const struct sockaddr *to,
2030 ssize_t ret)
2032 int saved_errno = errno;
2033 size_t i, len = 0;
2034 uint8_t *buf;
2035 off_t ofs = 0;
2036 size_t avail = 0;
2037 size_t remain;
2039 /* to give better errors */
2040 if (ret == -1 && saved_errno == ENOENT) {
2041 saved_errno = EHOSTUNREACH;
2044 for (i=0; i < msg->msg_iovlen; i++) {
2045 avail += msg->msg_iov[i].iov_len;
2048 if (ret == -1) {
2049 remain = MIN(80, avail);
2050 } else {
2051 remain = ret;
2054 /* we capture it as one single packet */
2055 buf = (uint8_t *)malloc(remain);
2056 if (!buf) {
2057 /* we just not capture the packet */
2058 errno = saved_errno;
2059 return;
2062 for (i=0; i < msg->msg_iovlen; i++) {
2063 size_t this_time = MIN(remain, msg->msg_iov[i].iov_len);
2064 memcpy(buf + ofs,
2065 msg->msg_iov[i].iov_base,
2066 this_time);
2067 ofs += this_time;
2068 remain -= this_time;
2070 len = ofs;
2072 switch (si->type) {
2073 case SOCK_STREAM:
2074 if (ret == -1) {
2075 swrap_dump_packet(si, NULL, SWRAP_SEND, buf, len);
2076 swrap_dump_packet(si, NULL, SWRAP_SEND_RST, NULL, 0);
2077 } else {
2078 swrap_dump_packet(si, NULL, SWRAP_SEND, buf, len);
2080 break;
2082 case SOCK_DGRAM:
2083 if (si->connected) {
2084 to = si->peername;
2086 if (ret == -1) {
2087 swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
2088 swrap_dump_packet(si, to, SWRAP_SENDTO_UNREACH, buf, len);
2089 } else {
2090 swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
2092 break;
2095 free(buf);
2096 errno = saved_errno;
2099 _PUBLIC_ ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
2101 struct sockaddr_un un_addr;
2102 socklen_t un_addrlen = sizeof(un_addr);
2103 int ret;
2104 struct socket_info *si = find_socket_info(s);
2105 struct sockaddr_storage ss;
2106 socklen_t ss_len = sizeof(ss);
2108 if (!si) {
2109 return real_recvfrom(s, buf, len, flags, from, fromlen);
2112 if (!from) {
2113 from = (struct sockaddr *)(void *)&ss;
2114 fromlen = &ss_len;
2117 if (si->type == SOCK_STREAM) {
2118 /* cut down to 1500 byte packets for stream sockets,
2119 * which makes it easier to format PCAP capture files
2120 * (as the caller will simply continue from here) */
2121 len = MIN(len, 1500);
2124 /* irix 6.4 forgets to null terminate the sun_path string :-( */
2125 memset(&un_addr, 0, sizeof(un_addr));
2126 ret = real_recvfrom(s, buf, len, flags,
2127 (struct sockaddr *)(void *)&un_addr, &un_addrlen);
2128 if (ret == -1)
2129 return ret;
2131 if (sockaddr_convert_from_un(si, &un_addr, un_addrlen,
2132 si->family, from, fromlen) == -1) {
2133 return -1;
2136 swrap_dump_packet(si, from, SWRAP_RECVFROM, buf, ret);
2138 return ret;
2142 _PUBLIC_ ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
2144 struct msghdr msg;
2145 struct iovec tmp;
2146 struct sockaddr_un un_addr;
2147 const struct sockaddr_un *to_un = NULL;
2148 ssize_t ret;
2149 struct socket_info *si = find_socket_info(s);
2150 int bcast = 0;
2152 if (!si) {
2153 return real_sendto(s, buf, len, flags, to, tolen);
2156 tmp.iov_base = discard_const_p(char, buf);
2157 tmp.iov_len = len;
2159 ZERO_STRUCT(msg);
2160 msg.msg_name = discard_const_p(struct sockaddr, to); /* optional address */
2161 msg.msg_namelen = tolen; /* size of address */
2162 msg.msg_iov = &tmp; /* scatter/gather array */
2163 msg.msg_iovlen = 1; /* # elements in msg_iov */
2164 #if 0 /* not available on solaris */
2165 msg.msg_control = NULL; /* ancillary data, see below */
2166 msg.msg_controllen = 0; /* ancillary data buffer len */
2167 msg.msg_flags = 0; /* flags on received message */
2168 #endif
2170 ret = swrap_sendmsg_before(si, &msg, &tmp, &un_addr, &to_un, &to, &bcast);
2171 if (ret == -1) return -1;
2173 buf = msg.msg_iov[0].iov_base;
2174 len = msg.msg_iov[0].iov_len;
2176 if (bcast) {
2177 struct stat st;
2178 unsigned int iface;
2179 unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
2180 char type;
2182 type = SOCKET_TYPE_CHAR_UDP;
2184 for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
2185 snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
2186 socket_wrapper_dir(), type, iface, prt);
2187 if (stat(un_addr.sun_path, &st) != 0) continue;
2189 /* ignore the any errors in broadcast sends */
2190 real_sendto(s, buf, len, flags,
2191 (struct sockaddr *)(void *)&un_addr,
2192 sizeof(un_addr));
2195 swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
2197 return len;
2200 ret = real_sendto(s, buf, len, flags, msg.msg_name, msg.msg_namelen);
2202 swrap_sendmsg_after(si, &msg, to, ret);
2204 return ret;
2207 _PUBLIC_ ssize_t swrap_recv(int s, void *buf, size_t len, int flags)
2209 int ret;
2210 struct socket_info *si = find_socket_info(s);
2212 if (!si) {
2213 return real_recv(s, buf, len, flags);
2216 if (si->type == SOCK_STREAM) {
2217 /* cut down to 1500 byte packets for stream sockets,
2218 * which makes it easier to format PCAP capture files
2219 * (as the caller will simply continue from here) */
2220 len = MIN(len, 1500);
2223 ret = real_recv(s, buf, len, flags);
2224 if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
2225 swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
2226 } else if (ret == 0) { /* END OF FILE */
2227 swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
2228 } else if (ret > 0) {
2229 swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
2232 return ret;
2235 _PUBLIC_ ssize_t swrap_read(int s, void *buf, size_t len)
2237 int ret;
2238 struct socket_info *si = find_socket_info(s);
2240 if (!si) {
2241 return real_read(s, buf, len);
2244 if (si->type == SOCK_STREAM) {
2245 /* cut down to 1500 byte packets for stream sockets,
2246 * which makes it easier to format PCAP capture files
2247 * (as the caller will simply continue from here) */
2248 len = MIN(len, 1500);
2251 ret = real_read(s, buf, len);
2252 if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
2253 swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
2254 } else if (ret == 0) { /* END OF FILE */
2255 swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
2256 } else if (ret > 0) {
2257 swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
2260 return ret;
2264 _PUBLIC_ ssize_t swrap_send(int s, const void *buf, size_t len, int flags)
2266 struct msghdr msg;
2267 struct iovec tmp;
2268 struct sockaddr_un un_addr;
2269 ssize_t ret;
2270 struct socket_info *si = find_socket_info(s);
2272 if (!si) {
2273 return real_send(s, buf, len, flags);
2276 tmp.iov_base = discard_const_p(char, buf);
2277 tmp.iov_len = len;
2279 ZERO_STRUCT(msg);
2280 msg.msg_name = NULL; /* optional address */
2281 msg.msg_namelen = 0; /* size of address */
2282 msg.msg_iov = &tmp; /* scatter/gather array */
2283 msg.msg_iovlen = 1; /* # elements in msg_iov */
2284 #if 0 /* not available on solaris */
2285 msg.msg_control = NULL; /* ancillary data, see below */
2286 msg.msg_controllen = 0; /* ancillary data buffer len */
2287 msg.msg_flags = 0; /* flags on received message */
2288 #endif
2290 ret = swrap_sendmsg_before(si, &msg, &tmp, &un_addr, NULL, NULL, NULL);
2291 if (ret == -1) return -1;
2293 buf = msg.msg_iov[0].iov_base;
2294 len = msg.msg_iov[0].iov_len;
2296 ret = real_send(s, buf, len, flags);
2298 swrap_sendmsg_after(si, &msg, NULL, ret);
2300 return ret;
2303 _PUBLIC_ ssize_t swrap_sendmsg(int s, const struct msghdr *omsg, int flags)
2305 struct msghdr msg;
2306 struct iovec tmp;
2307 struct sockaddr_un un_addr;
2308 const struct sockaddr_un *to_un = NULL;
2309 const struct sockaddr *to = NULL;
2310 ssize_t ret;
2311 struct socket_info *si = find_socket_info(s);
2312 int bcast = 0;
2314 if (!si) {
2315 return real_sendmsg(s, omsg, flags);
2318 tmp.iov_base = NULL;
2319 tmp.iov_len = 0;
2321 msg = *omsg;
2322 #if 0
2323 msg.msg_name = omsg->msg_name; /* optional address */
2324 msg.msg_namelen = omsg->msg_namelen; /* size of address */
2325 msg.msg_iov = omsg->msg_iov; /* scatter/gather array */
2326 msg.msg_iovlen = omsg->msg_iovlen; /* # elements in msg_iov */
2327 /* the following is not available on solaris */
2328 msg.msg_control = omsg->msg_control; /* ancillary data, see below */
2329 msg.msg_controllen = omsg->msg_controllen; /* ancillary data buffer len */
2330 msg.msg_flags = omsg->msg_flags; /* flags on received message */
2331 #endif
2333 ret = swrap_sendmsg_before(si, &msg, &tmp, &un_addr, &to_un, &to, &bcast);
2334 if (ret == -1) return -1;
2336 if (bcast) {
2337 struct stat st;
2338 unsigned int iface;
2339 unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
2340 char type;
2341 size_t i, len = 0;
2342 uint8_t *buf;
2343 off_t ofs = 0;
2344 size_t avail = 0;
2345 size_t remain;
2347 for (i=0; i < msg.msg_iovlen; i++) {
2348 avail += msg.msg_iov[i].iov_len;
2351 len = avail;
2352 remain = avail;
2354 /* we capture it as one single packet */
2355 buf = (uint8_t *)malloc(remain);
2356 if (!buf) {
2357 return -1;
2360 for (i=0; i < msg.msg_iovlen; i++) {
2361 size_t this_time = MIN(remain, msg.msg_iov[i].iov_len);
2362 memcpy(buf + ofs,
2363 msg.msg_iov[i].iov_base,
2364 this_time);
2365 ofs += this_time;
2366 remain -= this_time;
2369 type = SOCKET_TYPE_CHAR_UDP;
2371 for(iface=0; iface <= MAX_WRAPPED_INTERFACES; iface++) {
2372 snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
2373 socket_wrapper_dir(), type, iface, prt);
2374 if (stat(un_addr.sun_path, &st) != 0) continue;
2376 msg.msg_name = &un_addr; /* optional address */
2377 msg.msg_namelen = sizeof(un_addr); /* size of address */
2379 /* ignore the any errors in broadcast sends */
2380 real_sendmsg(s, &msg, flags);
2383 swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len);
2384 free(buf);
2386 return len;
2389 ret = real_sendmsg(s, &msg, flags);
2391 swrap_sendmsg_after(si, &msg, to, ret);
2393 return ret;
2396 int swrap_readv(int s, const struct iovec *vector, size_t count)
2398 int ret;
2399 struct socket_info *si = find_socket_info(s);
2400 struct iovec v;
2402 if (!si) {
2403 return real_readv(s, vector, count);
2406 if (!si->connected) {
2407 errno = ENOTCONN;
2408 return -1;
2411 if (si->type == SOCK_STREAM && count > 0) {
2412 /* cut down to 1500 byte packets for stream sockets,
2413 * which makes it easier to format PCAP capture files
2414 * (as the caller will simply continue from here) */
2415 size_t i, len = 0;
2417 for (i=0; i < count; i++) {
2418 size_t nlen;
2419 nlen = len + vector[i].iov_len;
2420 if (nlen > 1500) {
2421 break;
2424 count = i;
2425 if (count == 0) {
2426 v = vector[0];
2427 v.iov_len = MIN(v.iov_len, 1500);
2428 vector = &v;
2429 count = 1;
2433 ret = real_readv(s, vector, count);
2434 if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
2435 swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
2436 } else if (ret == 0) { /* END OF FILE */
2437 swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
2438 } else if (ret > 0) {
2439 uint8_t *buf;
2440 off_t ofs = 0;
2441 size_t i;
2442 size_t remain = ret;
2444 /* we capture it as one single packet */
2445 buf = (uint8_t *)malloc(ret);
2446 if (!buf) {
2447 /* we just not capture the packet */
2448 errno = 0;
2449 return ret;
2452 for (i=0; i < count; i++) {
2453 size_t this_time = MIN(remain, vector[i].iov_len);
2454 memcpy(buf + ofs,
2455 vector[i].iov_base,
2456 this_time);
2457 ofs += this_time;
2458 remain -= this_time;
2461 swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
2462 free(buf);
2465 return ret;
2468 int swrap_writev(int s, const struct iovec *vector, size_t count)
2470 struct msghdr msg;
2471 struct iovec tmp;
2472 struct sockaddr_un un_addr;
2473 ssize_t ret;
2474 struct socket_info *si = find_socket_info(s);
2476 if (!si) {
2477 return real_writev(s, vector, count);
2480 tmp.iov_base = NULL;
2481 tmp.iov_len = 0;
2483 ZERO_STRUCT(msg);
2484 msg.msg_name = NULL; /* optional address */
2485 msg.msg_namelen = 0; /* size of address */
2486 msg.msg_iov = discard_const_p(struct iovec, vector); /* scatter/gather array */
2487 msg.msg_iovlen = count; /* # elements in msg_iov */
2488 #if 0 /* not available on solaris */
2489 msg.msg_control = NULL; /* ancillary data, see below */
2490 msg.msg_controllen = 0; /* ancillary data buffer len */
2491 msg.msg_flags = 0; /* flags on received message */
2492 #endif
2494 ret = swrap_sendmsg_before(si, &msg, &tmp, &un_addr, NULL, NULL, NULL);
2495 if (ret == -1) return -1;
2497 ret = real_writev(s, msg.msg_iov, msg.msg_iovlen);
2499 swrap_sendmsg_after(si, &msg, NULL, ret);
2501 return ret;
2504 _PUBLIC_ int swrap_close(int fd)
2506 struct socket_info *si = find_socket_info(fd);
2507 int ret;
2509 if (!si) {
2510 return real_close(fd);
2513 SWRAP_DLIST_REMOVE(sockets, si);
2515 if (si->myname && si->peername) {
2516 swrap_dump_packet(si, NULL, SWRAP_CLOSE_SEND, NULL, 0);
2519 ret = real_close(fd);
2521 if (si->myname && si->peername) {
2522 swrap_dump_packet(si, NULL, SWRAP_CLOSE_RECV, NULL, 0);
2523 swrap_dump_packet(si, NULL, SWRAP_CLOSE_ACK, NULL, 0);
2526 if (si->path) free(si->path);
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;