rfe2636157 - Permit a delayed UDP connection to overcome unpredictable
NAT ports.
This commit is contained in:
parent
cb03b8fa9a
commit
66658236a7
20
TODO
Normal file
20
TODO
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
netlib.c:196 - set a timeout for waiting for the remote UDP start
|
||||||
|
|
||||||
|
NATHack
|
||||||
|
|
||||||
|
- unify the config as one (local) setting, and use a connection
|
||||||
|
cookie passed to coordinate which side goes passive. The server
|
||||||
|
wins in all ties. auth.c:195
|
||||||
|
|
||||||
|
- lose the global variable and move it into the vtun struct. For
|
||||||
|
now. main.c:54, vtun.h:111
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Comments, suggestion, wishes and if possible patches are always welcome.
|
||||||
|
Send them to vtun-users@lists.sourceforge.net .
|
||||||
|
|
||||||
|
Bishop Clark <bishop@platypus.bc.ca>
|
||||||
|
|
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Id: cfg_kwords.h,v 1.6.2.2 2008/01/07 22:35:26 mtbishop Exp $
|
* $Id: cfg_kwords.h,v 1.6.2.3 2009/03/29 10:08:41 mtbishop Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern int lineno;
|
extern int lineno;
|
||||||
@ -49,6 +49,8 @@ struct kword cfg_keyword[] = {
|
|||||||
{ "encrypt", K_ENCRYPT },
|
{ "encrypt", K_ENCRYPT },
|
||||||
{ "type", K_TYPE },
|
{ "type", K_TYPE },
|
||||||
{ "proto", K_PROT },
|
{ "proto", K_PROT },
|
||||||
|
{ "nat_hack", K_NAT_HACK },
|
||||||
|
{ "delay_udp",K_NAT_HACK },
|
||||||
{ "device", K_DEVICE },
|
{ "device", K_DEVICE },
|
||||||
{ "ppp", K_PPP },
|
{ "ppp", K_PPP },
|
||||||
{ "ifconfig", K_IFCFG },
|
{ "ifconfig", K_IFCFG },
|
||||||
@ -75,6 +77,8 @@ struct kword cfg_param[] = {
|
|||||||
{ "tun", VTUN_TUN },
|
{ "tun", VTUN_TUN },
|
||||||
{ "tcp", VTUN_TCP },
|
{ "tcp", VTUN_TCP },
|
||||||
{ "udp", VTUN_UDP },
|
{ "udp", VTUN_UDP },
|
||||||
|
{ "client", VTUN_NAT_HACK_CLIENT },
|
||||||
|
{ "server", VTUN_NAT_HACK_SERVER },
|
||||||
{ "lzo", VTUN_LZO },
|
{ "lzo", VTUN_LZO },
|
||||||
{ "zlib", VTUN_ZLIB },
|
{ "zlib", VTUN_ZLIB },
|
||||||
{ "wait", 1 },
|
{ "wait", 1 },
|
||||||
|
76
config.h.in
Normal file
76
config.h.in
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/* config.h.in. Generated automatically from configure.in by autoheader. */
|
||||||
|
|
||||||
|
/* Define to empty if the keyword does not work. */
|
||||||
|
#undef const
|
||||||
|
|
||||||
|
/* Define as __inline if that's what the C compiler calls it. */
|
||||||
|
#undef inline
|
||||||
|
|
||||||
|
/* Define if you have the ANSI C header files. */
|
||||||
|
#undef STDC_HEADERS
|
||||||
|
|
||||||
|
/* Define if you have the gettimeofday function. */
|
||||||
|
#undef HAVE_GETTIMEOFDAY
|
||||||
|
|
||||||
|
/* Define if you have the <arpa/inet.h> header file. */
|
||||||
|
#undef HAVE_ARPA_INET_H
|
||||||
|
|
||||||
|
/* Define if you have the <fcntl.h> header file. */
|
||||||
|
#undef HAVE_FCNTL_H
|
||||||
|
|
||||||
|
/* Define if you have the <netinet/in.h> header file. */
|
||||||
|
#undef HAVE_NETINET_IN_H
|
||||||
|
|
||||||
|
/* Define if you have the <netinet/ip.h> header file. */
|
||||||
|
#undef HAVE_NETINET_IP_H
|
||||||
|
|
||||||
|
/* Define if you have the <netinet/tcp.h> header file. */
|
||||||
|
#undef HAVE_NETINET_TCP_H
|
||||||
|
|
||||||
|
/* Define if you have the <netinet/in_systm.h> header file. */
|
||||||
|
#undef HAVE_NETINET_IN_SYSTM_H
|
||||||
|
|
||||||
|
/* Define if you have the <netdb.h> header file. */
|
||||||
|
#undef HAVE_NETDB_H
|
||||||
|
|
||||||
|
/* Define if you have the <sched.h> header file. */
|
||||||
|
#undef HAVE_SCHED_H
|
||||||
|
|
||||||
|
/* Define if you have the <sys/resource.h> header file. */
|
||||||
|
#undef HAVE_SYS_RESOURCE_H
|
||||||
|
|
||||||
|
/* Define if you have the <sys/time.h> header file. */
|
||||||
|
#undef HAVE_SYS_TIME_H
|
||||||
|
|
||||||
|
/* Define if you have the <sys/sockio.h> header file. */
|
||||||
|
#undef HAVE_SYS_SOCKIO_H
|
||||||
|
|
||||||
|
/* Define if you have the <linux/if_tun.h> header file. */
|
||||||
|
#undef HAVE_LINUX_IF_TUN_H
|
||||||
|
|
||||||
|
/* Define if you have setproctitle. */
|
||||||
|
#undef HAVE_SETPROC_TITLE
|
||||||
|
|
||||||
|
#undef HAVE_LIBUTIL_H
|
||||||
|
|
||||||
|
/* Define if you have ZLIB */
|
||||||
|
#undef HAVE_ZLIB
|
||||||
|
|
||||||
|
/* Define if you have LZO */
|
||||||
|
#undef HAVE_LZO
|
||||||
|
|
||||||
|
/* Define if you have OpenSSL */
|
||||||
|
#undef HAVE_SSL
|
||||||
|
|
||||||
|
#undef HAVE_SSL_BLOWFISH
|
||||||
|
|
||||||
|
#undef HAVE_SSL_AES
|
||||||
|
|
||||||
|
#undef HAVE_SSL_EVP
|
||||||
|
|
||||||
|
#undef HAVE_SHAPER
|
||||||
|
|
||||||
|
#undef ENABLE_NAT_HACK
|
||||||
|
|
||||||
|
/* Release version and date */
|
||||||
|
#undef VTUN_VER
|
13
configure.in
13
configure.in
@ -2,7 +2,7 @@ dnl
|
|||||||
dnl VTun - Virtual Tunnel over TCP/IP network.
|
dnl VTun - Virtual Tunnel over TCP/IP network.
|
||||||
dnl Copyright (C) 1998-2006 Maxim Krasnyansky <max_mk@yahoo.com>
|
dnl Copyright (C) 1998-2006 Maxim Krasnyansky <max_mk@yahoo.com>
|
||||||
dnl
|
dnl
|
||||||
dnl $Id: configure.in,v 1.19.2.1 2007/06/29 05:26:01 mtbishop Exp $
|
dnl $Id: configure.in,v 1.19.2.2 2009/03/29 10:08:51 mtbishop Exp $
|
||||||
dnl
|
dnl
|
||||||
dnl Process this file with autoconf to produce a configure script.
|
dnl Process this file with autoconf to produce a configure script.
|
||||||
dnl
|
dnl
|
||||||
@ -41,6 +41,13 @@ AC_ARG_ENABLE(socks,
|
|||||||
SOCKS=no
|
SOCKS=no
|
||||||
)
|
)
|
||||||
|
|
||||||
|
dnl Delayed UDP Start support
|
||||||
|
AC_ARG_ENABLE(nathack,
|
||||||
|
--disable-nathack Do not enable Nat Hack code,
|
||||||
|
NATHACK=$enableval,
|
||||||
|
NATHACK=yes
|
||||||
|
)
|
||||||
|
|
||||||
AC_ARG_WITH(ssl-headers,
|
AC_ARG_WITH(ssl-headers,
|
||||||
--with-ssl-headers=DIR Crypto Include files location,
|
--with-ssl-headers=DIR Crypto Include files location,
|
||||||
SSL_HDR_DIR="$withval"
|
SSL_HDR_DIR="$withval"
|
||||||
@ -212,6 +219,10 @@ if test "$SSL" = "yes"; then
|
|||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "$NATHACK" = "yes"; then
|
||||||
|
AC_DEFINE(ENABLE_NAT_HACK)
|
||||||
|
fi
|
||||||
|
|
||||||
if test "$SOCKS" = "yes"; then
|
if test "$SOCKS" = "yes"; then
|
||||||
AC_MSG_RESULT()
|
AC_MSG_RESULT()
|
||||||
AC_CHECKING( for SOCKS Library ... )
|
AC_CHECKING( for SOCKS Library ... )
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Id: udp_proto.c,v 1.10.2.2 2008/01/07 22:36:19 mtbishop Exp $
|
* $Id: udp_proto.c,v 1.10.2.3 2009/03/29 10:09:13 mtbishop Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -56,12 +56,16 @@
|
|||||||
#include "vtun.h"
|
#include "vtun.h"
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
|
|
||||||
|
extern int is_rmt_fd_connected;
|
||||||
|
|
||||||
/* Functions to read/write UDP frames. */
|
/* Functions to read/write UDP frames. */
|
||||||
int udp_write(int fd, char *buf, int len)
|
int udp_write(int fd, char *buf, int len)
|
||||||
{
|
{
|
||||||
register char *ptr;
|
register char *ptr;
|
||||||
register int wlen;
|
register int wlen;
|
||||||
|
|
||||||
|
if (!is_rmt_fd_connected) return 0;
|
||||||
|
|
||||||
ptr = buf - sizeof(short);
|
ptr = buf - sizeof(short);
|
||||||
|
|
||||||
*((unsigned short *)ptr) = htons(len);
|
*((unsigned short *)ptr) = htons(len);
|
||||||
@ -86,7 +90,25 @@ int udp_read(int fd, char *buf)
|
|||||||
unsigned short hdr, flen;
|
unsigned short hdr, flen;
|
||||||
struct iovec iv[2];
|
struct iovec iv[2];
|
||||||
register int rlen;
|
register int rlen;
|
||||||
|
struct sockaddr_in from;
|
||||||
|
socklen_t fromlen = sizeof(struct sockaddr);
|
||||||
|
|
||||||
|
/* Late connect (NAT hack enabled) */
|
||||||
|
if (!is_rmt_fd_connected) {
|
||||||
|
while( 1 ){
|
||||||
|
if( (rlen = recvfrom(fd,buf,2,MSG_PEEK,(struct sockaddr *)&from,&fromlen)) < 0 ){
|
||||||
|
if( errno == EAGAIN || errno == EINTR ) continue;
|
||||||
|
else return rlen;
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
if( connect(fd,(struct sockaddr *)&from,fromlen) ){
|
||||||
|
vtun_syslog(LOG_ERR,"Can't connect socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
is_rmt_fd_connected = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read frame */
|
/* Read frame */
|
||||||
iv[0].iov_len = sizeof(short);
|
iv[0].iov_len = sizeof(short);
|
||||||
iv[0].iov_base = (char *) &hdr;
|
iv[0].iov_base = (char *) &hdr;
|
||||||
|
10
linkfd.c
10
linkfd.c
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Id: linkfd.c,v 1.13.2.3 2008/01/07 22:35:43 mtbishop Exp $
|
* $Id: linkfd.c,v 1.13.2.4 2009/03/29 10:08:54 mtbishop Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -211,8 +211,12 @@ int lfd_linker(void)
|
|||||||
vtun_syslog(LOG_ERR,"Can't allocate buffer for the linker");
|
vtun_syslog(LOG_ERR,"Can't allocate buffer for the linker");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
proto_write(fd1, buf, VTUN_ECHO_REQ);
|
/* Delay sending of first UDP packet over broken NAT routers
|
||||||
|
because we will probably be disconnected. Wait for the remote
|
||||||
|
end to send us something first, and use that connection. */
|
||||||
|
if (!VTUN_USE_NAT_HACK(lfd_host))
|
||||||
|
proto_write(fd1, buf, VTUN_ECHO_REQ);
|
||||||
|
|
||||||
maxfd = (fd1 > fd2 ? fd1 : fd2) + 1;
|
maxfd = (fd1 > fd2 ? fd1 : fd2) + 1;
|
||||||
|
|
||||||
|
9
main.c
9
main.c
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Id: main.c,v 1.9.2.2 2008/01/07 22:35:53 mtbishop Exp $
|
* $Id: main.c,v 1.9.2.3 2009/03/29 10:08:57 mtbishop Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -50,9 +50,12 @@ void usage(void);
|
|||||||
extern int optind,opterr,optopt;
|
extern int optind,opterr,optopt;
|
||||||
extern char *optarg;
|
extern char *optarg;
|
||||||
|
|
||||||
|
/* for the NATHack bit. Is our UDP session connected? */
|
||||||
|
int is_rmt_fd_connected=1;
|
||||||
|
|
||||||
int main(int argc, char *argv[], char *env[])
|
int main(int argc, char *argv[], char *env[])
|
||||||
{
|
{
|
||||||
int svr, daemon, sock, dofork, fd, opt;
|
int svr, daemon, sock, dofork, fd, opt;
|
||||||
struct vtun_host *host = NULL;
|
struct vtun_host *host = NULL;
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
char *hst;
|
char *hst;
|
||||||
@ -133,6 +136,8 @@ int main(int argc, char *argv[], char *env[])
|
|||||||
openlog("vtund", LOG_PID|LOG_NDELAY|LOG_PERROR, vtun.syslog);
|
openlog("vtund", LOG_PID|LOG_NDELAY|LOG_PERROR, vtun.syslog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear_nat_hack_flags(svr);
|
||||||
|
|
||||||
if(!svr){
|
if(!svr){
|
||||||
if( argc - optind < 2 ){
|
if( argc - optind < 2 ){
|
||||||
usage();
|
usage();
|
||||||
|
14
netlib.c
14
netlib.c
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Id: netlib.c,v 1.11.2.2 2008/01/07 22:35:56 mtbishop Exp $
|
* $Id: netlib.c,v 1.11.2.3 2009/03/29 10:08:59 mtbishop Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -190,10 +190,22 @@ int udp_session(struct vtun_host *host)
|
|||||||
}
|
}
|
||||||
|
|
||||||
saddr.sin_port = port;
|
saddr.sin_port = port;
|
||||||
|
|
||||||
|
/* if the config says to delay the UDP connection, we wait for an
|
||||||
|
incoming packet and then force a connection back. We need to
|
||||||
|
put this here because we need to keep that incoming triggering
|
||||||
|
packet and pass it back up the chain. */
|
||||||
|
|
||||||
|
if (VTUN_USE_NAT_HACK(host))
|
||||||
|
is_rmt_fd_connected=0;
|
||||||
|
else {
|
||||||
if( connect(s,(struct sockaddr *)&saddr,sizeof(saddr)) ){
|
if( connect(s,(struct sockaddr *)&saddr,sizeof(saddr)) ){
|
||||||
vtun_syslog(LOG_ERR,"Can't connect socket");
|
vtun_syslog(LOG_ERR,"Can't connect socket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
is_rmt_fd_connected=1;
|
||||||
|
}
|
||||||
|
|
||||||
host->sopt.rport = htons(port);
|
host->sopt.rport = htons(port);
|
||||||
|
|
||||||
/* Close TCP socket and replace with UDP socket */
|
/* Close TCP socket and replace with UDP socket */
|
||||||
|
13
vtun.h
13
vtun.h
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Id: vtun.h,v 1.12.2.3 2008/01/07 22:36:07 mtbishop Exp $
|
* $Id: vtun.h,v 1.12.2.4 2009/03/29 10:09:11 mtbishop Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _VTUN_H
|
#ifndef _VTUN_H
|
||||||
@ -163,6 +163,17 @@ extern llist host_list;
|
|||||||
#define VTUN_STAT 0x1000
|
#define VTUN_STAT 0x1000
|
||||||
#define VTUN_PERSIST 0x2000
|
#define VTUN_PERSIST 0x2000
|
||||||
|
|
||||||
|
#ifdef ENABLE_NAT_HACK
|
||||||
|
/* Flags for the NAT hack with delayed UDP socket connect */
|
||||||
|
#define VTUN_NAT_HACK_CLIENT 0x4000
|
||||||
|
#define VTUN_NAT_HACK_SERVER 0x8000
|
||||||
|
#define VTUN_NAT_HACK_MASK (VTUN_NAT_HACK_CLIENT | VTUN_NAT_HACK_SERVER)
|
||||||
|
|
||||||
|
#define VTUN_USE_NAT_HACK(host) ((host)->flags & VTUN_NAT_HACK_MASK)
|
||||||
|
#else
|
||||||
|
#define VTUN_USE_NAT_HACK(host) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Constants and flags for VTun protocol */
|
/* Constants and flags for VTun protocol */
|
||||||
#define VTUN_FRAME_SIZE 2048
|
#define VTUN_FRAME_SIZE 2048
|
||||||
#define VTUN_FRAME_OVERHEAD 100
|
#define VTUN_FRAME_OVERHEAD 100
|
||||||
|
15
vtund.conf
15
vtund.conf
@ -6,7 +6,7 @@
|
|||||||
# Ted Rolle <ted@acacia.datacomm.com>
|
# Ted Rolle <ted@acacia.datacomm.com>
|
||||||
#
|
#
|
||||||
# Configuration file example
|
# Configuration file example
|
||||||
# $Id: vtund.conf,v 1.4.2.2 2008/01/07 22:36:05 mtbishop Exp $
|
# $Id: vtund.conf,v 1.4.2.3 2009/03/29 10:09:05 mtbishop Exp $
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Lines which begin with '#' are comments
|
# Lines which begin with '#' are comments
|
||||||
@ -107,6 +107,19 @@
|
|||||||
# This option is ignored by the client.
|
# This option is ignored by the client.
|
||||||
#
|
#
|
||||||
# -----------
|
# -----------
|
||||||
|
# nat_hack - Delay UDP set-up connection until Server or Client sends
|
||||||
|
# a UDP packet, depending on setting. Useful to work around
|
||||||
|
# routers which use mismatched port numbers for UDP traffic.
|
||||||
|
#
|
||||||
|
# 'client' - Delay UDP set-up on the client side
|
||||||
|
# 'server' - Delay UDP set-up on the server side.
|
||||||
|
# 'no' - Disable the NAT hack on both sides (default).
|
||||||
|
#
|
||||||
|
# Setting 'nat_hack client' on the server or 'nat_hack server'
|
||||||
|
# on the client is ignored. Please see the vtund.conf man page
|
||||||
|
# for more details and security information.
|
||||||
|
#
|
||||||
|
# -----------
|
||||||
# persist - Persist mode.
|
# persist - Persist mode.
|
||||||
# 'yes' - Reconnect to the server after connection
|
# 'yes' - Reconnect to the server after connection
|
||||||
# termination.
|
# termination.
|
||||||
|
29
vtund.conf.5
29
vtund.conf.5
@ -1,5 +1,5 @@
|
|||||||
.\" Manual page for vtund.conf
|
.\" Manual page for vtund.conf
|
||||||
.\" $Id: vtund.conf.5,v 1.4.2.1 2007/06/29 05:26:47 mtbishop Exp $
|
.\" $Id: vtund.conf.5,v 1.4.2.2 2009/03/29 10:09:08 mtbishop Exp $
|
||||||
.TH VTUND.CONF 5
|
.TH VTUND.CONF 5
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
@ -145,6 +145,33 @@ protocol to use. By default, \fBvtund\fR(8) will use TCP protocol.
|
|||||||
UDP is recommended for \fBether\fR and \fBtun\fR tunnels only.
|
UDP is recommended for \fBether\fR and \fBtun\fR tunnels only.
|
||||||
This option is ignored by the client.
|
This option is ignored by the client.
|
||||||
|
|
||||||
|
.IP \fBnat_hack\ \fBclient\fR|\fBserver\fR|\fBno\fR
|
||||||
|
side to use nat_hack on. By default, \fBvtund\fR(8) uses a 'no' setting.
|
||||||
|
The side that the NAT hack is enabled on will perform a delayed UDP socket
|
||||||
|
connect. Should only be enabled for the side outside of the NAT (typically
|
||||||
|
the server)! Setting 'client' on the server or 'server' on the client is
|
||||||
|
ignored, as to make a single configuration file reusable on both sides.
|
||||||
|
|
||||||
|
This is only relevant if you use \fBproto udp\fR. The NAT hack delays
|
||||||
|
the UDP socket connect until the first UDP packet is received from the other
|
||||||
|
side of the tunnel. The socket is then connected to the actual source port of
|
||||||
|
the packet (on the NAT box) and not to the one indicated in the handshake
|
||||||
|
(which is behind NAT and probably unreachable).
|
||||||
|
The first echo request is also disabled on the side with the NAT hack enabled.
|
||||||
|
|
||||||
|
Currently the mechanism works only for one side, for a single NAT traversal.
|
||||||
|
If you enable it for both sides, both will wait for a first packet and the
|
||||||
|
tunnel will never transport any data.
|
||||||
|
|
||||||
|
\fBSecurity warning!\fR Due to the nature of the delayed connection, the tunnel
|
||||||
|
can be hijacked in theory by an attacker behind the same NAT, sending the first
|
||||||
|
UDP packet to the server UDP port, before the real client does. If you do not
|
||||||
|
understand the risks, or want to remain as secure as possible behind this kind
|
||||||
|
of NAT router, use \fBproto tcp\fR as a NAT traversal solution.
|
||||||
|
|
||||||
|
Because of the security issue mentioned above, this option might be disabled
|
||||||
|
during compilation (configure --disable-nathack).
|
||||||
|
|
||||||
.IP \fBtimeout\ \fIsecounds\fR
|
.IP \fBtimeout\ \fIsecounds\fR
|
||||||
Connect timeout.
|
Connect timeout.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user