Blame

9399f3 Samuli Seppänen 2025-02-11 11:49:52 1
# OpenVPN as a Forking TCP Server Which Can Service Multiple Clients Over a Single TCP Port
2
3
**WARNING: this article is very outdated and refers to obsolete version of OpenVPN. This article is kept here purely for historical reference.**
4
5
See the OpenVPN 2.0 release notes.
6
7
Also:
8
9
Here at work, we wanted to implement a VPN solution for Roadwarriors who 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.
10
11
One problem though, was the inability to use a constant port number on the server side.
12
13
The `--inetd` option seemed very promising, but the man-page explicitly states that this option cannot 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).
14
15
A test later I found, that the code was written for inetd with "wait=yes" in mind, but that was quickly changed (see attached patch).
16
17
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.
18
19
Of course, this still runs one OpenVPN process per client. You still need one tap device per client, and configure bridging between them.
20
21
This also only works with SSL/TLS and tap devices, because of the single config file shared between all server processes.
22
23
The server config file in our case is easy:
24
```
25
# OpenVPN multiple-client-server
26
inetd nowait
27
proto tcp-server
28
29
# 10.254.0.1 is our local VPN endpoint (office).
30
dev tap
31
ifconfig 10.254.0.1 255.255.255.0
32
33
# Our up script will establish routes once the VPN is alive.
34
ifconfig-noexec
35
up /etc/openvpn/vpn-server.up
36
37
# We are SSL/TLS Server
38
tls-server
39
dh /etc/openvpn/dh2048.pem
40
ca /etc/openvpn/my-ca.crt
41
crl-verify /etc/openvpn/my-ca.crl
42
cert /etc/openvpn/server.crt
43
key /etc/openvpn/server.key
44
```
45
46
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.
47
48
My Bridging setup script (run once at bootup):
49
```
50
# load Bridging-Module
51
modprobe bridge
52
53
# configure bridge
54
brctl addbr br0
55
brctl stp br0 off
56
brctl setfd br0 0
57
58
# our private vpn network
59
ifconfig br0 10.254.0.1 netmask 0xffffff00 broadcast 10.254.0.255
60
```
61
62
The per-client setup script (vpn-server.up):
63
```
64
# add interface to bridge and activate
65
brctl addif br0 $1
66
ifconfig $1 up
67
```
68
69
And for completeness sake, here is the xinetd config file for the OpenVPN server:
70
```
71
service openvpn_1
72
{
73
type = UNLISTED
74
port = 443
75
socket_type = stream
76
protocol = tcp
77
wait = no
78
user = root
79
server = /usr/sbin/openvpn
80
server_args = --config /etc/openvpn/vpn-server.conf
81
disable = no
82
}
83
```
84
85
And that's it. It works for me. If you have any questions or comments, contact me, I'd be happy to hear from you.
86
87
CU,
88
Stefan `Sec` Zehl
89
90
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.
91
92
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.