Browse code

Added --port-share option for allowing OpenVPN and HTTPS server to share the same port number.

git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@893 e7ae566f-a301-0410-adde-c780ea21d3b5

james authored on 2006/02/17 03:12:24
Showing 24 changed files
... ...
@@ -3,8 +3,10 @@ Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
3 3
 
4 4
 $Id$
5 5
 
6
-2006.xx.xx -- Version 2.1-beta9
6
+2006.02.16 -- Version 2.1-beta9
7 7
 
8
+* Added --port-share option for allowing OpenVPN and HTTPS
9
+  server to share the same port number.
8 10
 * Added --management-client option to connect as a client
9 11
   to management GUI app rather than be connected to as a
10 12
   server.
... ...
@@ -79,6 +79,7 @@ openvpn_SOURCES = \
79 79
 	pool.c pool.h \
80 80
 	proto.c proto.h \
81 81
 	proxy.c proxy.h \
82
+        ps.c ps.h \
82 83
 	push.c push.h \
83 84
 	reliable.c reliable.h \
84 85
 	route.c route.h \
... ...
@@ -25,7 +25,7 @@ dnl Process this file with autoconf to produce a configure script.
25 25
 
26 26
 AC_PREREQ(2.50)
27 27
 
28
-AC_INIT([OpenVPN], [2.1_beta8b], [openvpn-users@lists.sourceforge.net], [openvpn])
28
+AC_INIT([OpenVPN], [2.1_beta8c], [openvpn-users@lists.sourceforge.net], [openvpn])
29 29
 AM_CONFIG_HEADER(config.h)
30 30
 AC_CONFIG_SRCDIR(syshead.h)
31 31
 
... ...
@@ -101,6 +101,12 @@ AC_ARG_ENABLE(multihome,
101 101
    [MULTIHOME="yes"]
102 102
 )
103 103
 
