From 300de6e099ea82ee5361918de8c3abb389e0782d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 8 Jun 2020 10:32:28 +0200 Subject: socket_wrapper.c: implement getsockopt(TCP_INFO) if the platform supports it This just implements a few basics, which are required by Samba. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11897 Signed-off-by: Stefan Metzmacher --- src/socket_wrapper.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'src') diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c index 5b7c9ea..4fb7b23 100644 --- a/src/socket_wrapper.c +++ b/src/socket_wrapper.c @@ -66,6 +66,9 @@ #include #include #include +#ifdef HAVE_NETINET_TCP_FSM_H +#include +#endif #include #include #include @@ -264,6 +267,7 @@ struct socket_info int defer_connect; int pktinfo; int tcp_nodelay; + int listening; /* The unix path so we can unlink it on close() */ struct sockaddr_un un_addr; @@ -4097,6 +4101,9 @@ static int swrap_listen(int s, int backlog) } ret = libc_listen(s, backlog); + if (ret == 0) { + si->listening = 1; + } out: SWRAP_UNLOCK_SI(si); @@ -4446,6 +4453,56 @@ static int swrap_getsockopt(int s, int level, int optname, ret = 0; goto done; #endif /* TCP_NODELAY */ +#ifdef TCP_INFO + case TCP_INFO: { + struct tcp_info info; + socklen_t ilen = sizeof(info); + +#ifdef HAVE_NETINET_TCP_FSM_H +/* This is FreeBSD */ +# define __TCP_LISTEN TCPS_LISTEN +# define __TCP_ESTABLISHED TCPS_ESTABLISHED +# define __TCP_CLOSE TCPS_CLOSED +#else +/* This is Linux */ +# define __TCP_LISTEN TCP_LISTEN +# define __TCP_ESTABLISHED TCP_ESTABLISHED +# define __TCP_CLOSE TCP_CLOSE +#endif + + ZERO_STRUCT(info); + if (si->listening) { + info.tcpi_state = __TCP_LISTEN; + } else if (si->connected) { + /* + * For now we just fake a few values + * supported both by FreeBSD and Linux + */ + info.tcpi_state = __TCP_ESTABLISHED; + info.tcpi_rto = 200000; /* 200 msec */ + info.tcpi_rtt = 5000; /* 5 msec */ + info.tcpi_rttvar = 5000; /* 5 msec */ + } else { + info.tcpi_state = __TCP_CLOSE; + info.tcpi_rto = 1000000; /* 1 sec */ + info.tcpi_rtt = 0; + info.tcpi_rttvar = 250000; /* 250 msec */ + } + + if (optval == NULL || optlen == NULL || + *optlen < (socklen_t)ilen) { + errno = EINVAL; + ret = -1; + goto done; + } + + *optlen = ilen; + memcpy(optval, &info, ilen); + + ret = 0; + goto done; + } +#endif /* TCP_INFO */ default: break; } -- cgit From c95b7cb1d7b9348472276edceff71889aa676d25 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 8 Jun 2020 14:18:44 +0200 Subject: socket_wrapper.c: make FIONREAD handling more robust in swrap_vioctl() We should only dereference the va args when the kernel already checked they are valid. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11897 Signed-off-by: Stefan Metzmacher --- src/socket_wrapper.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c index 4fb7b23..e7a7a8a 100644 --- a/src/socket_wrapper.c +++ b/src/socket_wrapper.c @@ -4635,7 +4635,7 @@ static int swrap_vioctl(int s, unsigned long int r, va_list va) { struct socket_info *si = find_socket_info(s); va_list ap; - int value; + int *value_ptr = NULL; int rc; if (!si) { @@ -4650,11 +4650,13 @@ static int swrap_vioctl(int s, unsigned long int r, va_list va) switch (r) { case FIONREAD: - value = *((int *)va_arg(ap, int *)); + if (rc == 0) { + value_ptr = ((int *)va_arg(ap, int *)); + } if (rc == -1 && errno != EAGAIN && errno != ENOBUFS) { swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0); - } else if (value == 0) { /* END OF FILE */ + } else if (value_ptr != NULL && *value_ptr == 0) { /* END OF FILE */ swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0); } break; -- cgit From f317ebcdcdd626ed9e06de2eb60031306994c803 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 8 Jun 2020 14:21:25 +0200 Subject: socket_wrapper.c: let swrap_vioctl() handle SIOCOUTQ/TIOCOUTQ/FIONWRITE explicitly They are used to ask for the number of unacked bytes in the send queue, with AF_UNIX sockets get strange result, on linux 5.3 I get more bytes reported than I sent into the socket. All bytes reach the destination directly, so we can just always report 0 unacked bytes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11897 Signed-off-by: Stefan Metzmacher --- src/socket_wrapper.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src') diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c index e7a7a8a..333bdd4 100644 --- a/src/socket_wrapper.c +++ b/src/socket_wrapper.c @@ -4660,6 +4660,24 @@ static int swrap_vioctl(int s, unsigned long int r, va_list va) swrap_pcap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0); } break; +#ifdef FIONWRITE + case FIONWRITE: + /* this is FreeBSD */ + FALL_THROUGH; /* to TIOCOUTQ */ +#endif /* FIONWRITE */ + case TIOCOUTQ: /* same as SIOCOUTQ on Linux */ + /* + * This may return more bytes then the application + * sent into the socket, for tcp it should + * return the number of unacked bytes. + * + * On AF_UNIX, all bytes are immediately acked! + */ + if (rc == 0) { + value_ptr = ((int *)va_arg(ap, int *)); + *value_ptr = 0; + } + break; } va_end(ap); -- cgit