[OpenVPN home] [Date Prev] [Date Index] [Date Next]
[OpenVPN mailing lists] [Thread Prev] [Thread Index] [Thread Next]
Google
 
Web openvpn.net

[Openvpn-users] Multiple users on a single port - It works :)


  • Subject: [Openvpn-users] Multiple users on a single port - It works :)
  • From: Stefan `Sec` Zehl <sec+ovpn@xxxxxx>
  • Date: Thu, 22 Jan 2004 17:55:06 +0100
  • Accept-languages: de, en
  • I-love-doing-this: really

Hi,

I just wanted to share my success story, and hope that perhaps my patch
can be made part of the main OpenVPN release.

Here at work, we wanted to implement a VPN solution for Roadwarriors
which have to connect to the main office. OpenVPN looked like a nice
solution, as it also works with Windows and can tunnel through an https
proxy.

One problem though, was the unability to use a constant port number on
the server side.

The --inetd option seemed very promising, but the man-page explicitly
states that this option can not be used for multiple connections,
although there seemed to be no reason. (The only reason i found
mentioned was, that there was no config file templating mechanism,
which obviously isn't really a problem).

A test later I found, that the code was written for inetd with
"wait=yes" in mind, but that was quickly changed[1] (see attached patch).

The attached patch adds a new option "--sane_inetd" which makes OpenVPN
work with a connected socket on stdin, like (x)inted does with wait=no,
or even netcat with the -e option.

Of course this still runs one OpenVPN process per client. You still need 
one tap device per client, and configure bridging between them.

This also only works with SSL/TLS and tap devices, because of the single
config file shared between all server processes.

The server config file in our case is easy:

| # OpenVPN multiple-client-server
| inetd
| sane_inetd
| proto tcp-server
| 
| # 10.254.0.1 is our local VPN endpoint (office).
| dev tap
| ifconfig 10.254.0.1 255.255.255.0
| 
| # Our up script will establish routes
| # once the VPN is alive.
| ifconfig-noexec
| up /etc/openvpn/vpn-server.up
| 
| # We are SSL/TLS Server
| tls-server
| dh /etc/openvpn/dh2048.pem
| ca /etc/openvpn/my-ca.crt
| crl-verify /etc/openvpn/my-ca.crl
| cert /etc/openvpn/server.crt
| key /etc/openvpn/server.key

The only magic thing is the ifconfig-noexec. Of course we can't ifconfig
each of the tap interfaces with the same IP address. But we don't need
to, as we are using bridging.

My Bridging setup script (run once at bootup):

| # load Bridging-Module
| modprobe bridge
| 
| # configure bridge
| brctl addbr br0
| brctl stp   br0 off
| brctl setfd br0 0
| 
| # our private vpn network
| ifconfig br0 10.254.0.1 netmask 0xffffff00 broadcast 10.254.0.255

The per-client setup script (vpn-server.up):

| # add interface to bridge and activate
| brctl addif br0 $1
| ifconfig $1 up


And for completeness sake, here is the xinetd config file for the
OpenVPN server:

| service openvpn_1
| {
|         type            = UNLISTED
|         port            = 443
|         socket_type     = stream
|         protocol        = tcp
|         wait            = no
|         user            = root
|         server          = /usr/sbin/openvpn
|         server_args     = --config /etc/openvpn/vpn-server.conf
|         disable         = no
| }

And thats it. It works for me. If you have any questions or comments,
contact me, I'd be happy to hear from you.

CU,
    Sec

[1]  The necessary code changes are very small.
     Only socket_listen_accept needs to be changed. The accept() and
     openvpn_close_socket() calls need to be removed, because the
     connection on stdin is already the connection we want.  The second
     thing is, we have to use getpeername to find the IP and Port of
     our remote peer.

     All the other changes in the attached patch deal with adding a new
     command-line option, and propagating that new option down to the
     correct function. 

-- 
> I even remember having a private exchange of messages with you about other
> possible approaches to that problem. :-)
Hopefully, these approaches involved slowly crushing of tender body parts.
                                    -- Liviu & Wietse about broken Mailers
diff -bur openvpn-1.5.0/openvpn.c openvpn-1.5.0-inet/openvpn.c
--- openvpn-1.5.0/openvpn.c	2003-11-06 14:45:12.000000000 +0100
+++ openvpn-1.5.0-inet/openvpn.c	2004-01-16 11:55:38.000000000 +0100
@@ -1171,6 +1171,7 @@
 			   options->bind_local,
 			   options->remote_float,
 			   options->inetd,
+			   options->sane_inetd,
 			   link_socket_addr,
 			   options->ipchange,
 			   options->resolve_retry_seconds,
@@ -2721,6 +2722,9 @@
       if (options.daemon && options.inetd)
 	msg (M_USAGE, "Options error: only one of --daemon or --inetd may be specified");
 
+      if (options.sane_inetd && !options.inetd)
+	msg (M_USAGE, "Options error: --sane_inetd can only be used together with --inetd");
+
       if (options.inetd && (options.local || options.remote))
 	msg (M_USAGE, "Options error: --local or --remote cannot be used with --inetd");
 