104
+AC_ARG_ENABLE(port-share,
105
+   [  --disable-port-share    Disable TCP server port-share support (--port-share)],
106
+   [PORT_SHARE="$enableval"],
107
+   [PORT_SHARE="yes"]
108
+)
109
+
104 110
 AC_ARG_ENABLE(debug,
105 111
    [  --disable-debug         Disable debugging support (disable gremlin and verb 7+ messages)],
106 112
    [DEBUG="$enableval"],
... ...
@@ -636,6 +642,11 @@ if test "$FRAGMENT" = "yes"; then
636 636
    AC_DEFINE(ENABLE_FRAGMENT, 1, [Enable internal fragmentation support])
637 637
 fi
638 638
 
639
+dnl enable --port-share
640
+if test "$PORT_SHARE" = "yes"; then
641
+   AC_DEFINE(ENABLE_PORT_SHARE, 1, [Enable TCP Server port sharing])
642
+fi
643
+
639 644
 dnl enable strict compiler warnings
640 645
 if test "$STRICT" = "yes"; then
641 646
    CFLAGS="$CFLAGS -Wall -Wpointer-arith -Wsign-compare -Wno-unused-parameter -Wno-unused-function"
... ...
@@ -93,6 +93,7 @@
93 93
 #define D_SCHED_EXIT         LOGLEV(3, 42, 0)        /* show arming of scheduled exit */
94 94
 #define D_ROUTE_QUOTA        LOGLEV(3, 43, 0)        /* show route quota exceeded messages */
95 95
 #define D_OSBUF              LOGLEV(3, 44, 0)        /* show socket/tun/tap buffer sizes */
96
+#define D_PS_PROXY           LOGLEV(3, 45, 0)        /* messages related to --port-share option */
96 97
 
97 98
 #define D_SHOW_PARMS         LOGLEV(4, 50, 0)        /* show all parameters on program initiation */
98 99
 #define D_SHOW_OCC           LOGLEV(4, 51, 0)        /* show options compatibility string */
... ...
@@ -132,6 +133,7 @@
132 132
 #define D_ALIGN_DEBUG        LOGLEV(7, 70, M_DEBUG)  /* show verbose struct alignment info */
133 133
 #define D_PACKET_TRUNC_DEBUG LOGLEV(7, 70, M_DEBUG)  /* PACKET_TRUNCATION_CHECK verbose */
134 134
 #define D_PING               LOGLEV(7, 70, M_DEBUG)  /* PING send/receive messages */
135
+#define D_PS_PROXY_DEBUG     LOGLEV(7, 70, M_DEBUG)  /* port share proxy debug */
135 136
 
136 137
 #define D_HANDSHAKE_VERBOSE  LOGLEV(8, 70, M_DEBUG)  /* show detailed description of each handshake */
137 138
 #define D_TLS_DEBUG_MED      LOGLEV(8, 70, M_DEBUG)  /* limited info from tls_session routines */
... ...
@@ -41,6 +41,7 @@
41 41
 #include "perf.h"
42 42
 #include "status.h"
43 43
 #include "integer.h"
44
+#include "ps.h"
44 45
 
45 46
 #ifdef USE_CRYPTO
46 47
 #include <openssl/err.h>
... ...
@@ -88,6 +89,15 @@ static char *pgmname_syslog;  /* GLOBAL */
88 88
 /* If non-null, messages should be written here (used for debugging only) */
89 89
 static FILE *msgfp;         /* GLOBAL */
90 90
 
91
+/* If true, we forked from main OpenVPN process */
92
+static bool forked;         /* GLOBAL */
93
+
94
+void
95
+msg_forked (void)
96
+{
97
+  forked = true;
98
+}
99
+
91 100
 bool
92 101
 set_debug_level (const int level, const unsigned int flags)
93 102
 {
... ...
@@ -270,21 +280,22 @@ void x_msg (const unsigned int flags, const char *format, ...)
270 270
     prefix_sep = prefix = "";
271 271
 
272 272
   /* virtual output capability used to copy output to management subsystem */
273
-  {
274
-    const struct virtual_output *vo = msg_get_virtual_output ();
275
-    if (vo)
276
-      {
277
-	openvpn_snprintf (m2, ERR_BUF_SIZE, "%s%s%s",
278
-			  prefix,
279
-			  prefix_sep,
280
-			  m1);
281
-	virtual_output_print (vo, flags, m2);
282
-      }
283
-  }
273
+  if (!forked)
274
+    {
275
+      const struct virtual_output *vo = msg_get_virtual_output ();
276
+      if (vo)
277
+	{
278
+	  openvpn_snprintf (m2, ERR_BUF_SIZE, "%s%s%s",
279
+			    prefix,
280
+			    prefix_sep,
281
+			    m1);
282
+	  virtual_output_print (vo, flags, m2);
283
+	}
284
+    }
284 285
 
285 286
   if (!(flags & M_MSG_VIRT_OUT))
286 287
     {
287
-      if (use_syslog && !std_redir)
288
+      if (use_syslog && !std_redir && !forked)
288 289
 	{
289 290
 #if SYSLOG_CAPABILITY
290 291
 	  syslog (level, "%s%s%s",
... ...
@@ -674,6 +685,11 @@ openvpn_exit (const int status)
674 674
   plugin_abort ();
675 675
 #endif
676 676
 
677
+#if PORT_SHARE
678
+  if (port_share)
679
+    port_share_abort (port_share);
680
+#endif
681
+
677 682
 #ifdef ABORT_ON_ERROR
678 683
   if (status == OPENVPN_EXIT_STATUS_ERROR)
679 684
     abort ();
... ...
@@ -196,7 +196,7 @@ FILE *msg_fp(void);
196 196
 void assert_failed (const char *filename, int line);
197 197
 
198 198
 #ifdef ENABLE_DEBUG
199
-void crash (void); // force a segfault (debugging only)
199
+void crash (void); /* force a segfault (debugging only) */
200 200
 #endif
201 201
 
202 202
 /* Inline functions */
... ...
@@ -207,6 +207,9 @@ check_debug_level (unsigned int level)
207 207
   return (level & M_DEBUG_LEVEL) <= x_debug_level;
208 208
 }
209 209
 
210
+/* Call if we forked */
211
+void msg_forked (void);
212
+
210 213
 /* syslog output */
211 214
 
212 215
 void open_syslog (const char *pgmname, bool stdio_to_null);
... ...
@@ -33,9 +33,9 @@
33 33
  * rwflags passed to event_ctl and returned by
34 34
  * struct event_set_return.
35 35
  */
36
+#define EVENT_UNDEF    4
36 37
 #define EVENT_READ     (1<<0)
37 38
 #define EVENT_WRITE    (1<<1)
38
-
39 39
 /*
40 40
  * Initialization flags passed to event_set_init
41 41
  */
... ...
@@ -98,7 +98,8 @@ struct event_set *event_set_init (int *maxevents, unsigned int flags);
98 98
 static inline void
99 99
 event_free (struct event_set *es)
100 100
 {
101
-  (*es->func.free)(es);
101
+  if (es)
102
+    (*es->func.free)(es);
102 103
 }
103 104
 
104 105
 static inline void
... ...
@@ -36,25 +36,43 @@
36 36
 #include "memdbg.h"
37 37
 
38 38
 /* Set a file descriptor to non-blocking */
39
-void
40
-set_nonblock (int fd)
39
+bool
40
+set_nonblock_action (int fd)
41 41
 {
42 42
 #ifdef WIN32
43 43
   u_long arg = 1;
44 44
   if (ioctlsocket (fd, FIONBIO, &arg))
45
-    msg (M_SOCKERR, "Set socket to non-blocking mode failed");
45
+    return false;
46 46
 #else
47 47
   if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
48
-    msg (M_ERR, "Set file descriptor to non-blocking mode failed");
48
+    return false;
49 49
 #endif
50
+  return true;
50 51
 }
51 52
 
52 53
 /* Set a file descriptor to not be passed across execs */
53
-void
54
-set_cloexec (int fd)
54
+bool
55
+set_cloexec_action (int fd)
55 56
 {
56 57
 #ifndef WIN32
57 58
   if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
58
-    msg (M_ERR, "Set FD_CLOEXEC flag on file descriptor failed");
59
+    return false;
59 60
 #endif
61
+  return true;
62
+}
63
+
64
+/* Set a file descriptor to non-blocking */
65
+void
66
+set_nonblock (int fd)
67
+{
68
+  if (!set_nonblock_action (fd))
69
+    msg (M_SOCKERR, "Set socket to non-blocking mode failed");
70
+}
71
+
72
+/* Set a file descriptor to not be passed across execs */
73
+void
74
+set_cloexec (int fd)
75
+{
76
+  if (!set_cloexec_action (fd))
77
+    msg (M_ERR, "Set FD_CLOEXEC flag on file descriptor failed");
60 78
 }
... ...
@@ -22,5 +22,10 @@
22 22
  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 23
  */
24 24
 
25
+#include "basic.h"
26
+
27
+bool set_nonblock_action (int fd);
28
+bool set_cloexec_action (int fd);
29
+
25 30
 void set_nonblock (int fd);
26 31
 void set_cloexec (int fd);
... ...
@@ -36,6 +36,7 @@
36 36
 #include "gremlin.h"
37 37
 #include "mss.h"
38 38
 #include "event.h"
39
+#include "ps.h"
39 40
 
40 41
 #include "memdbg.h"
41 42
 
... ...
@@ -640,18 +641,31 @@ read_incoming_link (struct context *c)
640 640
 
641 641
   if (socket_connection_reset (c->c2.link_socket, status))
642 642
     {
643
-      /* received a disconnect from a connection-oriented protocol */
644
-      if (c->options.inetd)
643
+#if PORT_SHARE
644
+      if (port_share && socket_foreign_protocol_detected (c->c2.link_socket))
645 645
 	{
646
+	  const struct buffer *fbuf = socket_foreign_protocol_head (c->c2.link_socket);
647
+	  const int sd = socket_foreign_protocol_sd (c->c2.link_socket);
648
+	  port_share_redirect (port_share, fbuf, sd);
646 649
 	  c->sig->signal_received = SIGTERM;
647
-	  msg (D_STREAM_ERRORS, "Connection reset, inetd/xinetd exit [%d]", status);
650
+	  c->sig->signal_text = "port-share-redirect";
648 651
 	}
649 652
       else
650
-	{
651
-	  c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- TCP connection reset */
652
-	  msg (D_STREAM_ERRORS, "Connection reset, restarting [%d]", status);
653
-	}
654
-      c->sig->signal_text = "connection-reset";
653
+#endif
654
+      {
655
+	/* received a disconnect from a connection-oriented protocol */
656
+	if (c->options.inetd)
657
+	  {
658
+	    c->sig->signal_received = SIGTERM;
659
+	    msg (D_STREAM_ERRORS, "Connection reset, inetd/xinetd exit [%d]", status);
660
+	  }
661
+	else
662
+	  {
663
+	    c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- TCP connection reset */
664
+	    msg (D_STREAM_ERRORS, "Connection reset, restarting [%d]", status);
665
+	  }
666
+	c->sig->signal_text = "connection-reset";
667
+      }
655 668
       perf_pop ();
656 669
       return;
657 670
     }
... ...
@@ -39,6 +39,7 @@
39 39
 #include "pool.h"
40 40
 #include "gremlin.h"
41 41
 #include "pkcs11.h"
42
+#include "ps.h"
42 43
 
43 44
 #include "memdbg.h"
44 45
 
... ...
@@ -191,6 +192,32 @@ context_gc_free (struct context *c)
191 191
   gc_free (&c->gc);
192 192
 }
193 193
 
194
+#if PORT_SHARE
195
+
196
+static void
197
+close_port_share (void)
198
+{
199
+  if (port_share)
200
+    {
201
+      port_share_close (port_share);
202
+      port_share = NULL;
203
+    }
204
+}
205
+
206
+static void
207
+init_port_share (struct context *c)
208
+{
209
+  if (!port_share && (c->options.port_share_host && c->options.port_share_port))
210
+    {
211
+      port_share = port_share_open (c->options.port_share_host,
212
+				    c->options.port_share_port);
213
+      if (port_share == NULL)
214
+	msg (M_FATAL, "Fatal error: Port sharing failed");
215
+    }
216
+}
217
+
218
+#endif
219
+
194 220
 bool
195 221
 init_static (void)
196 222
 {
... ...
@@ -274,6 +301,10 @@ uninit_static (void)
274 274
   pkcs11_terminate ();
275 275
 #endif
276 276
 
277
+#if PORT_SHARE
278
+  close_port_share ();
279
+#endif
280
+
277 281
 #if defined(MEASURE_TLS_HANDSHAKE_STATS) && defined(USE_CRYPTO) && defined(USE_SSL)
278 282
   show_tls_performance_stats ();
279 283
 #endif
... ...
@@ -1490,6 +1521,11 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
1490 1490
   to.renegotiate_seconds = options->renegotiate_seconds;
1491 1491
   to.single_session = options->single_session;
1492 1492
 
1493
+  /* should we not xmit any packets until we get an initial
1494
+     response from client? */
1495
+  if (to.server && options->proto == PROTO_TCPv4_SERVER)
1496
+    to.xmit_hold = true;
1497
+
1493 1498
 #ifdef ENABLE_OCC
1494 1499
   to.disable_occ = !options->occ;
1495 1500
 #endif
... ...
@@ -2659,6 +2695,12 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
2659 2659
     open_plugins (c, false, OPENVPN_PLUGIN_INIT_POST_UID_CHANGE);
2660 2660
 #endif
2661 2661
 
2662
+#if PORT_SHARE
2663
+  /* share OpenVPN port with foreign (such as HTTPS) server */
2664
+  if (c->first_time && (c->mode == CM_P2P || c->mode == CM_TOP))
2665
+    init_port_share (c);
2666
+#endif
2667
+	  
2662 2668
   /* Check for signals */
2663 2669
   if (IS_SIG (c))
2664 2670
     goto sig;
... ...
@@ -217,6 +217,7 @@ openvpn \- secure IP tunnel daemon.
217 217
 [\ \fB\-\-pkcs12\fR\ \fIfile\fR\ ]
218 218
 [\ \fB\-\-plugin\fR\ \fImodule\-pathname\ init\-string\fR\ ]
219 219
 [\ \fB\-\-port\fR\ \fIport\fR\ ]
220
+[\ \fB\-\-port\-share\fR\ \fIhost\ port\fR\ ]
220 221
 [\ \fB\-\-proto\fR\ \fIp\fR\ ]
221 222
 [\ \fB\-\-pull\fR\ ]
222 223
 [\ \fB\-\-push\-reset\fR\ ]
... ...
@@ -2971,6 +2972,23 @@ authentication, use
2971 2971
 the authenticated username as the common name,
2972 2972
 rather than the common name from the client cert.
2973 2973
 .\"*********************************************************
2974
+.TP
2975
+.B --port-share host port
2976
+When run in TCP server mode, share the OpenVPN port with
2977
+another application, such as an HTTPS server.  If OpenVPN
2978
+senses a connection to its port which is using a non-OpenVPN
2979
+protocol, it will proxy the connection to the server at
2980
+.B host:port.
2981
+Currently only designed to work with HTTPS,
2982
+though it would be theoretically possible to extend to
2983
+other protocols such as ssh.
2984
+
2985
+Currently only implemented
2986
+on Linux, though porting to BSDs should be straightforward.
2987
+The reason for the non-portability is that the current implementation
2988
+uses sendmsg and recvmsg for passing file descriptors between
2989
+processes.
2990
+.\"*********************************************************
2974 2991
 .SS Client Mode
2975 2992
 Use client mode when connecting to an OpenVPN server
2976 2993
 which has
... ...
@@ -192,7 +192,7 @@ main (int argc, char *argv[])
192 192
 	  if (!open_management (&c))
193 193
 	    break;
194 194
 #endif
195
-	  
195
+
196 196
 	  /* set certain options as environmental variables */
197 197
 	  setenv_settings (c.es, &c.options);
198 198
 
... ...
@@ -363,6 +363,10 @@ static const char usage_message[] =
363 363
   "--connect-freq n s : Allow a maximum of n new connections per s seconds.\n"
364 364
   "--max-clients n : Allow a maximum of n simultaneously connected clients.\n"
365 365
   "--max-routes-per-client n : Allow a maximum of n internal routes per client.\n"
366
+#if PORT_SHARE
367
+  "--port-share host port : When run in TCP mode, proxy incoming HTTPS sessions\n"
368
+  "                  to a web server at host:port.\n"
369
+#endif
366 370
 #endif
367 371
   "\n"
368 372
   "Client options (when connecting to a multi-client server):\n"
... ...
@@ -918,6 +922,10 @@ show_p2mp_parms (const struct options *o)
918 918
   SHOW_BOOL (username_as_common_name)
919 919
   SHOW_STR (auth_user_pass_verify_script);
920 920
   SHOW_BOOL (auth_user_pass_verify_script_via_file);
921
+#if PORT_SHARE
922
+  SHOW_STR (port_share_host);
923
+  SHOW_INT (port_share_port);
924
+#endif
921 925
 #endif /* P2MP_SERVER */
922 926
 
923 927
   SHOW_BOOL (client);
... ...
@@ -1594,6 +1602,10 @@ options_postprocess (struct options *options, bool first_time)
1594 1594
 	msg (M_USAGE, "--pull cannot be used with --mode server");
1595 1595
       if (!(options->proto == PROTO_UDPv4 || options->proto == PROTO_TCPv4_SERVER))
1596 1596
 	msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server");
1597
+#if PORT_SHARE
1598
+      if ((options->port_share_host || options->port_share_port) && options->proto != PROTO_TCPv4_SERVER)
1599
+	msg (M_USAGE, "--port-share only works in TCP server mode (--proto tcp-server)");
1600
+#endif
1597 1601
       if (!options->tls_server)
1598 1602
 	msg (M_USAGE, "--mode server requires --tls-server");
1599 1603
       if (options->remote_list)
... ...
@@ -1682,6 +1694,11 @@ options_postprocess (struct options *options, bool first_time)
1682 1682
 	msg (M_USAGE, "--username-as-common-name requires --mode server");
1683 1683
       if (options->auth_user_pass_verify_script)
1684 1684
 	msg (M_USAGE, "--auth-user-pass-verify requires --mode server");
1685
+#if PORT_SHARE
1686
+      if (options->port_share_host || options->port_share_port)
1687
+	msg (M_USAGE, "--port-share requires TCP server mode (--mode server --proto tcp-server)");
1688
+#endif
1689
+
1685 1690
     }
1686 1691
 #endif /* P2MP_SERVER */
1687 1692
 
... ...
@@ -4234,6 +4251,23 @@ add_option (struct options *options,
4234 4234
 	msg (msglevel, "--tcp-queue-limit parameter must be > 0");
4235 4235
       options->tcp_queue_limit = tcp_queue_limit;
4236 4236
     }
4237
+#if PORT_SHARE
4238
+  else if (streq (p[0], "port-share") && p[1] && p[2])
4239
+    {
4240
+      int port;
4241
+
4242
+      VERIFY_PERMISSION (OPT_P_GENERAL);
4243
+      port = atoi (p[2]);
4244
+      if (!legal_ipv4_port (port))
4245
+	{
4246
+	  msg (msglevel, "port number associated with --port-share directive is out of range");
4247
+	  goto err;
4248
+	}
4249
+
4250
+      options->port_share_host = p[1];
4251
+      options->port_share_port = port;
4252
+    }
4253
+#endif
4237 4254
   else if (streq (p[0], "client-to-client"))
4238 4255
     {
4239 4256
       VERIFY_PERMISSION (OPT_P_GENERAL);
... ...
@@ -344,6 +344,10 @@ struct options
344 344
   bool username_as_common_name;
345 345
   const char *auth_user_pass_verify_script;
346 346
   bool auth_user_pass_verify_script_via_file;
347
+#if PORT_SHARE
348
+  char *port_share_host;
349
+  int port_share_port;
350
+#endif
347 351
 #endif
348 352
 
349 353
   bool client;
350 354
new file mode 100644
... ...
@@ -0,0 +1,783 @@
0
+/*
1
+ *  OpenVPN -- An application to securely tunnel IP networks
2
+ *             over a single UDP port, with support for SSL/TLS-based
3
+ *             session authentication and key exchange,
4
+ *             packet encryption, packet authentication, and
5
+ *             packet compression.
6
+ *
7
+ *  Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
8
+ *
9
+ *  This program is free software; you can redistribute it and/or modify
10
+ *  it under the terms of the GNU General Public License version 2
11
+ *  as published by the Free Software Foundation.
12
+ *
13
+ *  This program is distributed in the hope that it will be useful,
14
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ *  GNU General Public License for more details.
17
+ *
18
+ *  You should have received a copy of the GNU General Public License
19
+ *  along with this program (see the file COPYING included with this
20
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
21
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
+ */
23
+
24
+#ifdef WIN32
25
+#include "config-win32.h"
26
+#else
27
+#include "config.h"
28
+#endif
29
+
30
+#include "syshead.h"
31
+
32
+#if PORT_SHARE
33
+
34
+#include "event.h"
35
+#include "socket.h"
36
+#include "fdmisc.h"
37
+#include "ps.h"
38
+
39
+#include "memdbg.h"
40
+
41
+struct port_share *port_share = NULL; /* GLOBAL */
42
+
43
+/* size of i/o buffers */
44
+#define PROXY_CONNECTION_BUFFER_SIZE 1500
45
+
46
+/* Command codes for foreground -> background communication */
47
+#define COMMAND_REDIRECT 10
48
+#define COMMAND_EXIT     11
49
+
50
+/* Response codes for background -> foreground communication */
51
+#define RESPONSE_INIT_SUCCEEDED   20
52
+#define RESPONSE_INIT_FAILED      21
53
+
54
+/* A foreign (non-OpenVPN) connection we are proxying,
55
+   usually HTTPS */
56
+struct proxy_connection {
57
+  bool defined;
58
+  struct proxy_connection *next;
59
+  struct proxy_connection *counterpart;
60
+  struct buffer buf;
61
+  bool buffer_initial;
62
+  int rwflags;
63
+  int sd;
64
+};
65
+
66
+/* used for passing fds between processes */
67
+union fdmsg {
68
+  struct cmsghdr h;
69
+  char buf[CMSG_SPACE(sizeof(socket_descriptor_t))];
70
+};
71
+
72
+#if 0
73
+static const char *
74
+headc (const struct buffer *buf)
75
+{
76
+  static char foo[16];
77
+  strncpy (foo, BSTR(buf), 15);
78
+  foo[15] = 0;
79
+  return foo;
80
+}
81
+#endif
82
+
83
+static void
84
+close_socket_if_defined (const socket_descriptor_t sd)
85
+{
86
+  if (socket_defined (sd))
87
+    openvpn_close_socket (sd);
88
+}
89
+
90
+/*
91
+ * Close most of parent's fds.
92
+ * Keep stdin/stdout/stderr, plus one
93
+ * other fd which is presumed to be
94
+ * our pipe back to parent.
95
+ * Admittedly, a bit of a kludge,
96
+ * but posix doesn't give us a kind
97
+ * of FD_CLOEXEC which will stop
98
+ * fds from crossing a fork().
99
+ */
100
+static void
101
+close_fds_except (int keep)
102
+{
103
+  socket_descriptor_t i;
104
+  closelog ();
105
+  for (i = 3; i <= 100; ++i)
106
+    {
107
+      if (i != keep)
108
+	openvpn_close_socket (i);
109
+    }
110
+}
111
+
112
+/*
113
+ * Usually we ignore signals, because our parent will
114
+ * deal with them.
115
+ */
116
+static void
117
+set_signals (void)
118
+{
119
+  signal (SIGTERM, SIG_DFL);
120
+
121
+  signal (SIGINT, SIG_IGN);
122
+  signal (SIGHUP, SIG_IGN);
123
+  signal (SIGUSR1, SIG_IGN);
124
+  signal (SIGUSR2, SIG_IGN);
125
+  signal (SIGPIPE, SIG_IGN);
126
+}
127
+
128
+/*
129
+ * Socket read/write functions.
130
+ */
131
+
132
+static int
133
+recv_control (const socket_descriptor_t fd)
134
+{
135
+  unsigned char c;
136
+  const ssize_t size = read (fd, &c, sizeof (c));
137
+  if (size == sizeof (c))
138
+    return c;
139
+  else
140
+    {
141
+      return -1;
142
+    }
143
+}
144
+
145
+static int
146
+send_control (const socket_descriptor_t fd, int code)
147
+{
148
+  unsigned char c = (unsigned char) code;
149
+  const ssize_t size = write (fd, &c, sizeof (c));
150
+  if (size == sizeof (c))
151
+    return (int) size;
152
+  else
153
+    return -1;
154
+}
155
+
156
+static void
157
+port_share_sendmsg (const socket_descriptor_t sd,
158
+		    const char command,
159
+		    const struct buffer *head,
160
+		    const socket_descriptor_t sd_send)
161
+{
162
+  if (socket_defined (sd))
163
+    {
164
+      struct msghdr mesg;
165
+      union fdmsg cmsg;
166
+      struct cmsghdr* h;
167
+      struct iovec iov[2];
168
+      socket_descriptor_t sd_null[2] = { SOCKET_UNDEFINED, SOCKET_UNDEFINED };
169
+      char cmd;
170
+      ssize_t status;
171
+
172
+      dmsg (D_PS_PROXY_DEBUG, "PORT SHARE: sendmsg sd=%d len=%d",
173
+	    sd_send,
174
+	    head ? BLEN(head) : -1);
175
+
176
+      CLEAR (mesg);
177
+
178
+      cmd = command;
179
+
180
+      iov[0].iov_base = &cmd;
181
+      iov[0].iov_len = sizeof (cmd);
182
+      mesg.msg_iovlen = 1;
183
+
184
+      if (head)
185
+	{
186
+	  iov[1].iov_base = BPTR (head);
187
+	  iov[1].iov_len = BLEN (head);
188
+	  mesg.msg_iovlen = 2;
189
+	}
190
+
191
+      mesg.msg_iov = iov;
192
+
193
+      mesg.msg_control = cmsg.buf;
194
+      mesg.msg_controllen = sizeof (union fdmsg);
195
+      mesg.msg_flags = 0;
196
+
197
+      h = CMSG_FIRSTHDR(&mesg);
198
+      h->cmsg_level = SOL_SOCKET;
199
+      h->cmsg_type = SCM_RIGHTS;
200
+      h->cmsg_len = CMSG_LEN(sizeof(socket_descriptor_t));
201
+
202
+      if (socket_defined (sd_send))
203
+	{
204
+	  *((socket_descriptor_t*)CMSG_DATA(h)) = sd_send;
205
+	}
206
+      else
207
+	{
208
+	  socketpair (PF_UNIX, SOCK_DGRAM, 0, sd_null);
209
+	  *((socket_descriptor_t*)CMSG_DATA(h)) = sd_null[0];
210
+	}
211
+
212
+      status = sendmsg (sd, &mesg, MSG_NOSIGNAL);
213
+      if (status == -1)
214
+	msg (M_WARN, "PORT SHARE: sendmsg failed (unable to communicate with background process)");
215
+
216
+      close_socket_if_defined (sd_null[0]);
217
+      close_socket_if_defined (sd_null[1]);
218
+    }
219
+}
220
+
221
+static int
222
+pc_list_len (struct proxy_connection *pc)
223
+{
224
+  int count = 0;
225
+  while (pc)
226
+    {
227
+      ++count;
228
+      pc = pc->next;
229
+    }
230
+  return count;
231
+}
232
+
233
+/* mark a proxy entry and its counterpart for close */
234
+static void
235
+proxy_entry_mark_for_close (struct proxy_connection *pc, struct event_set *es)
236
+{
237
+  if (pc->defined)
238
+    {
239
+      struct proxy_connection *cp = pc->counterpart;
240
+      dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: delete sd=%d", pc->sd);
241
+      if (socket_defined (pc->sd))
242
+	{
243
+	  if (es)
244
+	    event_del (es, pc->sd);
245
+	  openvpn_close_socket (pc->sd);
246
+	  pc->sd = SOCKET_UNDEFINED;
247
+	}
248
+      free_buf (&pc->buf);
249
+      pc->buffer_initial = false;
250
+      pc->rwflags = 0;
251
+      pc->counterpart = NULL;
252
+      pc->defined = false;
253
+      if (cp && cp->defined && cp->counterpart == pc)
254
+	proxy_entry_mark_for_close (cp, es);
255
+    }
256
+}
257
+
258
+static void
259
+proxy_list_housekeeping (struct proxy_connection **list)
260
+{
261
+  if (list)
262
+    {
263
+      struct proxy_connection *prev = NULL;
264
+      struct proxy_connection *pc = *list;
265
+
266
+      while (pc)
267
+	{
268
+	  struct proxy_connection *next = pc->next;
269
+	  if (!pc->defined)
270
+	    {
271
+	      free (pc);
272
+	      if (prev)
273
+		prev->next = next;
274
+	      else
275
+		*list = next;
276
+	    }
277
+	  else
278
+	    prev = pc;
279
+	  pc = next;
280
+	}
281
+    }
282
+}
283
+
284
+static void
285
+proxy_list_close (struct proxy_connection **list)
286
+{
287
+  if (list)
288
+    {
289
+      struct proxy_connection *pc = *list;
290
+      while (pc)
291
+	{
292
+	  proxy_entry_mark_for_close (pc, NULL);
293
+	  pc = pc->next;
294
+	}
295
+      proxy_list_housekeeping (list);
296
+    }
297
+}
298
+
299
+static void
300
+sock_addr_set (struct openvpn_sockaddr *osaddr,
301
+	       const in_addr_t addr,
302
+	       const int port)
303
+{
304
+  CLEAR (*osaddr);
305
+  osaddr->sa.sin_family = AF_INET;
306
+  osaddr->sa.sin_addr.s_addr = htonl (addr);
307
+  osaddr->sa.sin_port = htons (port);
308
+}
309
+
310
+static inline void
311
+proxy_connection_io_requeue (struct proxy_connection *pc, const int rwflags_new, struct event_set *es)
312
+{
313
+  if (pc->rwflags != rwflags_new)
314
+    {
315
+      event_ctl (es, pc->sd, rwflags_new, (void*)pc);
316
+      pc->rwflags = rwflags_new;
317
+    }
318
+}
319
+
320
+static bool
321
+proxy_entry_new (struct proxy_connection **list,
322
+		 struct event_set *es,
323
+		 const in_addr_t server_addr,
324
+		 const int server_port,
325
+		 const socket_descriptor_t sd_client,
326
+		 struct buffer *initial_data)
327
+{
328
+  struct openvpn_sockaddr osaddr;
329
+  socket_descriptor_t sd_server;
330
+  int status;
331
+  struct proxy_connection *pc;
332
+  struct proxy_connection *cp;
333
+
334
+  /* connect to port share server */
335
+  sock_addr_set (&osaddr, server_addr, server_port);
336
+  sd_server = create_socket_tcp ();
337
+  status = openvpn_connect (sd_server, &osaddr, 5, NULL);
338
+  if (status)
339
+    {
340
+      msg (M_WARN, "PORT SHARE PROXY: connect to port-share server failed");
341
+      openvpn_close_socket (sd_server);
342
+      return false;
343
+    }
344
+  dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: connect to port-share server succeeded");
345
+
346
+  set_nonblock (sd_client);
347
+  set_nonblock (sd_server);
348
+
349
+  /* allocate 2 new proxy_connection objects */
350
+  ALLOC_OBJ_CLEAR (pc, struct proxy_connection);
351
+  ALLOC_OBJ_CLEAR (cp, struct proxy_connection);
352
+
353
+  /* client object */
354
+  pc->defined = true;
355
+  pc->next = cp;
356
+  pc->counterpart = cp;
357
+  pc->buf = *initial_data;
358
+  pc->buffer_initial = true;
359
+  pc->rwflags = EVENT_UNDEF;
360
+  pc->sd = sd_client;
361
+
362
+  /* server object */
363
+  cp->defined = true;
364
+  cp->next = *list;
365
+  cp->counterpart = pc;
366
+  cp->buf = alloc_buf (PROXY_CONNECTION_BUFFER_SIZE);
367
+  cp->buffer_initial = false;
368
+  cp->rwflags = EVENT_UNDEF;
369
+  cp->sd = sd_server;
370
+
371
+  /* add to list */
372
+  *list = pc;
373
+  
374
+  dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: NEW CONNECTION [c=%d s=%d]", sd_client, sd_server);
375
+
376
+  /* set initial i/o states */
377
+  proxy_connection_io_requeue (pc, EVENT_READ, es);
378
+  proxy_connection_io_requeue (cp, EVENT_READ|EVENT_WRITE, es);
379
+  
380
+  return true;
381
+}
382
+
383
+static bool
384
+control_message_from_parent (const socket_descriptor_t sd_control,
385
+			     struct proxy_connection **list,
386
+			     struct event_set *es,
387
+			     const in_addr_t server_addr,
388
+			     const int server_port)
389
+{
390
+  struct buffer buf = alloc_buf (PROXY_CONNECTION_BUFFER_SIZE);
391
+  struct msghdr mesg;
392
+  union fdmsg cmsg;
393
+  struct cmsghdr* h;
394
+  struct iovec iov[2];
395
+  char command = 0;
396
+  ssize_t status;
397
+  int ret = true;
398
+
399
+  CLEAR (mesg);
400
+
401
+  iov[0].iov_base = &command;
402
+  iov[0].iov_len = sizeof (command);
403
+  iov[1].iov_base = BPTR (&buf);
404
+  iov[1].iov_len = BCAP (&buf);
405
+  mesg.msg_iov = iov;
406
+  mesg.msg_iovlen = 2;
407
+
408
+  mesg.msg_control = cmsg.buf;
409
+  mesg.msg_controllen = sizeof (union fdmsg);
410
+  mesg.msg_flags = 0;
411
+
412
+  h = CMSG_FIRSTHDR(&mesg);
413
+  h->cmsg_len = CMSG_LEN(sizeof(socket_descriptor_t));
414
+  h->cmsg_level = SOL_SOCKET;
415
+  h->cmsg_type = SCM_RIGHTS;
416
+  *((socket_descriptor_t*)CMSG_DATA(h)) = SOCKET_UNDEFINED;
417
+
418
+  status = recvmsg (sd_control, &mesg, MSG_NOSIGNAL);
419
+  if (status != -1)
420
+    {
421
+      if (   h == NULL
422
+	  || h->cmsg_len    != CMSG_LEN(sizeof(socket_descriptor_t))
423
+	  || h->cmsg_level  != SOL_SOCKET
424
+	  || h->cmsg_type   != SCM_RIGHTS )
425
+	{
426
+	  ret = false;
427
+	}
428
+      else
429
+	{
430
+	  const socket_descriptor_t received_fd = *((socket_descriptor_t*)CMSG_DATA(h));
431
+	  dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED sd=%d", received_fd);
432
+
433
+	  if (status >= 2 && command == COMMAND_REDIRECT)
434
+	    {
435
+	      buf.len = status - 1;
436
+	      if (proxy_entry_new (list,
437
+				   es,
438
+				   server_addr,
439
+				   server_port,
440
+				   received_fd,
441
+				   &buf))
442
+		{
443
+		  CLEAR (buf); /* we gave the buffer to proxy_entry_new */
444
+		}
445
+	      else
446
+		{
447
+		  openvpn_close_socket (received_fd);
448
+		}
449
+	    }
450
+	  else if (status >= 1 && command == COMMAND_EXIT)
451
+	    {
452
+	      dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED COMMAND_EXIT");
453
+	      openvpn_close_socket (received_fd); /* null socket */
454
+	      ret = false;
455
+	    }
456
+	}
457
+    }
458
+  free_buf (&buf);
459
+  return ret;
460
+}
461
+
462
+/* proxy_connection_io_xfer return values */
463
+
464
+#define IOSTAT_EAGAIN_ON_READ   0
465
+#define IOSTAT_EAGAIN_ON_WRITE  1
466
+#define IOSTAT_ERROR            2
467
+
468
+/* forward data from pc to pc->counterpart */
469
+static int
470
+proxy_connection_io_xfer (struct proxy_connection *pc)
471
+{
472
+  while (true)
473
+    {
474
+      if (!BLEN (&pc->buf))
475
+	{
476
+	  /* recv data from socket */
477
+	  ssize_t status = recv (pc->sd, BPTR(&pc->buf), BCAP(&pc->buf), MSG_NOSIGNAL);
478
+	  if (status == -1)
479
+	    {
480
+	      return (errno == EAGAIN) ? IOSTAT_EAGAIN_ON_READ : IOSTAT_ERROR;
481
+	    }
482
+	  else
483
+	    {
484
+	      if (!status)
485
+		return IOSTAT_ERROR;
486
+	      pc->buf.len = status;
487
+	    }
488
+	}
489
+
490
+      if (BLEN (&pc->buf))
491
+	{
492
+	  /* send data to counterpart socket */
493
+	  ssize_t status = send (pc->counterpart->sd, BPTR(&pc->buf), BLEN(&pc->buf), MSG_NOSIGNAL);
494
+	  if (status == -1)
495
+	    {
496
+	      const int e = errno;
497
+	      return (e == EAGAIN) ? IOSTAT_EAGAIN_ON_WRITE : IOSTAT_ERROR;
498
+	    }
499
+	  else
500
+	    {
501
+	      if (status != pc->buf.len)
502
+		return IOSTAT_ERROR;
503
+	      pc->buf.len = 0;
504
+	    }
505
+
506
+	  /* successful send */
507
+	  if (pc->buffer_initial)
508
+	    {
509
+	      free_buf (&pc->buf);
510
+	      pc->buf = alloc_buf (PROXY_CONNECTION_BUFFER_SIZE);
511
+	      pc->buffer_initial = false;
512
+	    }
513
+	}
514
+    }
515
+  return IOSTAT_ERROR;
516
+}
517
+
518
+static inline bool
519
+proxy_connection_io_status (const int status, int *rwflags_pc, int *rwflags_cp)
520
+{
521
+  switch (status)
522
+    {
523
+	case IOSTAT_EAGAIN_ON_READ:
524
+	  *rwflags_pc |= EVENT_READ;
525
+	  *rwflags_cp &= ~EVENT_WRITE;
526
+	  return true;
527
+	case IOSTAT_EAGAIN_ON_WRITE:
528
+	  *rwflags_pc &= ~EVENT_READ;
529
+	  *rwflags_cp |= EVENT_WRITE;
530
+	  return true;
531
+	default:
532
+	  return false;
533
+    }
534
+}
535
+
536
+static bool
537
+proxy_connection_io_dispatch (struct proxy_connection *pc,
538
+			      const int rwflags,
539
+			      struct event_set *es)
540
+{
541
+  struct proxy_connection *cp = pc->counterpart;
542
+  int status;
543
+  int rwflags_pc = pc->rwflags;
544
+  int rwflags_cp = cp->rwflags;
545
+
546
+  if (rwflags & EVENT_READ)
547
+    {
548
+      status = proxy_connection_io_xfer (pc);
549
+      if (!proxy_connection_io_status (status, &rwflags_pc, &rwflags_cp))
550
+	goto bad;
551
+    }
552
+  if (rwflags & EVENT_WRITE)
553
+    {
554
+      status = proxy_connection_io_xfer (cp);
555
+      if (!proxy_connection_io_status (status, &rwflags_cp, &rwflags_pc))
556
+	goto bad;
557
+    }
558
+  proxy_connection_io_requeue (pc, rwflags_pc, es);
559
+  proxy_connection_io_requeue (cp, rwflags_cp, es);
560
+
561
+  return true;
562
+
563
+ bad:
564
+  proxy_entry_mark_for_close (pc, es);
565
+  return false;
566
+}
567
+
568
+static void
569
+port_share_proxy (const in_addr_t hostaddr, const int port, const socket_descriptor_t sd_control)
570
+{
571
+  if (send_control (sd_control, RESPONSE_INIT_SUCCEEDED) >= 0)
572
+    {
573
+      void *sd_control_marker = (void *)1;
574
+      int maxevents = 256;
575
+      struct event_set *es;
576
+      struct event_set_return esr[64];
577
+      struct proxy_connection *list = NULL;
578
+      time_t last_housekeeping = 0;
579
+
580
+      msg (D_PS_PROXY, "PORT SHARE PROXY: proxy starting");
581
+
582
+      es = event_set_init (&maxevents, 0);
583
+      event_ctl (es, sd_control, EVENT_READ, sd_control_marker);
584
+      while (true)
585
+	{
586
+	  int n_events;
587
+	  struct timeval tv;
588
+	  time_t current;
589
+
590
+	  tv.tv_sec = 10;
591
+	  tv.tv_usec = 0;
592
+	  n_events = event_wait (es, &tv, esr, SIZE(esr));
593
+	  current = time(NULL);
594
+	  if (n_events > 0)
595
+	    {
596
+	      int i;
597
+	      for (i = 0; i < n_events; ++i)
598
+		{
599
+		  const struct event_set_return *e = &esr[i];
600
+		  if (e->arg == sd_control_marker)
601
+		    {
602
+		      if (!control_message_from_parent (sd_control, &list, es, hostaddr, port))
603
+			goto done;
604
+		    }
605
+		  else
606
+		    {
607
+		      struct proxy_connection *pc = (struct proxy_connection *)e->arg;
608
+		      if (pc->defined)
609
+			proxy_connection_io_dispatch (pc, e->rwflags, es);
610
+		    }
611
+		}
612
+	    }
613
+	  else if (n_events < 0)
614
+	    {
615
+	      dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: event_wait failed");
616
+	    }
617
+	  if (current > last_housekeeping)
618
+	    {
619
+	      proxy_list_housekeeping (&list);
620
+	      last_housekeeping = current;
621
+	    }
622
+	}
623
+
624
+    done:
625
+      proxy_list_close (&list);
626
+      event_free (es);
627
+    }
628
+  msg (D_PS_PROXY, "PORT SHARE PROXY: proxy exiting");
629
+}
630
+
631
+struct port_share *
632
+port_share_open (const char *host, const int port)
633
+{
634
+  pid_t pid;
635
+  socket_descriptor_t fd[2];
636
+  in_addr_t hostaddr;
637
+  struct port_share *ps;
638
+
639
+  ALLOC_OBJ_CLEAR (ps, struct port_share);
640
+
641
+  /*
642
+   * Get host's IP address
643
+   */
644
+  hostaddr = getaddr (GETADDR_RESOLVE|GETADDR_HOST_ORDER|GETADDR_FATAL, host, 0, NULL, NULL);
645
+
646
+  /*
647
+   * Make a socket for foreground and background processes
648
+   * to communicate.
649
+   */
650
+  if (socketpair (PF_UNIX, SOCK_DGRAM, 0, fd) == -1)
651
+    {
652
+      msg (M_WARN, "PORT SHARE: socketpair call failed");
653
+      goto error;
654
+    }
655
+
656
+  /*
657
+   * Fork off background proxy process.
658
+   */
659
+  pid = fork ();
660
+
661
+  if (pid)
662
+    {
663
+      int status;
664
+
665
+      /*
666
+       * Foreground Process
667
+       */
668
+
669
+      ps->background_pid = pid;
670
+
671
+      /* close our copy of child's socket */
672
+      openvpn_close_socket (fd[1]);
673
+
674
+      /* don't let future subprocesses inherit child socket */
675
+      set_cloexec (fd[0]);
676
+
677
+      /* wait for background child process to initialize */
678
+      status = recv_control (fd[0]);
679
+      if (status == RESPONSE_INIT_SUCCEEDED)
680
+	{
681
+	  ps->foreground_fd = fd[0];
682
+	  return ps;
683
+	}
684
+    }
685
+  else
686
+    {
687
+      /*
688
+       * Background Process
689
+       */
690
+
691
+      /* Ignore most signals (the parent will receive them) */
692
+      set_signals ();
693
+
694
+      /* Let msg know that we forked */
695
+      msg_forked ();
696
+
697
+      /* close all parent fds except our socket back to parent */
698
+      close_fds_except (fd[1]);
699
+
700
+      /* no blocking on control channel back to parent */
701
+      set_nonblock (fd[1]);
702
+
703
+      /* execute the event loop */
704
+      port_share_proxy (hostaddr, port, fd[1]);
705
+
706
+      openvpn_close_socket (fd[1]);
707
+
708
+      exit (0);
709
+      return 0; /* NOTREACHED */
710
+    }
711
+
712
+ error:
713
+  port_share_close (ps);
714
+  return NULL;
715
+}
716
+
717
+void
718
+port_share_close (struct port_share *ps)
719
+{
720
+  if (ps)
721
+    {
722
+      if (ps->foreground_fd >= 0)
723
+	{
724
+	  /* tell background process to exit */
725
+	  port_share_sendmsg (ps->foreground_fd, COMMAND_EXIT, NULL, SOCKET_UNDEFINED);
726
+
727
+	  /* wait for background process to exit */
728
+	  dmsg (D_PS_PROXY_DEBUG, "PORT SHARE: waiting for background process to exit");
729
+	  if (ps->background_pid > 0)
730
+	    waitpid (ps->background_pid, NULL, 0);
731
+	  dmsg (D_PS_PROXY_DEBUG, "PORT SHARE: background process exited");
732
+
733
+	  openvpn_close_socket (ps->foreground_fd);
734
+	  ps->foreground_fd = -1;
735
+	}
736
+
737
+      free (ps);
738
+    }
739
+}
740
+
741
+void
742
+port_share_abort (struct port_share *ps)
743
+{
744
+  if (ps)
745
+    {
746
+      /* tell background process to exit */
747
+      if (ps->foreground_fd >= 0)
748
+	{
749
+	  send_control (ps->foreground_fd, COMMAND_EXIT);
750
+	  openvpn_close_socket (ps->foreground_fd);
751
+	  ps->foreground_fd = -1;
752
+	}
753
+    }
754
+}
755
+
756
+bool
757
+is_openvpn_protocol (const struct buffer *buf)
758
+{
759
+  const unsigned char *p = BSTR (buf);
760
+  const int len = BLEN (buf);
761
+  if (len >= 3)
762
+    {
763
+      return p[0] == 0
764
+	&& p[1] >= 14
765
+	&& p[2] == (P_CONTROL_HARD_RESET_CLIENT_V2<<P_OPCODE_SHIFT);
766
+    }
767
+  else if (len >= 2)
768
+    {
769
+      return p[0] == 0 && p[1] >= 14;
770
+    }
771
+  else
772
+    return true;
773
+}
774
+
775
+void
776
+port_share_redirect (struct port_share *ps, const struct buffer *head, socket_descriptor_t sd)
777
+{
778
+  if (ps)
779
+    port_share_sendmsg (ps->foreground_fd, COMMAND_REDIRECT, head, sd);
780
+}
781
+
782
+#endif
0 783
new file mode 100644
... ...
@@ -0,0 +1,57 @@
0
+/*
1
+ *  OpenVPN -- An application to securely tunnel IP networks
2
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
3
+ *             session authentication and key exchange,
4
+ *             packet encryption, packet authentication, and
5
+ *             packet compression.
6
+ *
7
+ *  Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
8
+ *
9
+ *  This program is free software; you can redistribute it and/or modify
10
+ *  it under the terms of the GNU General Public License version 2
11
+ *  as published by the Free Software Foundation.
12
+ *
13
+ *  This program is distributed in the hope that it will be useful,
14
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ *  GNU General Public License for more details.
17
+ *
18
+ *  You should have received a copy of the GNU General Public License
19
+ *  along with this program (see the file COPYING included with this
20
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
21
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
+ */
23
+
24
+#ifndef PS_H
25
+#define PS_H
26
+
27
+#if PORT_SHARE
28
+
29
+#include "basic.h"
30
+#include "buffer.h"
31
+#include "ssl.h"
32
+
33
+typedef void (*post_fork_cleanup_func_t)(void *arg);
34
+
35
+struct port_share {
36
+  /* Foreground's socket to background process */
37
+  socket_descriptor_t foreground_fd;
38
+
39
+  /* Process ID of background process */
40
+  pid_t background_pid;
41
+};
42
+
43
+extern struct port_share *port_share;
44
+
45
+struct port_share *port_share_open (const char *host,
46
+				    const int port);
47
+
48
+void port_share_close (struct port_share *ps);
49
+void port_share_abort (struct port_share *ps);
50
+
51
+bool is_openvpn_protocol (const struct buffer *buf);
52
+
53
+void port_share_redirect (struct port_share *ps, const struct buffer *head, socket_descriptor_t sd);
54
+
55
+#endif
56
+#endif
... ...
@@ -221,12 +221,13 @@ reliable_ack_print (struct buffer *buf, bool verbose, struct gc_arena *gc)
221 221
  */
222 222
 
223 223
 void
224
-reliable_init (struct reliable *rel, int buf_size, int offset, int array_size)
224
+reliable_init (struct reliable *rel, int buf_size, int offset, int array_size, bool hold)
225 225
 {
226 226
   int i;
227 227
 
228 228
   CLEAR (*rel);
229 229
   ASSERT (array_size > 0 && array_size <= RELIABLE_CAPACITY);
230
+  rel->hold = hold;
230 231
   rel->size = array_size;
231 232
   rel->offset = offset;
232 233
   for (i = 0; i < rel->size; ++i)
... ...
@@ -465,7 +466,7 @@ reliable_can_send (const struct reliable *rel)
465 465
        reliable_print_ids (rel, &gc));
466 466
 
467 467
   gc_free (&gc);
468
-  return n_current > 0;
468
+  return n_current > 0 && !rel->hold;
469 469
 }
470 470
 
471 471
 /* return a unique point-in-time to trigger retry */
... ...
@@ -530,6 +531,7 @@ reliable_schedule_now (struct reliable *rel)
530 530
 {
531 531
   int i;
532 532
   dmsg (D_REL_DEBUG, "ACK reliable_schedule_now");
533
+  rel->hold = false;
533 534
   for (i = 0; i < rel->size; ++i)
534 535
     {
535 536
       struct reliable_entry *e = &rel->array[i];
... ...
@@ -96,6 +96,7 @@ struct reliable
96 96
   interval_t initial_timeout;
97 97
   packet_id_type packet_id;
98 98
   int offset;
99
+  bool hold; /* don't xmit until reliable_schedule_now is called */
99 100
   struct reliable_entry array[RELIABLE_CAPACITY];
100 101
 };
101 102
 
... ...
@@ -108,7 +109,7 @@ reliable_set_timeout (struct reliable *rel, interval_t timeout)
108 108
   rel->initial_timeout = timeout;
109 109
 }
110 110
 
111
-void reliable_init (struct reliable *rel, int buf_size, int offset, int array_size);
111
+void reliable_init (struct reliable *rel, int buf_size, int offset, int array_size, bool hold);
112 112
 
113 113
 void reliable_free (struct reliable *rel);
114 114
 
... ...
@@ -36,6 +36,7 @@
36 36
 #include "misc.h"
37 37
 #include "gremlin.h"
38 38
 #include "plugin.h"
39
+#include "ps.h"
39 40
 
40 41
 #include "memdbg.h"
41 42
 
... ...
@@ -739,11 +740,14 @@ openvpn_connect (socket_descriptor_t sd,
739 739
 
740 740
 	  status = select (sd + 1, NULL, &writes, NULL, &tv);
741 741
 
742
-	  get_signal (signal_received);
743
-	  if (*signal_received)
742
+	  if (signal_received)
744 743
 	    {
745
-	      status = 0;
746
-	      break;
744
+	      get_signal (signal_received);
745
+	      if (*signal_received)
746
+		{
747
+		  status = 0;
748
+		  break;
749
+		}
747 750
 	    }
748 751
 	  if (status < 0)
749 752
 	    {
... ...
@@ -1666,6 +1670,9 @@ stream_buf_init (struct stream_buf *sb,
1666 1666
   sb->buf_init.len = 0;
1667 1667
   sb->residual = alloc_buf (sb->maxlen);
1668 1668
   sb->error = false;
1669
+#if PORT_SHARE
1670
+  sb->port_share_state = PS_ENABLED;
1671
+#endif
1669 1672
   stream_buf_reset (sb);
1670 1673
 
1671 1674
   dmsg (D_STREAM_DEBUG, "STREAM: INIT maxlen=%d", sb->maxlen);
... ...
@@ -1735,6 +1742,22 @@ stream_buf_added (struct stream_buf *sb,
1735 1735
   if (sb->len < 0 && sb->buf.len >= (int) sizeof (packet_size_type))
1736 1736
     {
1737 1737
       packet_size_type net_size;
1738
+
1739
+#if PORT_SHARE
1740
+      if (sb->port_share_state == PS_ENABLED)
1741
+	{
1742
+	  if (!is_openvpn_protocol (&sb->buf))
1743
+	    {
1744
+	      msg (D_STREAM_ERRORS, "Non-OpenVPN protocol detected");
1745
+	      sb->port_share_state = PS_FOREIGN;
1746
+	      sb->error = true;
1747
+	      return false;
1748
+	    }
1749
+	  else
1750
+	    sb->port_share_state = PS_DISABLED;
1751
+	}
1752
+#endif
1753
+
1738 1754
       ASSERT (buf_read (&sb->buf, &net_size, sizeof (net_size)));
1739 1755
       sb->len = ntohps (net_size);
1740 1756
 
... ...
@@ -130,6 +130,12 @@ struct stream_buf
130 130
 
131 131
   bool error;  /* if true, fatal TCP error has occurred,
132 132
 		  requiring that connection be restarted */
133
+#if PORT_SHARE
134
+# define PS_DISABLED 0
135
+# define PS_ENABLED  1
136
+# define PS_FOREIGN  2
137
+  int port_share_state;
138
+#endif
133 139
 };
134 140
 
135 141
 /*
... ...
@@ -540,6 +546,29 @@ link_socket_actual_match (const struct link_socket_actual *a1, const struct link
540 540
   return addr_port_match (&a1->dest, &a2->dest);
541 541
 }
542 542
 
543
+#if PORT_SHARE
544
+
545
+static inline bool
546
+socket_foreign_protocol_detected (const struct link_socket *sock)
547
+{
548
+  return link_socket_connection_oriented (sock)
549
+    && sock->stream_buf.port_share_state == PS_FOREIGN;
550
+}
551
+
552
+static inline const struct buffer *
553
+socket_foreign_protocol_head (const struct link_socket *sock)
554
+{
555
+  return &sock->stream_buf.buf;
556
+}
557
+
558
+static inline int
559
+socket_foreign_protocol_sd (const struct link_socket *sock)
560
+{
561
+  return sock->sd;
562
+}
563
+
564
+#endif
565
+
543 566
 static inline bool
544 567
 socket_connection_reset (const struct link_socket *sock, int status)
545 568
 {
... ...
@@ -1791,9 +1791,11 @@ key_state_init (struct tls_session *session, struct key_state *ks)
1791 1791
   ks->plaintext_write_buf = alloc_buf (PLAINTEXT_BUFFER_SIZE);
1792 1792
   ks->ack_write_buf = alloc_buf (BUF_SIZE (&session->opt->frame));
1793 1793
   reliable_init (ks->send_reliable, BUF_SIZE (&session->opt->frame),
1794
-		 FRAME_HEADROOM (&session->opt->frame), TLS_RELIABLE_N_SEND_BUFFERS);
1794
+		 FRAME_HEADROOM (&session->opt->frame), TLS_RELIABLE_N_SEND_BUFFERS,
1795
+		 session->opt->xmit_hold);
1795 1796
   reliable_init (ks->rec_reliable, BUF_SIZE (&session->opt->frame),
1796
-		 FRAME_HEADROOM (&session->opt->frame), TLS_RELIABLE_N_REC_BUFFERS);
1797
+		 FRAME_HEADROOM (&session->opt->frame), TLS_RELIABLE_N_REC_BUFFERS,
1798
+		 false);
1797 1799
   reliable_set_timeout (ks->send_reliable, session->opt->packet_timeout);
1798 1800
 
1799 1801
   /* init packet ID tracker */
... ...
@@ -384,6 +384,9 @@ struct tls_options
384 384
   /* true if we are a TLS server, client otherwise */
385 385
   bool server;
386 386
 
387
+  /* if true, don't xmit until first packet from peer is received */
388
+  bool xmit_hold;
389
+
387 390
 #ifdef ENABLE_OCC
388 391
   /* local and remote options strings
389 392
      that must match between client and server */
... ...
@@ -396,6 +396,15 @@ socket_defined (const socket_descriptor_t sd)
396 396
 #endif
397 397
 
398 398
 /*
399
+ * HTTPS port sharing capability
400
+ */
401
+#if defined(ENABLE_PORT_SHARE) && P2MP_SERVER && defined(SCM_RIGHTS) && defined(HAVE_MSGHDR) && defined(HAVE_CMSGHDR) && defined(HAVE_IOVEC) && defined(CMSG_FIRSTHDR) && defined(CMSG_NXTHDR) && defined(HAVE_RECVMSG) && defined(HAVE_SENDMSG)
402
+#define PORT_SHARE 1
403
+#else
404
+#define PORT_SHARE 0
405
+#endif
406
+
407
+/*
399 408
  * Do we have a plug-in capability?
400 409
  */
401 410
 #if defined(USE_LIBDL) || defined(USE_LOAD_LIBRARY)