From ed358ff5c72d5384fd4c5e616c1da618f88d06f6 Mon Sep 17 00:00:00 2001
From: Nathan Ferch <nf+github@marginal.net>
Date: Sat, 15 Dec 2012 19:39:32 -0600
Subject: [PATCH] Add timeout option for socks proxies

---
 doc/openvpn.8         |    9 +++++++--
 src/openvpn/init.c    |    3 ++-
 src/openvpn/options.c |   17 +++++++++++++++++
 src/openvpn/options.h |    1 +
 src/openvpn/socks.c   |   20 ++++++++++----------
 src/openvpn/socks.h   |    4 +++-
 6 files changed, 40 insertions(+), 14 deletions(-)

diff --git a/doc/openvpn.8 b/doc/openvpn.8
index 2ed5201..2494ac0 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -365,6 +365,7 @@ block:
 .B rport,
 .B socks-proxy,
 .B socks-proxy-retry,
+.B socks-proxy-timeout,
 .B tun-mtu and
 .B tun-mtu-extra.

@@ -567,6 +568,10 @@ Retry indefinitely on Socks proxy errors.  If a Socks proxy error
 occurs, simulate a SIGUSR1 reset.
 .\"*********************************************************
 .TP
+.B \-\-socks-proxy-timeout [seconds]
+Timeout for connections through Socks proxy. (default=5)
+.\"*********************************************************
+.TP
 .B \-\-resolv-retry n
 If hostname resolve fails for
 .B \-\-remote,
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index 25d8225..47ab9a6 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -472,7 +472,8 @@ init_proxy_dowork (struct context *c)
       c->c1.socks_proxy = socks_proxy_new (c->options.ce.socks_proxy_server,
 					   c->options.ce.socks_proxy_port,
 					   c->options.ce.socks_proxy_authfile,
-					   c->options.ce.socks_proxy_retry);
+					   c->options.ce.socks_proxy_retry,
+					   c->options.ce.socks_proxy_timeout);
       if (c->c1.socks_proxy)
 	{
 	  c->c1.socks_proxy_owned = true;
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 33dbf51..08b16c7 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -158,6 +158,7 @@ static const char usage_message[] =
   "                  up is a file containing username/password on 2 lines, or\n"
   "                  'stdin' to prompt for console.\n"
   "--socks-proxy-retry : Retry indefinitely on Socks proxy errors.\n"
+  "--socks-proxy-timeout n : Socks proxy timeout in seconds, default=5.\n"
 #endif
   "--resolv-retry n: If hostname resolve fails for --remote, retry\n"
   "                  resolve for n seconds before failing (disabled by default).\n"
@@ -870,6 +871,10 @@ init_options (struct options *o, const bool init_gc)
   }
 #endif /* WIN32 */
 #endif /* P2MP_SERVER */
+#ifdef ENABLE_SOCKS
+  /* previously hardcoded in socks.c */
+  o->ce.socks_proxy_timeout=5;
+#endif /* ENABLE_SOCKS */
 }
 
 void
@@ -1356,6 +1361,7 @@ show_connection_entry (const struct connection_entry *o)
   SHOW_STR (socks_proxy_server);
   SHOW_INT (socks_proxy_port);
   SHOW_BOOL (socks_proxy_retry);
+  SHOW_INT (socks_proxy_timeout);
 #endif
   SHOW_INT (tun_mtu);
   SHOW_BOOL (tun_mtu_defined);
@@ -5009,6 +5015,17 @@ add_option (struct options *options,
       options->ce.socks_proxy_server = p[1];
       options->ce.socks_proxy_authfile = p[3]; /* might be NULL */
     }