Only in openvpn-1.5.0-inet: openvpn.c.orig
Only in openvpn-1.5.0-inet: openvpn.c.rej
diff -bur openvpn-1.5.0/options.c openvpn-1.5.0-inet/options.c
--- openvpn-1.5.0/options.c	2003-11-06 14:45:12.000000000 +0100
+++ openvpn-1.5.0-inet/options.c	2004-01-16 11:53:59.000000000 +0100
@@ -472,6 +472,7 @@
   SHOW_BOOL (up_restart);
   SHOW_BOOL (daemon);
   SHOW_BOOL (inetd);
+  SHOW_BOOL (sane_inetd);
   SHOW_BOOL (log);
   SHOW_INT (nice);
   SHOW_INT (verbosity);
@@ -1162,6 +1163,10 @@
 	    ++i;
 	}
     }
+  else if (streq (p[0], "sane_inetd"))
+    {
+      options->sane_inetd = true;
+    }
   else if (streq (p[0], "log") && p[1])
     {
       ++i;
diff -bur openvpn-1.5.0/options.h openvpn-1.5.0-inet/options.h
--- openvpn-1.5.0/options.h	2003-11-06 14:45:12.000000000 +0100
+++ openvpn-1.5.0-inet/options.h	2004-01-16 11:53:59.000000000 +0100
@@ -135,6 +135,7 @@
   bool up_restart;
   bool daemon;
   bool inetd;
+  bool sane_inetd;
   bool log;
   int nice;
 #ifdef USE_PTHREAD
diff -bur openvpn-1.5.0/socket.c openvpn-1.5.0-inet/socket.c
--- openvpn-1.5.0/socket.c	2003-11-06 14:45:12.000000000 +0100
+++ openvpn-1.5.0-inet/socket.c	2004-01-16 11:55:08.000000000 +0100
@@ -274,6 +274,7 @@
 		      bool *remote_changed,
 		      const struct sockaddr_in *local,
 		      bool do_listen,
+		      bool sane_inetd,
 		      volatile int *signal_received)
 {
   socklen_t remote_len = sizeof (*remote);
@@ -314,7 +315,20 @@
       if (status <= 0)
 	continue;
 
+      if(sane_inetd)
+        {
+	  new_sd = getpeername (sd, (struct sockaddr *) remote, &remote_len);
+
+	  if (new_sd == -1)
+	    msg (D_LINK_ERRORS | M_ERRNO_SOCK, "getpeername() failed");
+	  else
+	    new_sd=sd;
+	}
+      else
+        {
       new_sd = accept (sd, (struct sockaddr *) remote, &remote_len);
+	}
+
       if (new_sd == -1)
 	{
 	  msg (D_LINK_ERRORS | M_ERRNO_SOCK, "accept() failed");
@@ -341,7 +355,7 @@
       sleep (1);
     }
 
-  if (openvpn_close_socket (sd))
+  if (!sane_inetd && openvpn_close_socket (sd))
     msg (M_SOCKERR, "close socket failed (sd)");
   msg (M_INFO, "TCP connection established with %s", 
        print_sockaddr (remote));
@@ -550,6 +564,7 @@
 			 bool bind_local,
 			 bool remote_float,
 			 bool inetd,
+			 bool sane_inetd,
 			 struct link_socket_addr *lsa,
 			 const char *ipchange_command,
 			 int resolve_retry_seconds,
@@ -563,6 +578,7 @@
   sock->bind_local = bind_local;
   sock->remote_float = remote_float;
   sock->inetd = inetd;
+  sock->sane_inetd = sane_inetd;
   sock->lsa = lsa;
   sock->ipchange_command = ipchange_command;
   sock->resolve_retry_seconds = resolve_retry_seconds;
@@ -633,7 +649,8 @@
 	sock->sd =
 	  socket_listen_accept (sock->sd, &sock->lsa->actual,
 				remote_dynamic, &remote_changed,
-				&sock->lsa->local, false, signal_received);
+				&sock->lsa->local, false, sock->sane_inetd,
+				signal_received);
       ASSERT (!remote_changed);
       if (*signal_received)
 	return;
@@ -650,7 +667,8 @@
 	{
 	  sock->sd = socket_listen_accept (sock->sd, &sock->lsa->actual,
 					   remote_dynamic, &remote_changed,
-					   &sock->lsa->local, true, signal_received);
+					   &sock->lsa->local, true, false,
+					   signal_received);
 	}
       else if (sock->proto == PROTO_TCPv4_CLIENT)
 	{
Only in openvpn-1.5.0-inet: socket.c.orig
Only in openvpn-1.5.0-inet: socket.c.rej
diff -bur openvpn-1.5.0/socket.h openvpn-1.5.0-inet/socket.h
--- openvpn-1.5.0/socket.h	2003-11-06 14:45:12.000000000 +0100
+++ openvpn-1.5.0-inet/socket.h	2004-01-16 11:53:59.000000000 +0100
@@ -118,6 +118,7 @@
   bool bind_local;
   bool remote_float;
   bool inetd;
+  bool sane_inetd;
   struct link_socket_addr *lsa;
   const char *ipchange_command;
   int resolve_retry_seconds;
@@ -189,6 +190,7 @@
 			      bool bind_local,
 			      bool remote_float,
 			      bool inetd,
+			      bool sane_inetd,
 			      struct link_socket_addr *lsa,
 			      const char *ipchange_command,
 			      int resolve_retry_seconds,