GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 8dada9...ab747f )
by François
03:06
created

OpenVpn::getRoutes()   B

Complexity

Conditions 4
Paths 2

Size

Total Lines 37
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 37
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 14
nc 2
nop 1
1
<?php
2
/**
3
 *  Copyright (C) 2016 SURFnet.
4
 *
5
 *  This program is free software: you can redistribute it and/or modify
6
 *  it under the terms of the GNU Affero General Public License as
7
 *  published by the Free Software Foundation, either version 3 of the
8
 *  License, or (at your option) any later version.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU Affero General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU Affero General Public License
16
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18
namespace SURFnet\VPN\Server\Config;
19
20
use SURFnet\VPN\Server\PoolConfig;
21
use SURFnet\VPN\Server\IP;
22
use SURFnet\VPN\Common\FileIO;
23
use RuntimeException;
24
use SURFnet\VPN\Common\HttpClient\CaClient;
25
26
class OpenVpn
27
{
28
    /** @var string */
29
    private $vpnConfigDir;
30
31
    /** @var string */
32
    private $vpnTlsDir;
33
34
    public function __construct($vpnConfigDir, $vpnTlsDir)
35
    {
36
        FileIO::createDir($vpnConfigDir, 0700);
37
        $this->vpnConfigDir = $vpnConfigDir;
38
        FileIO::createDir($vpnTlsDir, 0700);
39
        $this->vpnTlsDir = $vpnTlsDir;
40
    }
41
42
    public function generateKeys(CaClient $caClient, $commonName, $dhSourceFile)
43
    {
44
        $certData = $caClient->addServerCertificate($commonName);
45
46
        $certFileMapping = [
47
            'ca' => sprintf('%s/ca.crt', $this->vpnTlsDir),
48
            'cert' => sprintf('%s/server.crt', $this->vpnTlsDir),
49
            'key' => sprintf('%s/server.key', $this->vpnTlsDir),
50
            'ta' => sprintf('%s/ta.key', $this->vpnTlsDir),
51
        ];
52
53
        foreach ($certFileMapping as $k => $v) {
54
            FileIO::writeFile($v, $certData[$k], 0600);
55
        }
56
57
        // copy the DH parameter file
58
        $dhTargetFile = sprintf('%s/dh.pem', $this->vpnTlsDir);
59
        if (false === copy($dhSourceFile, $dhTargetFile)) {
60
            throw new RuntimeException('unable to copy DH file');
61
        }
62
    }
63
64
    public function writePool($instanceNumber, $instanceId, $poolId, PoolConfig $poolConfig)
65
    {
66
        $range = new IP($poolConfig->v('range'));
67
        $range6 = new IP($poolConfig->v('range6'));
68
        $processCount = $poolConfig->v('processCount');
69
70
        $splitRange = $range->split($processCount);
71
        $splitRange6 = $range6->split($processCount);
72
73
        $processConfig = [
74
            'managementIp' => sprintf('127.42.%d.%d', 100 + $instanceNumber, 100 + $poolConfig->v('poolNumber')),
75
        ];
76
77
        for ($i = 0; $i < $processCount; ++$i) {
78
            // protocol is udp unless it is the last process when there is
79
            // not just one process
80
            if (1 === $processCount || $i !== $processCount - 1) {
81
                $proto = 'udp';
82
                $port = 1194 + $i;
83
            } else {
84
                $proto = 'tcp';
85
                $port = 1194;
86
            }
87
88
            $processConfig['range'] = $splitRange[$i];
89
            $processConfig['range6'] = $splitRange6[$i];
90
            $processConfig['dev'] = sprintf('tun-%d-%d-%d', $instanceNumber, $poolConfig->v('poolNumber'), $i);
91
            $processConfig['proto'] = $proto;
92
            $processConfig['port'] = $port;
93
            $processConfig['managementPort'] = 11940 + $i;
94
            $processConfig['configName'] = sprintf(
95
                'server-%s-%s-%d.conf',
96
                $instanceId,
97
                $poolId,
98
                $i
99
            );
100
101
            $this->writeProcess($instanceId, $poolId, $poolConfig, $processConfig);
102
        }
103
    }
104
105
    private function writeProcess($instanceId, $poolId, PoolConfig $poolConfig, array $processConfig)
