git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@893 e7ae566f-a301-0410-adde-c780ea21d3b5
| ... | ... |
@@ -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. |
| ... | ... |
@@ -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 |
} |
| ... | ... |
@@ -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 |
| ... | ... |
@@ -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) |