+  else if (streq (p[0], "socks-proxy-timeout") && p[1])
+    {
+      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
+
+      if (p[1])
+	{
+	  int timeout;
+          timeout = positive_atoi (p[1]);
+          options->ce.socks_proxy_timeout = timeout;
+	}
+    }
   else if (streq (p[0], "socks-proxy-retry"))
     {
       VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
index 306520b..4c4dcdb 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -108,6 +108,7 @@ struct connection_entry
   int socks_proxy_port;
   const char *socks_proxy_authfile;
   bool socks_proxy_retry;
+  int socks_proxy_timeout;
 #endif
 
   int tun_mtu;           /* MTU of tun device */
diff --git a/src/openvpn/socks.c b/src/openvpn/socks.c
index 235982e..e6d1c46 100644
--- a/src/openvpn/socks.c
+++ b/src/openvpn/socks.c
@@ -63,7 +63,8 @@ struct socks_proxy_info *
 socks_proxy_new (const char *server,
 		 int port,
 		 const char *authfile,
-		 bool retry)
+		 bool retry,
+		 int timeout)
 {
   struct socks_proxy_info *p;
 
@@ -81,6 +82,7 @@ socks_proxy_new (const char *server,
     p->authfile[0] = 0;
 
   p->retry = retry;
+  p->timeout = timeout;
   p->defined = true;
 
   return p;
@@ -100,7 +102,6 @@ socks_username_password_auth (struct socks_proxy_info *p,
   char to_send[516];
   char buf[2];
   int len = 0;
-  const int timeout_sec = 5;
   struct user_pass creds;
   ssize_t size;
 
@@ -134,7 +135,7 @@ socks_username_password_auth (struct socks_proxy_info *p,
 
       FD_ZERO (&reads);
       FD_SET (sd, &reads);
-      tv.tv_sec = timeout_sec;
+      tv.tv_sec = p->timeout;
       tv.tv_usec = 0;
 
       status = select (sd + 1, &reads, NULL, NULL, &tv);
@@ -188,7 +189,6 @@ socks_handshake (struct socks_proxy_info *p,
 {
   char buf[2];
   int len = 0;
-  const int timeout_sec = 5;
 
   /* VER = 5, NMETHODS = 2, METHODS = [0 (no auth), 2 (plain login)] */
   const ssize_t size = send (sd, "\x05\x02\x00\x02", 4, MSG_NOSIGNAL);
@@ -208,7 +208,7 @@ socks_handshake (struct socks_proxy_info *p,
 
       FD_ZERO (&reads);
       FD_SET (sd, &reads);
-      tv.tv_sec = timeout_sec;
+      tv.tv_sec = p->timeout;
       tv.tv_usec = 0;
 
       status = select (sd + 1, &reads, NULL, NULL, &tv);
@@ -282,13 +282,13 @@ socks_handshake (struct socks_proxy_info *p,
 static bool
 recv_socks_reply (socket_descriptor_t sd,
 		  struct openvpn_sockaddr *addr,
-		  volatile int *signal_received)
+		  volatile int *signal_received,
+		  int timeout)
 {
   char atyp = '\0';
   int alen = 0;
   int len = 0;
   char buf[22];
-  const int timeout_sec = 5;
 
   if (addr != NULL)
     {
@@ -307,7 +307,7 @@ recv_socks_reply (socket_descriptor_t sd,
 
       FD_ZERO (&reads);
       FD_SET (sd, &reads);
-      tv.tv_sec = timeout_sec;
+      tv.tv_sec = timeout;
       tv.tv_usec = 0;
 
       status = select (sd + 1, &reads, NULL, NULL, &tv);
@@ -427,7 +427,7 @@ establish_socks_proxy_passthru (struct socks_proxy_info *p,
   }
 
   /* receive reply from Socks proxy and discard */
-  if (!recv_socks_reply (sd, NULL, signal_received))
+  if (!recv_socks_reply (sd, NULL, signal_received, p->timeout))
     goto error;
 
   return;
@@ -465,7 +465,7 @@ establish_socks_proxy_udpassoc (struct socks_proxy_info *p,
 
   /* receive reply from Socks proxy */
   CLEAR (*relay_addr);
-  if (!recv_socks_reply (ctrl_sd, relay_addr, signal_received))
+  if (!recv_socks_reply (ctrl_sd, relay_addr, signal_received, p->timeout))
     goto error;
 
   return;
diff --git a/src/openvpn/socks.h b/src/openvpn/socks.h
index b55ff6f..3c131fd 100644
--- a/src/openvpn/socks.h
+++ b/src/openvpn/socks.h
@@ -44,6 +44,7 @@ struct socks_proxy_info {
   char server[128];
   int port;
   char authfile[256];
+  int timeout;
 };
 
 void socks_adjust_frame_parameters (struct frame *frame, int proto);
@@ -51,7 +52,8 @@ void socks_adjust_frame_parameters (struct frame *frame, int proto);
 struct socks_proxy_info *socks_proxy_new (const char *server,
 					  int port,
 					  const char *authfile,
-					  bool retry);
+					  bool retry,
+					  int timeout);
 
 void socks_proxy_close (struct socks_proxy_info *sp);
 
-- 
1.7.10.4

