= OpenVPN as a , forking TCP server which can service multiple clients over a single TCP port? = {{{ #!html
See the OpenVPN 2.0 release notes.
Also:
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 [merged with OpenVPN as of 1.6-beta5]
adds a new option "--inetd nowait" which makes OpenVPN
work with a connected socket on stdin, like (x)inetd 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 nowait
| 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,
Stefan `Sec` Zehl
[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.
}}} [wiki:FAQ Return to FAQ]