106
    {
107
        $tlsDir = sprintf('/etc/openvpn/tls/%s/%s', $instanceId, $poolId);
108
109
        $rangeIp = new IP($processConfig['range']);
110
        $range6Ip = new IP($processConfig['range6']);
111
112
        // static options
113
        $serverConfig = [
114
            '# OpenVPN Server Configuration',
115
            'verb 3',
116
            'dev-type tun',
117
            'user openvpn',
118
            'group openvpn',
119
            'topology subnet',
120
            'persist-key',
121
            'persist-tun',
122
            'keepalive 10 60',
123
            'comp-lzo no',
124
            'remote-cert-tls client',
125
            'tls-version-min 1.2',
126
            'tls-cipher TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA',
127
            'auth SHA256',
128
            'cipher AES-256-CBC',
129
            'client-connect /usr/sbin/vpn-server-api-client-connect',
130
            'client-disconnect /usr/sbin/vpn-server-api-client-disconnect',
131
            'push "comp-lzo no"',
132
            'push "explicit-exit-notify 3"',
133
            sprintf('ca %s/ca.crt', $tlsDir),
134
            sprintf('cert %s/server.crt', $tlsDir),
135
            sprintf('key %s/server.key', $tlsDir),
136
            sprintf('dh %s/dh.pem', $tlsDir),
137
            sprintf('tls-auth %s/ta.key 0', $tlsDir),
138
            sprintf('server %s %s', $rangeIp->getNetwork(), $rangeIp->getNetmask()),
139
            sprintf('server-ipv6 %s', $range6Ip->getAddressPrefix()),
140
            sprintf('max-clients %d', $rangeIp->getNumberOfHosts() - 1),
141
            sprintf('script-security %d', $poolConfig->v('twoFactor') ? 3 : 2),
142
            sprintf('dev %s', $processConfig['dev']),
143
            sprintf('port %d', $processConfig['port']),
144
            sprintf('management %s %d', $processConfig['managementIp'], $processConfig['managementPort']),
145
            sprintf('setenv INSTANCE_ID %s', $instanceId),
146
            sprintf('setenv POOL_ID %s', $poolId),
147
            sprintf('proto %s', 'tcp' === $processConfig['proto'] ? 'tcp-server' : 'udp'),
148
            sprintf('local %s', 'tcp' === $processConfig['proto'] ? $processConfig['managementIp'] : $poolConfig->v('listen')),
149
150
            // increase the renegotiation time to 8h from the default of 1h when
151
            // using 2FA, otherwise the user would be asked for the 2FA key every
152
            // hour
153
            sprintf('reneg-sec %d', $poolConfig->v('twoFactor') ? 28800 : 3600),
154
        ];
155
156
        if (!$poolConfig->v('enableLog')) {
157
            $serverConfig[] = 'log /dev/null';
158
        }
159
160
        if ('tcp' === $processConfig['proto']) {
161
            $serverConfig[] = 'tcp-nodelay';
162
        }
163
164
        if ($poolConfig->v('twoFactor')) {
165
            $serverConfig[] = 'auth-user-pass-verify /usr/sbin/vpn-server-api-verify-otp via-env';
166
        }
167
168
        // Routes
169
        $serverConfig = array_merge($serverConfig, self::getRoutes($poolConfig));
170
171
        // DNS
172
        $serverConfig = array_merge($serverConfig, self::getDns($poolConfig));
173
174
        // Client-to-client
175
        $serverConfig = array_merge($serverConfig, self::getClientToClient($poolConfig));
176
177
        sort($serverConfig, SORT_STRING);
178
179
        $configFile = sprintf('%s/%s', $this->vpnConfigDir, $processConfig['configName']);
180
181
        FileIO::writeFile($configFile, implode(PHP_EOL, $serverConfig), 0600);
182
    }
183
184
    private static function getRoutes(PoolConfig $poolConfig)
185
    {
186
        $routeConfig = [];
187
        if ($poolConfig->v('defaultGateway')) {
188
            $routeConfig[] = 'push "redirect-gateway def1 bypass-dhcp"';
189
190
            // for Windows clients we need this extra route to mark the TAP adapter as
191
            // trusted and as having "Internet" access to allow the user to set it to
192
            // "Home" or "Work" to allow accessing file shares and printers
193
            // NOTE: this will break OS X tunnelblick because on disconnect it will
194
            // remove all default routes, including the one set before the VPN
195
            // was brought up
196
            //$routeConfig[] = 'push "route 0.0.0.0 0.0.0.0"';
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
197
198
            // for iOS we need this OpenVPN 2.4 "ipv6" flag to redirect-gateway
199
            // See https://docs.openvpn.net/docs/openvpn-connect/openvpn-connect-ios-faq.html
200
            $routeConfig[] = 'push "redirect-gateway ipv6"';
201
202
            // we use 2000::/3 instead of ::/0 because it seems to break on native IPv6
203
            // networks where the ::/0 default route already exists
204
            $routeConfig[] = 'push "route-ipv6 2000::/3"';
205
        } else {
206
            // there may be some routes specified, push those, and not the default
207
            foreach ($poolConfig->v('routes') as $route) {
208
                $routeIp = new IP($route);
209
                if (6 === $routeIp->getFamily()) {
210
                    // IPv6
211
                    $routeConfig[] = sprintf('push "route-ipv6 %s"', $routeIp->getAddressPrefix());
212
                } else {
213
                    // IPv4
214
                    $routeConfig[] = sprintf('push "route %s %s"', $routeIp->getAddress(), $routeIp->getNetmask());
215
                }
216
            }
217
        }
218
219
        return $routeConfig;
220
    }
221
222
    private static function getDns(PoolConfig $poolConfig)
223
    {
224
        // only push DNS if we are the default route
225
        if (!$poolConfig->v('defaultGateway')) {
226
            return [];
227
        }
228
229
        $dnsEntries = [];
230
        foreach ($poolConfig->v('dns') as $dnsAddress) {
231
            $dnsEntries[] = sprintf('push "dhcp-option DNS %s"', $dnsAddress);
232
        }
233
234
        // prevent DNS leakage on Windows
235
        $dnsEntries[] = 'push "block-outside-dns"';
236
237
        return $dnsEntries;
238
    }
239
240
    private static function getClientToClient(PoolConfig $poolConfig)
241
    {
242
        if (!$poolConfig->v('clientToClient')) {
243
            return [];
244
        }
245
246
        $rangeIp = new IP($poolConfig->v('range'));
247
        $range6Ip = new IP($poolConfig->v('range6'));
248
249
        return [
250
            'client-to-client',
251
            sprintf('push "route %s %s"', $rangeIp->getAddress(), $rangeIp->getNetmask()),
252
            sprintf('push "route-ipv6 %s"', $range6Ip->getAddressPrefix()),
253
        ];
254
    }
255
}
256