1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace OpenVPN; |
4
|
|
|
|
5
|
|
|
use OpenVPN\Interfaces\ConfigInterface; |
6
|
|
|
use OpenVPN\Interfaces\GeneratorInterface; |
7
|
|
|
use RuntimeException; |
8
|
|
|
use function in_array; |
9
|
|
|
use function is_bool; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* Class Config |
13
|
|
|
* |
14
|
|
|
* @property string $modeSet OpenVPN major mode: p2p, server |
15
|
|
|
* @property string $local Local host name or IP address |
16
|
|
|
* @property string $remote Remote host name or IP address |
17
|
|
|
* @property bool|null $remoteRandom When multiple --remote address/ports are specified, initially randomize the order of the list |
18
|
|
|
* @property string $proto Protocol for communicating with remote host: tcp, udp, tcp-client |
19
|
|
|
* @property integer $connectRetry For --proto tcp-client, take n as the number of seconds to wait between connection retries (default=5) |
20
|
|
|
* @property string $httpProxy Connect to remote host through an HTTP proxy |
21
|
|
|
* @property bool|null $httpProxyRetry Retry indefinitely on HTTP proxy errors. If an HTTP proxy error occurs, simulate a SIGUSR1 reset. |
22
|
|
|
* @property integer $httpProxyTimeout Set proxy timeout to n seconds, default=5. |
23
|
|
|
* @property string $httpProxyOption Set extended HTTP proxy options |
24
|
|
|
* @property string $socksProxy Connect to remote host through a Socks5 proxy |
25
|
|
|
* @property bool|null $socksProxyRetry Retry indefinitely on Socks proxy errors. If a Socks proxy error occurs, simulate a SIGUSR1 reset. |
26
|
|
|
* @property string $resolvRetry If hostname resolve fails for --remote, retry resolve for n seconds before failing |
27
|
|
|
* @property bool|null $float Allow remote peer to change its IP address and/or port number, such as due to DHCP |
28
|
|
|
* @property string $ipchange Execute shell command, format: cmd ip_address port_number |
29
|
|
|
* @property integer $port TCP/UDP port number for both local and remote: 1194 |
30
|
|
|
* @property integer $lport TCP/UDP port number for local |
31
|
|
|
* @property integer $rport TCP/UDP port number for remote |
32
|
|
|
* @property bool|null $nobind Do not bind to local address and port |
33
|
|
|
* @property string $dev TUN/TAP virtual network device: tunX, tapX, null |
34
|
|
|
* @property string $devType Which device type are we using? device-type should be tun or tap |
35
|
|
|
* @property bool|null $tunIpv6 Build a tun link capable of forwarding IPv6 traffic |
36
|
|
|
* @property string $devNode Explicitly set the device node rather than using /dev/net/tun, /dev/tun, /dev/tap, etc. |
37
|
|
|
* @property string $ifconfig Set TUN/TAP adapter IP address of the local VPN endpoint. |
38
|
|
|
* @property bool|null $ifconfigNoexec Don’t actually execute ifconfig/netsh commands, instead pass –ifconfig parameters to scripts using environmental variables. |
39
|
|
|
* @property bool|null $ifconfigNowarn Don’t output an options consistency check warning |
40
|
|
|
* @property string $ifconfigPool Set aside a pool of subnets to be dynamically allocated to connecting clients, similar to a DHCP server. |
41
|
|
|
* @property string $ifconfigPoolPersist Persist/unpersist ifconfig-pool data to file, at secondsintervals (default=600), |
42
|
|
|
* @property string $cipher Encrypt packets with cipher algorithm alg. The default is BF-CBC,an abbreviation for Blowfish in Cipher Block Chaining mode. |
43
|
|
|
* @property bool|null $redirectGateway |
44
|
|
|
* @property integer $keyDirection |
45
|
|
|
* @property string $remoteCertTls |
46
|
|
|
* @property string $auth Authenticate packets with HMAC using message digest algorithm alg. (The default is SHA1). |
47
|
|
|
* @property bool|null $authUserPass |
48
|
|
|
* @property bool|null $authNocache |
49
|
|
|
* @property string $authUserPassVerify Path to login script |
50
|
|
|
* @property bool|null $duplicateCn You may need this if everyone is using same certificate |
51
|
|
|
* @property bool|null $persistKey |
52
|
|
|
* @property bool|null $persistTun |
53
|
|
|
* @property bool|null $compLzo Use fast LZO compression — may add up to 1 byte per packet for incompressible data. |
54
|
|
|
* @property bool|null $compNoadapt When used in conjunction with –comp-lzo, this option will disable OpenVPN’s adaptive compression algorithm. |
55
|
|
|
* @property integer $verb Set output verbosity to n(default=1). Each level shows all info from the previous levels: 0,1,2 ... 11 |
56
|
|
|
* @property string $server A helper directive designed to simplify the configuration of OpenVPN’s server mode. |
57
|
|
|
* @property string $serverBridge A helper directive similar to --server which is designed to simplify the configuration of OpenVPN’s server mode in ethernet bridging configurations. |
58
|
|
|
* @property string $keepalive |
59
|
|
|
* @property integer $renegSec |
60
|
|
|
* @property string $user |
61
|
|
|
* @property string $group |
62
|
|
|
* @property string $mute |
63
|
|
|
* @property string $status |
64
|
|
|
* @property string $logAppend |
65
|
|
|
* @property string $clientConfigDir |
66
|
|
|
* @property string $scriptSecurity |
67
|
|
|
* @property string $usernameAsCommonName |
68
|
|
|
* @property string $verifyClientCert |
69
|
|
|
* |
70
|
|
|
* @package OpenVPN |
71
|
|
|
*/ |
72
|
|
|
class Config implements ConfigInterface, GeneratorInterface |
73
|
|
|
{ |
74
|
|
|
/** |
75
|
|
|
* Array with all certificates |
76
|
|
|
* |
77
|
|
|
* @var array |
78
|
|
|
*/ |
79
|
|
|
private $certs = []; |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* List of all routes available on server |
83
|
|
|
* |
84
|
|
|
* @var array |
85
|
|
|
*/ |
86
|
|
|
private $routes = []; |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* List of lines which must be pushed to clients |
90
|
|
|
* |
91
|
|
|
* @var array |
92
|
|
|
*/ |
93
|
|
|
private $pushes = []; |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* All parameters added via addParam method |
97
|
|
|
* |
98
|
|
|
* @var array |
99
|
|
|
*/ |
100
|
|
|
private $parameters = []; |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Config constructor. |
104
|
|
|
* |
105
|
|
|
* @param array $parameters List of default parameters |
106
|
|
|
*/ |
107
|
6 |
|
public function __construct(array $parameters = []) |
108
|
|
|
{ |
109
|
6 |
|
$this->setParams($parameters); |
110
|
6 |
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* Alias for client line of config |
114
|
|
|
* |
115
|
|
|
* @return \OpenVPN\Interfaces\ConfigInterface |
116
|
|
|
*/ |
117
|
|
|
public function client(): ConfigInterface |
118
|
|
|
{ |
119
|
|
|
return $this->set('client'); |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Import content of all listed certificates |
124
|
|
|
* |
125
|
|
|
* @return void |
126
|
|
|
*/ |
127
|
|
|
public function loadCertificates(): void |
128
|
|
|
{ |
129
|
|
|
foreach ($this->certs as &$cert) { |
130
|
|
|
$cert['content'] = rtrim(file_get_contents($cert['path'])); |
131
|
|
|
} |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* Alias to setCert |
136
|
|
|
* |
137
|
|
|
* @deprecated TODO: Delete in future releases |
138
|
|
|
*/ |
139
|
|
|
public function addCert(string $type, string $pathOrContent, bool $isContent = false): ConfigInterface |
140
|
|
|
{ |
141
|
|
|
return $this->setCert($type, $pathOrContent, $isContent); |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* Add new cert into the configuration |
146
|
|
|
* |
147
|
|
|
* @param string $type Type of certificate [ca, cert, key, dh, tls-auth] |
148
|
|
|
* @param string $path Absolute or relative path to certificate or content of this file |
149
|
|
|
* @param bool|null $isContent If true, then script will try to load file from dist by $path |
150
|
|
|
* |
151
|
|
|
* @return \OpenVPN\Interfaces\ConfigInterface |
152
|
|
|
* @throws \RuntimeException |
153
|
|
|
*/ |
154
|
6 |
|
public function setCert(string $type, string $path, bool $isContent = null): ConfigInterface |
155
|
|
|
{ |
156
|
6 |
|
$type = mb_strtolower($type); |
157
|
6 |
|
Helpers::isCertAllowed($type); |
158
|
6 |
|
if (true === $isContent) { |
159
|
1 |
|
$this->certs[$type]['content'] = $path; |
160
|
|
|
} else { |
161
|
6 |
|
$this->certs[$type]['path'] = $path; |
162
|
|
|
} |
163
|
6 |
|
return $this; |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* Return information about specified certificate |
168
|
|
|
* |
169
|
|
|
* @param string $type |
170
|
|
|
* |
171
|
|
|
* @return array |
172
|
|
|
* @throws \RuntimeException |
173
|
|
|
*/ |
174
|
|
|
public function getCert(string $type): array |
175
|
|
|
{ |
176
|
|
|
$type = mb_strtolower($type); |
177
|
|
|
Helpers::isCertAllowed($type); |
178
|
|
|
return $this->certs[$type] ?? []; |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
/** |
182
|
|
|
* Alias to setPush |
183
|
|
|
* |
184
|
|
|
* @deprecated TODO: Delete in future releases |
185
|
|
|
*/ |
186
|
|
|
public function addPush(string $line): ConfigInterface |
187
|
|
|
{ |
188
|
|
|
return $this->setPush($line); |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* Append new push into the array |
193
|
|
|
* |
194
|
|
|
* @param string $line String with line which must be pushed |
195
|
|
|
* |
196
|
|
|
* @return \OpenVPN\Interfaces\ConfigInterface |
197
|
|
|
*/ |
198
|
3 |
|
public function setPush(string $line): ConfigInterface |
199
|
|
|
{ |
200
|
3 |
|
$this->pushes[] = trim($line, '"'); |
201
|
3 |
|
return $this; |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* Remove route line from push array |
206
|
|
|
* |
207
|
|
|
* @param string $line String with line which must be pushed |
208
|
|
|
* |
209
|
|
|
* @return \OpenVPN\Interfaces\ConfigInterface |
210
|
|
|
*/ |
211
|
|
|
public function unsetPush(string $line): ConfigInterface |
212
|
|
|
{ |
213
|
|
|
unset($this->pushes[$line]); |
214
|
|
|
return $this; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* Append new route into the array |
219
|
|
|
* |
220
|
|
|
* @param string $line String with route |
221
|
|
|
* |
222
|
|
|
* @return \OpenVPN\Interfaces\ConfigInterface |
223
|
|
|
*/ |
224
|
3 |
|
public function setRoute(string $line): ConfigInterface |
225
|
|
|
{ |
226
|
3 |
|
$this->routes[] = trim($line, '"'); |
227
|
3 |
|
return $this; |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
/** |
231
|
|
|
* Remove route line from routes array |
232
|
|
|
* |
233
|
|
|
* @param string $line String with route |
234
|
|
|
* |
235
|
|
|
* @return \OpenVPN\Interfaces\ConfigInterface |
236
|
|
|
*/ |
237
|
|
|
public function unsetRoute(string $line): ConfigInterface |
238
|
|
|
{ |
239
|
|
|
unset($this->routes[$line]); |
240
|
|
|
return $this; |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Alias to set |
245
|
|
|
* |
246
|
|
|
* @deprecated TODO: Delete in future releases |
247
|
|
|
*/ |
248
|
|
|
public function add(string $name, $value = null): ConfigInterface |
249
|
|
|
{ |
250
|
|
|
return $this->set($name, $value); |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
/** |
254
|
|
|
* Add some new parameter to the list of parameters |
255
|
|
|
* |
256
|
|
|
* @param string $name Name of parameter |
257
|
|
|
* @param string|bool|null $value Value of parameter |
258
|
|
|
* |
259
|
|
|
* @return \OpenVPN\Interfaces\ConfigInterface |
260
|
|
|
* @example $this->add('client')->add('remote', 'vpn.example.com'); |
261
|
|
|
*/ |
262
|
3 |
|
public function set(string $name, $value = null): ConfigInterface |
263
|
|
|
{ |
264
|
3 |
|
$name = mb_strtolower($name); |
265
|
|
|
|
266
|
|
|
// Check if key is certificate or push, or classic parameter |
267
|
3 |
|
if (in_array($name, self::ALLOWED_TYPES_OF_CERTS, true)) { |
268
|
3 |
|
return $this->setCert($name, $value); |
|
|
|
|
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
// If is push then use add push method |
272
|
3 |
|
if ($name === 'push') { |
273
|
3 |
|
return $this->setPush($value); |
|
|
|
|
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
// If is push then use add push method |
277
|
3 |
|
if ($name === 'route') { |
278
|
3 |
|
return $this->setRoute($value); |
|
|
|
|
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
// Check if provided value is boolean and if it's true, then set null (that mean parameter without value) |
282
|
3 |
|
if (is_bool($value) && $value) { |
283
|
3 |
|
if ($value) { |
284
|
3 |
|
$value = null; |
285
|
|
|
} else { |
286
|
|
|
// If false then skip this step |
287
|
|
|
return $this; |
288
|
|
|
} |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
// Set new value |
292
|
3 |
|
$this->parameters[$name] = $value; |
293
|
|
|
|
294
|
3 |
|
return $this; |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
/** |
298
|
|
|
* Get some custom element |
299
|
|
|
* |
300
|
|
|
* @param string|null $name Name of parameter |
301
|
|
|
* |
302
|
|
|
* @return mixed |
303
|
|
|
*/ |
304
|
|
|
public function get(string $name) |
305
|
|
|
{ |
306
|
|
|
return $this->parameters[$name] ?? null; |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
/** |
310
|
|
|
* Generate config by parameters in memory |
311
|
|
|
* |
312
|
|
|
* @return string |
313
|
|
|
*/ |
314
|
1 |
|
public function generate(): string |
315
|
|
|
{ |
316
|
1 |
|
$generator = new Generator($this); |
317
|
1 |
|
return $generator->generate(); |
318
|
|
|
} |
319
|
|
|
|
320
|
|
|
/** |
321
|
|
|
* @param string $name |
322
|
|
|
* |
323
|
|
|
* @return bool |
324
|
|
|
*/ |
325
|
|
|
public function __isset(string $name): bool |
326
|
|
|
{ |
327
|
|
|
// Inform about deleting push |
328
|
|
|
if ($name === 'push') { |
329
|
|
|
throw new RuntimeException("Not possible to remove push, use 'unsetPush' instead"); |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
// Inform about deleting route |
333
|
|
|
if ($name === 'route') { |
334
|
|
|
throw new RuntimeException("Not possible to remove route, use 'unsetRoute' instead"); |
335
|
|
|
} |
336
|
|
|
|
337
|
|
|
return isset($this->parameters[$name]); |
338
|
|
|
} |
339
|
|
|
|
340
|
|
|
/** |
341
|
|
|
* @param string $name |
342
|
|
|
* @param string|bool|integer|null $value |
343
|
|
|
*/ |
344
|
3 |
|
public function __set(string $name, $value = null): void |
345
|
|
|
{ |
346
|
3 |
|
$name = Helpers::decamelize($name); |
347
|
3 |
|
$this->set($name, $value); |
348
|
3 |
|
} |
349
|
|
|
|
350
|
|
|
/** |
351
|
|
|
* @param string $name |
352
|
|
|
* |
353
|
|
|
* @return string|bool|null |
354
|
|
|
*/ |
355
|
|
|
public function __get(string $name) |
356
|
|
|
{ |
357
|
|
|
return $this->get($name); |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
/** |
361
|
|
|
* Remove some parameter from array by name |
362
|
|
|
* |
363
|
|
|
* @param string $name Name of parameter |
364
|
|
|
* |
365
|
|
|
* @return void |
366
|
|
|
* @throws \RuntimeException |
367
|
|
|
*/ |
368
|
|
|
public function __unset(string $name) |
369
|
|
|
{ |
370
|
|
|
// Inform about deleting push |
371
|
|
|
if ($name === 'push') { |
372
|
|
|
throw new RuntimeException("Not possible to remove push, use 'unsetPush' instead"); |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
// Inform about deleting route |
376
|
|
|
if ($name === 'route') { |
377
|
|
|
throw new RuntimeException("Not possible to remove route, use 'unsetRoute' instead"); |
378
|
|
|
} |
379
|
|
|
|
380
|
|
|
// Check if key is certificate or push, or classic parameter |
381
|
|
|
if (in_array($name, self::ALLOWED_TYPES_OF_CERTS, true)) { |
382
|
|
|
$this->unsetCert($name); |
383
|
|
|
return; |
384
|
|
|
} |
385
|
|
|
|
386
|
|
|
// Update list of parameters |
387
|
|
|
$this->parameters = array_map( |
388
|
|
|
static function ($param) use ($name) { |
389
|
|
|
return ($param['name'] === $name) ? null : $param; |
390
|
|
|
}, |
391
|
|
|
$this->parameters |
392
|
|
|
); |
393
|
|
|
} |
394
|
|
|
|
395
|
|
|
/** |
396
|
|
|
* Remove selected certificate from array |
397
|
|
|
* |
398
|
|
|
* @param string $type Type of certificate [ca, cert, key, dh, tls-auth] |
399
|
|
|
* |
400
|
|
|
* @return \OpenVPN\Interfaces\ConfigInterface |
401
|
|
|
* @throws \RuntimeException |
402
|
|
|
*/ |
403
|
2 |
|
public function unsetCert(string $type): ConfigInterface |
404
|
|
|
{ |
405
|
2 |
|
$type = mb_strtolower($type); |
406
|
2 |
|
Helpers::isCertAllowed($type); |
407
|
2 |
|
unset($this->certs[$type]); |
408
|
2 |
|
return $this; |
409
|
|
|
} |
410
|
|
|
|
411
|
|
|
/** |
412
|
|
|
* Set scope of certs |
413
|
|
|
* |
414
|
|
|
* @param \OpenVPN\Types\Cert[] $certs |
415
|
|
|
* @param bool $loadCertificates |
416
|
|
|
* |
417
|
|
|
* @return \OpenVPN\Interfaces\ConfigInterface |
418
|
|
|
*/ |
419
|
3 |
|
public function setCerts(array $certs, bool $loadCertificates = false): ConfigInterface |
420
|
|
|
{ |
421
|
|
|
// Pass list of certs from array to variable |
422
|
3 |
|
foreach ($certs as $type => $path) { |
423
|
3 |
|
$this->setCert($type, $path); |
|
|
|
|
424
|
|
|
} |
425
|
|
|
|
426
|
|
|
// If need to load content of files from disk |
427
|
3 |
|
if ($loadCertificates) { |
428
|
|
|
$this->loadCertificates(); |
429
|
|
|
} |
430
|
|
|
|
431
|
3 |
|
return $this; |
432
|
|
|
} |
433
|
|
|
|
434
|
|
|
/** |
435
|
|
|
* Set scope of unique pushes |
436
|
|
|
* |
437
|
|
|
* @param \OpenVPN\Types\Push[] $pushes |
438
|
|
|
* |
439
|
|
|
* @return \OpenVPN\Interfaces\ConfigInterface |
440
|
|
|
*/ |
441
|
3 |
|
public function setPushes(array $pushes): ConfigInterface |
442
|
|
|
{ |
443
|
3 |
|
foreach ($pushes as $push) { |
444
|
3 |
|
$this->setPush($push); |
|
|
|
|
445
|
|
|
} |
446
|
|
|
|
447
|
3 |
|
return $this; |
448
|
|
|
} |
449
|
|
|
|
450
|
|
|
/** |
451
|
|
|
* Set scope of unique routes |
452
|
|
|
* |
453
|
|
|
* @param \OpenVPN\Types\Route[] $routes |
454
|
|
|
* |
455
|
|
|
* @return \OpenVPN\Interfaces\ConfigInterface |
456
|
|
|
*/ |
457
|
3 |
|
public function setRoutes(array $routes): ConfigInterface |
458
|
|
|
{ |
459
|
3 |
|
foreach ($routes as $route) { |
460
|
3 |
|
$this->setRoute($route); |
|
|
|
|
461
|
|
|
} |
462
|
|
|
|
463
|
3 |
|
return $this; |
464
|
|
|
} |
465
|
|
|
|
466
|
|
|
/** |
467
|
|
|
* Set scope of unique parameters |
468
|
|
|
* |
469
|
|
|
* @param \OpenVPN\Types\Parameter[] $parameters |
470
|
|
|
* |
471
|
|
|
* @return \OpenVPN\Interfaces\ConfigInterface |
472
|
|
|
*/ |
473
|
6 |
|
public function setParams(array $parameters): ConfigInterface |
474
|
|
|
{ |
475
|
6 |
|
foreach ($parameters as $name => $value) { |
476
|
|
|
$this->set($name, $value); |
|
|
|
|
477
|
|
|
} |
478
|
|
|
|
479
|
6 |
|
return $this; |
480
|
|
|
} |
481
|
|
|
|
482
|
|
|
/** |
483
|
|
|
* Export array of all certificates |
484
|
|
|
* |
485
|
|
|
* @return array |
486
|
|
|
*/ |
487
|
6 |
|
public function getCerts(): array |
488
|
|
|
{ |
489
|
6 |
|
return $this->certs; |
490
|
|
|
} |
491
|
|
|
|
492
|
|
|
/** |
493
|
|
|
* Export array of all pushes |
494
|
|
|
* |
495
|
|
|
* @return array |
496
|
|
|
*/ |
497
|
3 |
|
public function getPushes(): array |
498
|
|
|
{ |
499
|
3 |
|
return $this->pushes; |
500
|
|
|
} |
501
|
|
|
|
502
|
|
|
/** |
503
|
|
|
* Export array of all routes |
504
|
|
|
* |
505
|
|
|
* @return array |
506
|
|
|
*/ |
507
|
3 |
|
public function getRoutes(): array |
508
|
|
|
{ |
509
|
3 |
|
return $this->routes; |
510
|
|
|
} |
511
|
|
|
|
512
|
|
|
/** |
513
|
|
|
* Export array of all parameters |
514
|
|
|
* |
515
|
|
|
* @return array |
516
|
|
|
*/ |
517
|
3 |
|
public function getParameters(): array |
518
|
|
|
{ |
519
|
3 |
|
return $this->parameters; |
520
|
|
|
} |
521
|
|
|
} |
522
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.