Project

General

Profile

Download (39.4 KB) Statistics
| Branch: | Tag: | Revision:
1 5b237745 Scott Ullrich
<?php
2 b1ad443d Scott Ullrich
/*
3 9a6d6728 Ermal
	openvpn.inc part of pfSense
4 33ab8aa5 Scott Ullrich
	
5
	Copyright (C) 2008 Scott Ullrich <sullrich@gmail.com>
6
	All rights reserved.
7
	
8 b1ad443d Scott Ullrich
	Copyright (C) 2006  Fernando Lemos
9
	All rights reserved.
10
11 33ab8aa5 Scott Ullrich
	This file was rewritten from scratch by Fernando Lemos but
12
	*MIGHT* contain code previously written by:
13
14 b1ad443d Scott Ullrich
	Copyright (C) 2005 Peter Allgeyer <allgeyer_AT_web.de>
15
	All rights reserved.
16
17
	Copyright (C) 2004 Peter Curran (peter@closeconsultants.com).
18
	All rights reserved.
19
20
	Redistribution and use in source and binary forms, with or without
21
	modification, are permitted provided that the following conditions are met:
22
23
	1. Redistributions of source code must retain the above copyright notices,
24
	   this list of conditions and the following disclaimer.
25
26
	2. Redistributions in binary form must reproduce the above copyright
27
	   notices, this list of conditions and the following disclaimer in the
28
	   documentation and/or other materials provided with the distribution.
29
30
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
31
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
32
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
33
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
34
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39
	POSSIBILITY OF SUCH DAMAGE.
40 523855b0 Scott Ullrich
	
41
	DISABLE_PHP_LINT_CHECKING
42
	
43 dae707f5 jim-p
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/openvpn	/usr/local/bin/openssl	/sbin/ifconfig
44 523855b0 Scott Ullrich
	pfSense_MODULE:	openvpn
45 b1ad443d Scott Ullrich
46 523855b0 Scott Ullrich
*/
47 8dc3ef67 Scott Ullrich
require_once('config.inc');
48 32a7a1f6 Ermal Lu?i
require_once("certs.inc");
49 36df0acc Scott Ullrich
require_once('pfsense-utils.inc');
50 c61e4626 Ermal Lu?i
require_once("auth.inc");
51 8dc3ef67 Scott Ullrich
52 6714bbdc jim-p
$openvpn_prots = array("UDP", "UDP6", "TCP", "TCP6");
53 702a4702 Scott Ullrich
54 691fbf14 Ermal Lu?i
$openvpn_dev_mode = array("tun", "tap");
55
56 3c11bd3c Matthew Grooms
/* 
57
 * The User Auth mode below is disabled because
58
 * OpenVPN erroneously requires that we provide
59
 * a CA configuration parameter. In this mode,
60
 * clients don't send a certificate so there is
61
 * no need for a CA. If we require that admins
62
 * provide one in the pfSense UI due to a bogus
63
 * requirement imposed by OpenVPN, it could be
64
 * considered very confusing ( I know I was ).
65
 *
66
 * -mgrooms
67
 */
68
69 fe787fc7 Matthew Grooms
$openvpn_dh_lengths = array(
70
	1024, 2048, 4096 );
71
72 98963f27 jim-p
$openvpn_cert_depths = array(
73
	1 => "One (Client+Server)",
74
	2 => "Two (Client+Intermediate+Server)",
75
	3 => "Three (Client+2xIntermediate+Server)",
76
	4 => "Four (Client+3xIntermediate+Server)",
77
	5 => "Five (Client+4xIntermediate+Server)"
78
);
79
80 3c11bd3c Matthew Grooms
$openvpn_server_modes = array(
81 4aa02281 Carlos Eduardo Ramos
	'p2p_tls' => gettext("Peer to Peer ( SSL/TLS )"),
82
	'p2p_shared_key' => gettext("Peer to Peer ( Shared Key )"),
83
	'server_tls' => gettext("Remote Access ( SSL/TLS )"),
84
	'server_user' => gettext("Remote Access ( User Auth )"),
85
	'server_tls_user' => gettext("Remote Access ( SSL/TLS + User Auth )"));
86 3c11bd3c Matthew Grooms
87
$openvpn_client_modes = array(
88 4aa02281 Carlos Eduardo Ramos
	'p2p_tls' => gettext("Peer to Peer ( SSL/TLS )"),
89
	'p2p_shared_key' => gettext("Peer to Peer ( Shared Key )") );
90 3c11bd3c Matthew Grooms
91
function openvpn_create_key() {
92
93
	$fp = popen("/usr/local/sbin/openvpn --genkey --secret /dev/stdout 2>/dev/null", "r");
94
	if (!$fp)
95
		return false;
96
97
	$rslt = stream_get_contents($fp);
98
	pclose($fp);
99
100
	return $rslt;
101
}
102 d799787e Matthew Grooms
103 8411b218 Matthew Grooms
function openvpn_create_dhparams($bits) {
104 34bc1324 Matthew Grooms
105 dae707f5 jim-p
	$fp = popen("/usr/local/bin/openssl dhparam {$bits} 2>/dev/null", "r");
106 34bc1324 Matthew Grooms
	if (!$fp)
107
		return false;
108
109
	$rslt = stream_get_contents($fp);
110
	pclose($fp);
111
112
	return $rslt;
113
}
114
115 d799787e Matthew Grooms
function openvpn_vpnid_used($vpnid) {
116 8be2d6d3 Ermal Luçi
	global $config;
117
118 d799787e Matthew Grooms
	if (is_array($config['openvpn']['openvpn-server']))
119 dc408939 Matthew Grooms
		foreach ($config['openvpn']['openvpn-server'] as & $settings)
120 f432e364 Matthew Grooms
			if ($vpnid == $settings['vpnid'])
121 d799787e Matthew Grooms
				return true;
122
123
	if (is_array($config['openvpn']['openvpn-client']))
124 dc408939 Matthew Grooms
		foreach ($config['openvpn']['openvpn-client'] as & $settings)
125 f432e364 Matthew Grooms
			if ($vpnid == $settings['vpnid'])
126 d799787e Matthew Grooms
				return true;
127 04a6e900 Ermal Luçi
128 d799787e Matthew Grooms
	return false;
129
}
130
131
function openvpn_vpnid_next() {
132
133
	$vpnid = 1;
134
	while(openvpn_vpnid_used($vpnid))
135
		$vpnid++;
136
137
	return $vpnid;
138
}
139
140 49b76122 Renato Botelho
function openvpn_port_used($prot, $interface, $port, $curvpnid = 0) {
141 f432e364 Matthew Grooms
	global $config;
142
143 49b76122 Renato Botelho
	if (is_array($config['openvpn']['openvpn-server'])) {
144
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
145
			if (isset($settings['disable']))
146
				continue;
147
148
			if ($curvpnid != 0 && $curvpnid == $settings['vpnid'])
149
				continue;
150
151
			if ($port == $settings['local_port'] && $prot == $settings['protocol'] &&
152
				($interface == $settings['interface'] || $interface == "any" || $settings['interface'] == "any"))
153 f432e364 Matthew Grooms
				return $settings['vpnid'];
154 49b76122 Renato Botelho
		}
155
	}
156 f432e364 Matthew Grooms
157 49b76122 Renato Botelho
	if (is_array($config['openvpn']['openvpn-client'])) {
158
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
159
			if (isset($settings['disable']))
160
				continue;
161
162
			if ($curvpnid != 0 && $curvpnid == $settings['vpnid'])
163
				continue;
164
165
			if ($port == $settings['local_port'] && $prot == $settings['protocol'] &&
166
				($interface == $settings['interface'] || $interface == "any" || $settings['interface'] == "any"))
167 f432e364 Matthew Grooms
				return $settings['vpnid'];
168 49b76122 Renato Botelho
		}
169
	}
170 f432e364 Matthew Grooms
171
	return 0;
172
}
173
174 49b76122 Renato Botelho
function openvpn_port_next($prot, $interface = "wan") {
175 f432e364 Matthew Grooms
176
	$port = 1194;
177 49b76122 Renato Botelho
	while(openvpn_port_used($prot, $interface, $port))
178
		$port++;
179
	while(openvpn_port_used($prot, "any", $port))
180 f432e364 Matthew Grooms
		$port++;
181
182
	return $port;
183
}
184
185 d799787e Matthew Grooms
function openvpn_get_cipherlist() {
186
187
	$ciphers = array();
188 5a7cc1f9 Ermal
	$cipher_out = shell_exec('/usr/local/sbin/openvpn --show-ciphers | /usr/bin/grep "default key" | /usr/bin/awk \'{print $1, "(" $2 "-" $3 ")";}\'');
189 d799787e Matthew Grooms
	$cipher_lines = explode("\n", trim($cipher_out));
190
	sort($cipher_lines);
191
	foreach ($cipher_lines as $line) {
192
		$words = explode(' ', $line);
193
		$ciphers[$words[0]] = "{$words[0]} {$words[1]}";
194 8be2d6d3 Ermal Luçi
	}
195 4aa02281 Carlos Eduardo Ramos
	$ciphers["none"] = gettext("None (No Encryption)");
196 d799787e Matthew Grooms
	return $ciphers;
197
}
198
199 582c58ae jim-p
function openvpn_get_engines() {
200
	$openssl_engines = array('none' => 'No Hardware Crypto Acceleration');
201 349bf358 jim-p
	exec("/usr/local/bin/openssl engine -t -c", $openssl_engine_output);
202
	$openssl_engine_output = implode("\n", $openssl_engine_output);
203
	$openssl_engine_output = preg_replace("/\\n\\s+/", "|", $openssl_engine_output);
204
	$openssl_engine_output = explode("\n", $openssl_engine_output);
205
206 582c58ae jim-p
	foreach ($openssl_engine_output as $oeo) {
207 349bf358 jim-p
		$keep = true;
208
		$details = explode("|", $oeo);
209
		$engine = array_shift($details);
210 582c58ae jim-p
		$linematch = array();
211 349bf358 jim-p
		preg_match("/\((.*)\)\s(.*)/", $engine, $linematch);
212
		foreach ($details as $dt) {
213
			if (strpos($dt, "unavailable") !== FALSE)
214
				$keep = false;
215
			if (strpos($dt, "available") !== FALSE)
216
				continue;
217
			if (strpos($dt, "[") !== FALSE)
218
				$ciphers = trim($dt, "[]");
219
		}
220
		if (!empty($ciphers))
221
			$ciphers = " - " . $ciphers;
222
		if (strlen($ciphers) > 60)
223
			$ciphers = substr($ciphers, 0, 60) . " ... ";
224
		if ($keep)
225
			$openssl_engines[$linematch[1]] = $linematch[2] . $ciphers;
226 582c58ae jim-p
	}
227
	return $openssl_engines;
228
}
229
230
function openvpn_validate_engine($engine) {
231
	$engines = openvpn_get_engines();
232
	return array_key_exists($engine, $engines);
233
}
234
235 d799787e Matthew Grooms
function openvpn_validate_host($value, $name) {
236
	$value = trim($value);
237 3e2bd5de Ermal Lu?i
	if (empty($value) || (!is_domain($value) && !is_ipaddr($value)))
238 4aa02281 Carlos Eduardo Ramos
		return sprintf(gettext("The field '%s' must contain a valid IP address or domain name."), $name);
239 d799787e Matthew Grooms
	return false;
240 8dc3ef67 Scott Ullrich
}
241
242
function openvpn_validate_port($value, $name) {
243
	$value = trim($value);
244 3e2bd5de Ermal Lu?i
	if (empty($value) || !is_numeric($value) || $value < 0 || ($value > 65535))
245 4aa02281 Carlos Eduardo Ramos
		return sprintf(gettext("The field '%s' must contain a valid port, ranging from 0 to 65535."), $name);
246 b398bbca Martin Fuchs
	return false;
247 8dc3ef67 Scott Ullrich
}
248
249 a28d40cb jim-p
function openvpn_validate_cidr($value, $name, $multiple = false, $ipproto = "ipv4") {
250
	$value = trim($value);
251
	$error = false;
252
	if (empty($value))
253
		return false;
254
	$networks = explode(',', $value);
255
256
	if (!$multiple && (count($networks) > 1))
257
		return sprintf(gettext("The field '%s' must contain a single valid %s CIDR range."), $name, $ipproto);
258
259
	foreach ($networks as $network) {
260
		if ($ipproto == "ipv4")
261
			$error = !openvpn_validate_cidr_ipv4($network);
262
		else
263
			$error = !openvpn_validate_cidr_ipv6($network);
264
		if ($error)
265
			break;
266
	}
267
268
	if ($error)
269
		return sprintf(gettext("The field '%s' must contain only valid %s CIDR range(s) separated by commas."), $name, $ipproto);
270
	else
271
		return false;
272
}
273
274
function openvpn_validate_cidr_ipv4($value) {
275 8dc3ef67 Scott Ullrich
	$value = trim($value);
276
	if (!empty($value)) {
277
		list($ip, $mask) = explode('/', $value);
278 a28d40cb jim-p
		if (!is_ipaddrv4($ip) or !is_numeric($mask) or ($mask > 32) or ($mask < 0))
279
			return false;
280 8dc3ef67 Scott Ullrich
	}
281 a28d40cb jim-p
	return true;
282
}
283
284
function openvpn_validate_cidr_ipv6($value) {
285
	$value = trim($value);
286
	if (!empty($value)) {
287
		list($ipv6, $prefix) = explode('/', $value);
288
		if (empty($prefix))
289
			$prefix = "128";
290
		if (!is_ipaddrv6($ipv6) or !is_numeric($prefix) or ($prefix > 128) or ($prefix < 0))
291
			return false;
292
	}
293
	return true;
294 afb07cf1 Scott Ullrich
}
295
296 d799787e Matthew Grooms
function openvpn_add_dhcpopts(& $settings, & $conf) {
297 afb07cf1 Scott Ullrich
298 d799787e Matthew Grooms
	if (!empty($settings['dns_domain'])) 
299
		$conf .= "push \"dhcp-option DOMAIN {$settings['dns_domain']}\"\n";
300 add2e3f7 Scott Ullrich
301 d799787e Matthew Grooms
	if (!empty($settings['dns_server1']))
302
		$conf .= "push \"dhcp-option DNS {$settings['dns_server1']}\"\n";
303
	if (!empty($settings['dns_server2']))
304
		$conf .= "push \"dhcp-option DNS {$settings['dns_server2']}\"\n";
305
	if (!empty($settings['dns_server3']))
306
		$conf .= "push \"dhcp-option DNS {$settings['dns_server3']}\"\n";
307
	if (!empty($settings['dns_server4']))
308
		$conf .= "push \"dhcp-option DNS {$settings['dns_server4']}\"\n";
309 f9927473 Scott Ullrich
310 d799787e Matthew Grooms
	if (!empty($settings['ntp_server1']))
311 c7f70dbc Chris Buechler
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server1']}\"\n";
312 d799787e Matthew Grooms
	if (!empty($settings['ntp_server2']))
313 c7f70dbc Chris Buechler
		$conf .= "push \"dhcp-option NTP {$settings['ntp_server2']}\"\n";
314 f9927473 Scott Ullrich
315 d799787e Matthew Grooms
	if ($settings['netbios_enable']) {
316 add2e3f7 Scott Ullrich
317 095a95ae Matthew Grooms
		if (!empty($settings['dhcp_nbttype']) && ($settings['dhcp_nbttype'] != 0))
318
			$conf .= "push \"dhcp-option NBT {$settings['dhcp_nbttype']}\"\n";
319
		if (!empty($settings['dhcp_nbtscope'])) 
320 d799787e Matthew Grooms
			$conf .= "push \"dhcp-option NBS {$settings['dhcp_nbtscope']}\"\n";
321 8dc3ef67 Scott Ullrich
322 d799787e Matthew Grooms
		if (!empty($settings['wins_server1']))
323
			$conf .= "push \"dhcp-option WINS {$settings['wins_server1']}\"\n";
324
		if (!empty($settings['wins_server2']))
325
			$conf .= "push \"dhcp-option WINS {$settings['wins_server2']}\"\n";
326 add2e3f7 Scott Ullrich
327 d799787e Matthew Grooms
		if (!empty($settings['nbdd_server1']))
328
			$conf .= "push \"dhcp-option NBDD {$settings['nbdd_server1']}\"\n";
329
	}
330 8dc3ef67 Scott Ullrich
331 d799787e Matthew Grooms
	if ($settings['gwredir']) 
332
		$conf .= "push \"redirect-gateway def1\"\n";
333
}
334 24012690 Scott Ullrich
335 d799787e Matthew Grooms
function openvpn_add_custom(& $settings, & $conf) {
336 add2e3f7 Scott Ullrich
337 d799787e Matthew Grooms
	if ($settings['custom_options']) {
338 8dc3ef67 Scott Ullrich
339 d799787e Matthew Grooms
		$options = explode(';', $settings['custom_options']);
340
341
		if (is_array($options)) {
342
			foreach ($options as $option)
343
				$conf .= "$option\n";
344
		} else
345
			$conf .= "{$settings['custom_options']}\n";
346 add2e3f7 Scott Ullrich
	}
347
}
348
349 691fbf14 Ermal Lu?i
function openvpn_add_keyfile(& $data, & $conf, $mode_id, $directive, $opt = "") {
350 d799787e Matthew Grooms
	global $g;
351 add2e3f7 Scott Ullrich
352 d799787e Matthew Grooms
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.{$directive}";
353 a8f538a8 jim-p
	openvpn_create_dirs();
354 d799787e Matthew Grooms
	file_put_contents($fpath, base64_decode($data));
355 f9ac3784 Ermal Lu?i
	//chown($fpath, 'nobody');
356
	//chgrp($fpath, 'nobody');
357 6f27412f Ermal Lu?i
	@chmod($fpath, 0600);
358 d799787e Matthew Grooms
359 691fbf14 Ermal Lu?i
	$conf .= "{$directive} {$fpath} {$opt}\n";
360 4eefa6e8 Scott Ullrich
}
361
362 fc05822b jim-p
function openvpn_reconfigure($mode, $settings) {
363 add2e3f7 Scott Ullrich
	global $g, $config;
364 afb07cf1 Scott Ullrich
365 93a0a028 Ermal Luçi
	if (empty($settings))
366
		return;
367 a1cab2c7 Ermal
	if (isset($settings['disable'])) 
368 4eefa6e8 Scott Ullrich
		return;
369 a8f538a8 jim-p
	openvpn_create_dirs();
370 fdd725f0 Ermal Luçi
	/*
371 d799787e Matthew Grooms
	 * NOTE: Deleting tap devices causes spontaneous reboots. Instead,
372
	 * we use a vpnid number which is allocated for a particular client
373
	 * or server configuration. ( see openvpn_vpnid_next() )
374 fdd725f0 Ermal Luçi
	 */
375 8874c692 Ermal Luçi
376 d799787e Matthew Grooms
	$vpnid = $settings['vpnid'];
377
	$mode_id = $mode.$vpnid;
378 8874c692 Ermal Luçi
379 4936ff53 jim-p
	if (isset($settings['dev_mode']))
380
		$tunname = "{$settings['dev_mode']}{$vpnid}";
381 bd7ca506 jim-p
	else {	/* defaults to tun */
382
		$tunname = "tun{$vpnid}";
383 4936ff53 jim-p
		$settings['dev_mode'] = "tun";
384 691fbf14 Ermal Lu?i
	}
385
386 bd7ca506 jim-p
	if ($mode == "server")
387
		$devname = "ovpns{$vpnid}";
388
	else
389
		$devname = "ovpnc{$vpnid}";
390 8874c692 Ermal Luçi
391 bd7ca506 jim-p
	/* is our device already configured */
392 1bc783b6 bcyrill
	if (mwexec("/sbin/ifconfig {$devname}", true)) {
393 dc408939 Matthew Grooms
394 bd7ca506 jim-p
		/* create the tap device if required */
395
		if (!file_exists("/dev/{$tunname}"))
396
			exec("/sbin/ifconfig {$tunname} create");
397 98872d89 Ermal Luçi
398 bd7ca506 jim-p
		/* rename the device */
399
		mwexec("/sbin/ifconfig {$tunname} name {$devname}");
400 095a95ae Matthew Grooms
401 bd7ca506 jim-p
		/* add the device to the openvpn group */
402
		mwexec("/sbin/ifconfig {$devname} group openvpn");
403 dc408939 Matthew Grooms
	}
404 d799787e Matthew Grooms
405 dc408939 Matthew Grooms
	$pfile = $g['varrun_path'] . "/openvpn_{$mode_id}.pid";
406 6714bbdc jim-p
	$proto = strtolower($settings['protocol']);
407
	if (substr($settings['protocol'], 0, 3) == "TCP")
408
			$proto = "{$proto}-{$mode}";
409 4936ff53 jim-p
	$dev_mode = $settings['dev_mode'];
410 c0cf27aa Scott Ullrich
	$cipher = $settings['crypto'];
411 d799787e Matthew Grooms
412 47c48e28 smos
	$interface = get_failover_interface($settings['interface']);
413 d7a0c22a bcyrill
	$ipaddr = $settings['ipaddr'];
414
	$ipaddrv6 = $settings['ipaddrv6'];
415 d799787e Matthew Grooms
416 67b0902f pierrepomes
	// If a specific ip address (VIP) is requested, use it.
417
	// Otherwise, if a specific interface is requested, use it
418
	// If "any" interface was selected, local directive will be ommited.
419 97ffc513 Seth Mos
	if (is_ipaddrv4($ipaddr)) {
420 67b0902f pierrepomes
		$iface_ip=$ipaddr;
421 3d06e8f0 pierrepomes
	} else {
422 67b0902f pierrepomes
		if ((!empty($interface)) && (strcmp($interface, "any"))) {
423 507af8dd pierrepomes
			$iface_ip=get_interface_ip($interface);
424 67b0902f pierrepomes
		}
425 47c48e28 smos
	}
426
	if (is_ipaddrv6($ipaddrv6)) {
427
		$iface_ipv6=$ipaddrv6;
428
	} else {
429 97ffc513 Seth Mos
		if ((!empty($interface)) && (strcmp($interface, "any"))) {
430
			$iface_ipv6=get_interface_ipv6($interface);
431
		}
432 3d06e8f0 pierrepomes
	}
433 d799787e Matthew Grooms
434 bd7ca506 jim-p
	$conf  = "dev {$devname}\n";
435 4936ff53 jim-p
	$conf .= "dev-type {$settings['dev_mode']}\n";
436 97ffc513 Seth Mos
	switch($settings['dev_mode']) {
437
		case "tun":
438
			$conf .= "tun-ipv6\n";
439
			break;
440
	}
441 bd7ca506 jim-p
	$conf .= "dev-node /dev/{$tunname}\n";
442 3c11bd3c Matthew Grooms
	$conf .= "writepid {$pfile}\n";
443
	$conf .= "#user nobody\n";
444
	$conf .= "#group nobody\n";
445 d1014c18 Chris Buechler
	$conf .= "script-security 3\n";
446 3c11bd3c Matthew Grooms
	$conf .= "daemon\n";
447
	$conf .= "keepalive 10 60\n";
448
	$conf .= "ping-timer-rem\n";
449
	$conf .= "persist-tun\n";
450
	$conf .= "persist-key\n";
451
	$conf .= "proto {$proto}\n";
452
	$conf .= "cipher {$cipher}\n";
453 8d964cea Ermal
	$conf .= "up /usr/local/sbin/ovpn-linkup\n";
454
	$conf .= "down /usr/local/sbin/ovpn-linkdown\n";
455 1492e02c Ermal
	if (file_exists("/usr/local/sbin/openvpn.attributes.sh")) {
456 a1b9105b jim-p
		switch($settings['mode']) {
457
			case 'server_user':
458
			case 'server_tls_user':
459
				$conf .= "client-connect /usr/local/sbin/openvpn.attributes.sh\n";
460
				$conf .= "client-disconnect /usr/local/sbin/openvpn.attributes.sh\n";
461
				break;
462
		}
463 1492e02c Ermal
	}
464 3c11bd3c Matthew Grooms
465 6714bbdc jim-p
	/* Determine the local IP to use - and make sure it matches with the selected protocol. */
466
	if (is_ipaddrv4($iface_ip) && (stristr($settings['protocol'], "6") === false)) {
467
		$conf .= "local {$iface_ip}\n";
468
	} elseif (is_ipaddrv6($iface_ipv6) && (stristr($settings['protocol'], "6") !== false)) {
469
		$conf .= "local {$iface_ipv6}\n";
470 97ffc513 Seth Mos
	}
471 d799787e Matthew Grooms
472 582c58ae jim-p
	if (openvpn_validate_engine($settings['engine']) && ($settings['engine'] != "none"))
473
		$conf .= "engine {$settings['engine']}\n";
474
475 67b0902f pierrepomes
	// server specific settings
476 8dc3ef67 Scott Ullrich
	if ($mode == 'server') {
477 d799787e Matthew Grooms
478 5dc6c910 jim-p
		list($ip, $cidr) = explode('/', $settings['tunnel_network']);
479 97ffc513 Seth Mos
		list($ipv6, $prefix) = explode('/', $settings['tunnel_networkv6']);
480 5dc6c910 jim-p
		$mask = gen_subnet_mask($cidr);
481 8dc3ef67 Scott Ullrich
482 3c11bd3c Matthew Grooms
		// configure tls modes
483
		switch($settings['mode']) {
484
			case 'p2p_tls':
485
			case 'server_tls':
486 e62e2f8b Ermal Lu?i
			case 'server_user':
487 3c11bd3c Matthew Grooms
			case 'server_tls_user':
488 d799787e Matthew Grooms
				$conf .= "tls-server\n";
489 3c11bd3c Matthew Grooms
				break;
490 8dc3ef67 Scott Ullrich
		}
491 d799787e Matthew Grooms
492 3c11bd3c Matthew Grooms
		// configure p2p/server modes
493
		switch($settings['mode']) {
494 6c9cf466 jim-p
			case 'p2p_tls':
495 5dc6c910 jim-p
				// If the CIDR is less than a /30, OpenVPN will complain if you try to
496
				//  use the server directive. It works for a single client without it.
497
				//  See ticket #1417
498 74a556a3 jim-p
				if (!empty($ip) && !empty($mask) && ($cidr < 30)) {
499 5dc6c910 jim-p
					$conf .= "server {$ip} {$mask}\n";
500
					$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
501 a0e3ee98 jim-p
					if(is_ipaddr($ipv6))
502
						$conf .= "server-ipv6 {$ipv6}/{$prefix}\n";
503 5dc6c910 jim-p
				}
504 3c11bd3c Matthew Grooms
			case 'p2p_shared_key':
505 74a556a3 jim-p
				if (!empty($ip) && !empty($mask)) {
506 91c44185 jim-p
					list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
507 459e9333 jim-p
					if ($settings['dev_mode'] == 'tun')
508
						$conf .= "ifconfig {$ip1} {$ip2}\n";
509
					else
510
						$conf .= "ifconfig {$ip1} {$mask}\n";
511 1ab6bdb5 jim-p
				}
512 a0e3ee98 jim-p
				if (!empty($ipv6) && !empty($prefix)) {
513 91c44185 jim-p
					list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix);
514 a0e3ee98 jim-p
					if ($settings['dev_mode'] == 'tun')
515
						$conf .= "ifconfig-ipv6 {$ipv6_1} {$ipv6_2}\n";
516
					else
517 60f501ec Phil Davis
						$conf .= "ifconfig-ipv6 {$ipv6_1} {$prefix}\n";
518 a0e3ee98 jim-p
				}
519 3c11bd3c Matthew Grooms
				break;
520
			case 'server_tls':
521
			case 'server_user':
522
			case 'server_tls_user':
523 74a556a3 jim-p
				if (!empty($ip) && !empty($mask)) {
524 1ab6bdb5 jim-p
					$conf .= "server {$ip} {$mask}\n";
525
					if(is_ipaddr($ipv6))
526
						$conf .= "server-ipv6 {$ipv6}/{$prefix}\n";
527
					$conf .= "client-config-dir {$g['varetc_path']}/openvpn-csc\n";
528
				} else {
529
					if ($settings['serverbridge_dhcp']) {
530
						if ((!empty($settings['serverbridge_interface'])) && (strcmp($settings['serverbridge_interface'], "none"))) {
531
							$biface_ip=get_interface_ip($settings['serverbridge_interface']);
532
							$biface_sm=gen_subnet_mask(get_interface_subnet($settings['serverbridge_interface']));
533
							if (is_ipaddrv4($biface_ip) && is_ipaddrv4($settings['serverbridge_dhcp_start']) && is_ipaddrv4($settings['serverbridge_dhcp_end'])) {
534
								$conf .= "server-bridge {$biface_ip} {$biface_sm} {$settings['serverbridge_dhcp_start']} {$settings['serverbridge_dhcp_end']}\n";
535
							} else {
536
								$conf .= "mode server\n";
537
							}
538
						} else {
539
							$conf .= "mode server\n";
540
						}
541
					}
542
				}
543 3c11bd3c Matthew Grooms
				break;
544 8dc3ef67 Scott Ullrich
		}
545
546 3c11bd3c Matthew Grooms
		// configure user auth modes
547
		switch($settings['mode']) {
548
			case 'server_user':
549
				$conf .= "client-cert-not-required\n";
550
			case 'server_tls_user':
551 9eced774 jim-p
				/* username-as-common-name is not compatible with server-bridge */
552
				if (stristr($conf, "server-bridge") === false)
553
					$conf .= "username-as-common-name\n";
554 8a47c190 Ermal Lu?i
				if (!empty($settings['authmode'])) {
555
					$authcfgs = explode(",", $settings['authmode']);
556
					$sed = "\$authmodes=array(";
557
					$firstsed = 0;
558
					foreach ($authcfgs as $authcfg) {
559
						if ($firstsed > 0)
560
							$sed .= ",";
561
						$firstsed = 1;
562
						$sed .= "\"{$authcfg}\"";
563
					}
564 8901958c jim-p
					$sed .= ");\\\n";
565 53d41b68 Erik Fonnesbeck
					if ($settings['strictusercn'])
566 befad728 Ermal
						$sed .= "\$strictusercn = true;";
567 1bab0df1 jim-p
					$sed .= " \$modeid = \"{$mode_id}\";";
568 8a47c190 Ermal Lu?i
					mwexec("/bin/cat /etc/inc/openvpn.auth-user.php | /usr/bin/sed 's/\/\/<template>/{$sed}/g' >  {$g['varetc_path']}/openvpn/{$mode_id}.php");
569
					mwexec("/bin/chmod a+x {$g['varetc_path']}/openvpn/{$mode_id}.php");
570
					$conf .= "auth-user-pass-verify {$g['varetc_path']}/openvpn/{$mode_id}.php via-env\n";
571 e8a58de4 Ermal Lu?i
				}
572 3c11bd3c Matthew Grooms
				break;
573 8dc3ef67 Scott Ullrich
		}
574 41936acc jim-p
		if (!isset($settings['cert_depth']) && (strstr($settings['mode'], 'tls')))
575
			$settings['cert_depth'] = 1;
576 98963f27 jim-p
		if (is_numeric($settings['cert_depth'])) {
577
			$sed = "";
578
			$cert = lookup_cert($settings['certref']);
579
			$servercn = cert_get_cn($cert['crt']);
580
			$sed .= "\$server_cn = \"{$servercn}\";\\\n";
581
			$sed .= "\$allowed_depth = {$settings['cert_depth']};\\\n";
582
			mwexec("/bin/cat /etc/inc/openvpn.tls-verify.php | /usr/bin/sed 's/\/\/<template>/{$sed}/g' >  {$g['varetc_path']}/openvpn/{$mode_id}.tls-verify.php");
583
			mwexec("/bin/chmod a+x {$g['varetc_path']}/openvpn/{$mode_id}.tls-verify.php");
584
			$conf .= "tls-verify {$g['varetc_path']}/openvpn/{$mode_id}.tls-verify.php\n";
585
		}
586 8dc3ef67 Scott Ullrich
587 63084885 Matthew Grooms
		// The local port to listen on
588 d799787e Matthew Grooms
		$conf .= "lport {$settings['local_port']}\n";
589 c0cf27aa Scott Ullrich
590 63084885 Matthew Grooms
		// The management port to listen on
591 71ca2cb2 Ermal
		// Use unix socket to overcome the problem on any type of server
592
		$conf .= "management {$g['varetc_path']}/openvpn/{$mode_id}.sock unix\n";
593
		//$conf .= "management 127.0.0.1 {$settings['local_port']}\n";
594 63084885 Matthew Grooms
595 3c11bd3c Matthew Grooms
		if ($settings['maxclients'])
596 d799787e Matthew Grooms
			$conf .= "max-clients {$settings['maxclients']}\n";
597
598 3c11bd3c Matthew Grooms
		// Can we push routes
599
		if ($settings['local_network']) {
600 a28d40cb jim-p
			$conf .= openvpn_gen_routes($settings['local_network'], "ipv4", true);
601 3c11bd3c Matthew Grooms
		}
602 787de45a Seth Mos
		if ($settings['local_networkv6']) {
603 a28d40cb jim-p
			$conf .= openvpn_gen_routes($settings['local_networkv6'], "ipv6", true);
604 787de45a Seth Mos
		}
605 3c11bd3c Matthew Grooms
606
		switch($settings['mode']) {
607
			case 'server_tls':
608
			case 'server_user':
609
			case 'server_tls_user':
610 5d8cd81a jim-p
				// Configure client dhcp options
611 3c11bd3c Matthew Grooms
				openvpn_add_dhcpopts($settings, $conf);
612 5d8cd81a jim-p
				if ($settings['client2client'])
613
					$conf .= "client-to-client\n";
614 3c11bd3c Matthew Grooms
				break;
615
		}
616 bca35cff jim-p
		if (isset($settings['duplicate_cn']))
617
			$conf .= "duplicate-cn\n";
618 d799787e Matthew Grooms
	}
619
620 3c11bd3c Matthew Grooms
	// client specific settings
621 d799787e Matthew Grooms
622 3c11bd3c Matthew Grooms
	if ($mode == 'client') {
623 d799787e Matthew Grooms
624 3c11bd3c Matthew Grooms
		// configure p2p mode
625
		switch($settings['mode']) {
626
			case 'p2p_tls':
627
				$conf .= "tls-client\n";
628
			case 'shared_key':
629
				$conf .= "client\n";
630
				break;
631
		}
632 d799787e Matthew Grooms
633 e3924384 jim-p
		// If there is no bind option at all (ip and/or port), add "nobind" directive
634
		//  Otherwise, use the local port if defined, failing that, use lport 0 to 
635
		//  ensure a random source port.
636
		if ((empty($iface_ip)) && (!$settings['local_port']))
637
			$conf .= "nobind\n";
638
		elseif ($settings['local_port'])
639
			$conf .= "lport {$settings['local_port']}\n";
640
		else
641
			$conf .= "lport 0\n";
642 5708241f jim-p
643 4b887ef4 jim-p
		// Use unix socket to overcome the problem on any type of server
644
		$conf .= "management {$g['varetc_path']}/openvpn/{$mode_id}.sock unix\n";
645 48a458d2 pierrepomes
646 3c11bd3c Matthew Grooms
		// The remote server
647
		$conf .= "remote {$settings['server_addr']} {$settings['server_port']}\n";
648
649 d799787e Matthew Grooms
		if (!empty($settings['use_shaper']))
650
			$conf .= "shaper {$settings['use_shaper']}\n";
651 ee506044 Scott Ullrich
652 d799787e Matthew Grooms
		if (!empty($settings['tunnel_network'])) {
653
			list($ip, $mask) = explode('/', $settings['tunnel_network']);
654 8dc3ef67 Scott Ullrich
			$mask = gen_subnet_mask($mask);
655 91c44185 jim-p
			list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
656 459e9333 jim-p
			if ($settings['dev_mode'] == 'tun')
657
				$conf .= "ifconfig {$ip2} {$ip1}\n";
658
			else
659
				$conf .= "ifconfig {$ip2} {$mask}\n";
660 8dc3ef67 Scott Ullrich
		}
661 d799787e Matthew Grooms
662 a0e3ee98 jim-p
		if (!empty($settings['tunnel_networkv6'])) {
663
			list($ipv6, $prefix) = explode('/', $settings['tunnel_networkv6']);
664 91c44185 jim-p
			list($ipv6_1, $ipv6_2) = openvpn_get_interface_ipv6($ipv6, $prefix);
665 a0e3ee98 jim-p
			if ($settings['dev_mode'] == 'tun')
666
				$conf .= "ifconfig-ipv6 {$ipv6_2} {$ipv6_1}\n";
667
			else
668 60f501ec Phil Davis
				$conf .= "ifconfig-ipv6 {$ipv6_2} {$prefix}\n";
669 a0e3ee98 jim-p
		}
670
671 762a24a3 Ermal Lu?i
		if ($settings['proxy_addr']) {
672
			$conf .= "http-proxy {$settings['proxy_addr']} {$settings['proxy_port']}";
673
			if ($settings['proxy_authtype'] != "none") {
674
				$conf .= " {$g['varetc_path']}/openvpn/{$mode_id}.pas {$settings['proxy_authtype']}";
675
				$proxypas = "{$settings['proxy_user']}\n";
676
				$proxypas .= "{$settings['proxy_passwd']}\n";
677
				file_put_contents("{$g['varetc_path']}/openvpn/{$mode_id}.pas", $proxypas);
678
			}
679
			$conf .= " \n";
680
		}
681 8dc3ef67 Scott Ullrich
	}
682
683 17c98ba9 jim-p
	// Add a remote network route if set, and only for p2p modes.
684 54285411 jim-p
	if ((substr($settings['mode'], 0, 3) == "p2p") && (openvpn_validate_cidr($settings['remote_network'], "", true, "ipv4") === FALSE)) {
685 a28d40cb jim-p
		$conf .= openvpn_gen_routes($settings['remote_network'], "ipv4", false);
686 8dc3ef67 Scott Ullrich
	}
687 4856df9b jim-p
	// Add a remote network route if set, and only for p2p modes.
688 54285411 jim-p
	if ((substr($settings['mode'], 0, 3) == "p2p") && (openvpn_validate_cidr($settings['remote_networkv6'], "", true, "ipv6") === FALSE)) {
689 a28d40cb jim-p
		$conf .= openvpn_gen_routes($settings['remote_networkv6'], "ipv6", false);
690 4856df9b jim-p
	}
691 afb07cf1 Scott Ullrich
692 d799787e Matthew Grooms
	// Write the settings for the keys
693 3c11bd3c Matthew Grooms
	switch($settings['mode']) {
694
		case 'p2p_shared_key':
695
			openvpn_add_keyfile($settings['shared_key'], $conf, $mode_id, "secret");
696
			break;
697
		case 'p2p_tls':
698
		case 'server_tls':
699
		case 'server_tls_user':
700 e62e2f8b Ermal Lu?i
		case 'server_user':
701 3c11bd3c Matthew Grooms
			$ca = lookup_ca($settings['caref']);
702
			openvpn_add_keyfile($ca['crt'], $conf, $mode_id, "ca");
703
			$cert = lookup_cert($settings['certref']);
704
			openvpn_add_keyfile($cert['crt'], $conf, $mode_id, "cert");
705
			openvpn_add_keyfile($cert['prv'], $conf, $mode_id, "key");
706
			if ($mode == 'server')
707 fe787fc7 Matthew Grooms
				$conf .= "dh {$g['etc_path']}/dh-parameters.{$settings['dh_length']}\n";
708 6db02381 jim-p
			if (!empty($settings['crlref'])) {
709
				$crl = lookup_crl($settings['crlref']);
710 cfcc6994 jim-p
				crl_update($crl);
711 6db02381 jim-p
				openvpn_add_keyfile($crl['text'], $conf, $mode_id, "crl-verify");
712
			}
713 db746ce2 Ermal Lu?i
			if ($settings['tls']) {
714 756720e2 Pierre POMES
				if ($mode == "server") 
715 db746ce2 Ermal Lu?i
					$tlsopt = 0;
716
				else
717
					$tlsopt = 1;
718
				openvpn_add_keyfile($settings['tls'], $conf, $mode_id, "tls-auth", $tlsopt);
719
			}
720 3c11bd3c Matthew Grooms
			break;
721 8dc3ef67 Scott Ullrich
	}
722
723 1cb0b40a Matthew Grooms
	if ($settings['compression'])
724 d799787e Matthew Grooms
		$conf .= "comp-lzo\n";
725
726
	if ($settings['passtos'])
727
		$conf .= "passtos\n";
728
729
	if ($settings['resolve_retry'])
730
		$conf .= "resolv-retry infinite\n";
731
732
	if ($settings['dynamic_ip']) {
733
		$conf .= "persist-remote-ip\n";
734
		$conf .= "float\n";
735 8dc3ef67 Scott Ullrich
	}
736 afb07cf1 Scott Ullrich
737 ee55ce7d jim-p
	if ($settings['topology_subnet']) {
738
		$conf .= "topology subnet\n";
739
	}
740
741 d799787e Matthew Grooms
	openvpn_add_custom($settings, $conf);
742
743 a8f538a8 jim-p
	openvpn_create_dirs();
744 938fc5b0 Ermal
	$fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.conf";
745 d799787e Matthew Grooms
	file_put_contents($fpath, $conf);
746 938fc5b0 Ermal
	unset($conf);
747 be00850b Phil Davis
	$fpath = "{$g['varetc_path']}/openvpn/{$mode_id}.interface";
748
	file_put_contents($fpath, $interface);
749 f9ac3784 Ermal Lu?i
	//chown($fpath, 'nobody');
750
	//chgrp($fpath, 'nobody');
751 6f27412f Ermal Lu?i
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
752 be00850b Phil Davis
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.interface", 0600);
753 6f27412f Ermal Lu?i
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.key", 0600);
754
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.tls-auth", 0600);
755
	@chmod("{$g['varetc_path']}/openvpn/{$mode_id}.conf", 0600);
756 d799787e Matthew Grooms
}
757
758 fc05822b jim-p
function openvpn_restart($mode, $settings) {
759 d799787e Matthew Grooms
	global $g, $config;
760
761
	$vpnid = $settings['vpnid'];
762
	$mode_id = $mode.$vpnid;
763
764 76369bfc Matthew Grooms
	/* kill the process if running */
765 705c8ec9 Matthew Grooms
	$pfile = $g['varrun_path']."/openvpn_{$mode_id}.pid";
766 76369bfc Matthew Grooms
	if (file_exists($pfile)) {
767 705c8ec9 Matthew Grooms
768 76369bfc Matthew Grooms
		/* read the pid file */
769
		$pid = rtrim(file_get_contents($pfile));
770
		unlink($pfile);
771 705c8ec9 Matthew Grooms
772 76369bfc Matthew Grooms
		/* send a term signal to the process */
773
		posix_kill($pid, SIGTERM);
774
775
		/* wait until the process exits */
776
		while(posix_kill($pid, 0))
777
			usleep(250000);
778
	}
779 d799787e Matthew Grooms
780 a1cab2c7 Ermal
	if (isset($settings['disable']))
781 d799787e Matthew Grooms
		return;
782
783 260f267e jim-p
	/* Do not start a client if we are a CARP backup on this vip! */
784
	if (($mode == "client") && strstr($settings['interface'], "_vip") && (get_carp_interface_status($settings['interface']) == "BACKUP"))
785 9ea0cb90 jim-p
		return;
786
787 705c8ec9 Matthew Grooms
	/* start the new process */
788 d799787e Matthew Grooms
	$fpath = $g['varetc_path']."/openvpn/{$mode_id}.conf";
789 91c44185 jim-p
	openvpn_clear_route($mode, $settings);
790 5a7cc1f9 Ermal
	mwexec_bg("/usr/local/sbin/openvpn --config {$fpath}");
791 847cd48d Ermal
792
	if (!$g['booting'])
793
		send_event("filter reload");
794 afb07cf1 Scott Ullrich
}
795
796 dc408939 Matthew Grooms
function openvpn_delete($mode, & $settings) {
797 d799787e Matthew Grooms
	global $g, $config;
798
799
	$vpnid = $settings['vpnid'];
800
	$mode_id = $mode.$vpnid;
801
802 da601f8e PiBa-NL
	if (isset($settings['dev_mode']))
803
		$tunname = "{$settings['dev_mode']}{$vpnid}";
804
	else {  /* defaults to tun */
805
		$tunname = "tun{$vpnid}";
806
	}
807
808 095a95ae Matthew Grooms
	if ($mode == "server")
809
		$devname = "ovpns{$vpnid}";
810
	else
811
		$devname = "ovpnc{$vpnid}";
812 dc408939 Matthew Grooms
813 76369bfc Matthew Grooms
	/* kill the process if running */
814 dc408939 Matthew Grooms
	$pfile = "{$g['varrun_path']}/openvpn_{$mode_id}.pid";
815 76369bfc Matthew Grooms
	if (file_exists($pfile)) {
816 dc408939 Matthew Grooms
817 76369bfc Matthew Grooms
		/* read the pid file */
818
		$pid = trim(file_get_contents($pfile));
819
		unlink($pfile);
820
821
		/* send a term signal to the process */
822
		posix_kill($pid, SIGTERM);
823
	}
824 705c8ec9 Matthew Grooms
825 095a95ae Matthew Grooms
	/* remove the device from the openvpn group */
826
	mwexec("/sbin/ifconfig {$devname} -group openvpn");
827
828 dc408939 Matthew Grooms
	/* restore the original adapter name */
829
	mwexec("/sbin/ifconfig {$devname} name {$tunname}");
830
831
	/* remove the configuration files */
832
	mwexec("/bin/rm {$g['varetc_path']}/openvpn/{$mode_id}.*");
833 d799787e Matthew Grooms
}
834 afb07cf1 Scott Ullrich
835 dc408939 Matthew Grooms
function openvpn_resync_csc(& $settings) {
836 8dc3ef67 Scott Ullrich
	global $g, $config;
837
838 ea28182c Matthew Grooms
	$fpath = $g['varetc_path']."/openvpn-csc/".$settings['common_name'];
839 8dc3ef67 Scott Ullrich
840 a1cab2c7 Ermal
	if (isset($settings['disable'])) {
841 d799787e Matthew Grooms
		unlink_if_exists($fpath);
842 c876662c Scott Ullrich
		return;
843
	}
844 a8f538a8 jim-p
	openvpn_create_dirs();
845 d799787e Matthew Grooms
846 8dc3ef67 Scott Ullrich
	$conf = '';
847 d799787e Matthew Grooms
	if ($settings['block'])
848
		$conf .= "disable\n";
849
850
	if ($settings['push_reset'])
851
		$conf .= "push-reset\n";
852
853
	if (!empty($settings['tunnel_network'])) {
854
		list($ip, $mask) = explode('/', $settings['tunnel_network']);
855 96033063 Erik Fonnesbeck
		$baselong = ip2long32($ip) & gen_subnet_mask_long($mask);
856 298fe5ae jim-p
		$serverip = long2ip32($baselong + 1);
857
		$clientip = long2ip32($baselong + 2);
858
		/* Because this is being pushed, the order from the client's point of view. */
859 d9c96fb1 jim-p
		if ($settings['dev_mode'] != 'tap')
860
			$conf .= "ifconfig-push {$clientip} {$serverip}\n";
861 e052047d jim-p
		else
862
			$conf .= "ifconfig-push {$clientip} {$mask}\n";
863 8dc3ef67 Scott Ullrich
	}
864 6d031071 Martin Fuchs
865 d799787e Matthew Grooms
	openvpn_add_dhcpopts($settings, $conf);
866 8dc3ef67 Scott Ullrich
867 d799787e Matthew Grooms
	if ($settings['gwredir'])
868
		$conf .= "push \"redirect-gateway def1\"\n";
869 6d031071 Martin Fuchs
870 d799787e Matthew Grooms
	openvpn_add_custom($settings, $conf);
871 8dc3ef67 Scott Ullrich
872 d799787e Matthew Grooms
	file_put_contents($fpath, $conf);
873
	chown($fpath, 'nobody');
874
	chgrp($fpath, 'nobody');
875
}
876 8dc3ef67 Scott Ullrich
877 dc408939 Matthew Grooms
function openvpn_delete_csc(& $settings) {
878 add2e3f7 Scott Ullrich
	global $g, $config;
879 3c2e5528 Scott Ullrich
880 ea28182c Matthew Grooms
	$fpath = $g['varetc_path']."/openvpn-csc/".$settings['common_name'];
881 d799787e Matthew Grooms
	unlink_if_exists($fpath);
882 267ab13f Ermal Luçi
}
883 afb07cf1 Scott Ullrich
884 24012690 Scott Ullrich
// Resync the configuration and restart the VPN
885 fc05822b jim-p
function openvpn_resync($mode, $settings) {
886 dc408939 Matthew Grooms
	openvpn_reconfigure($mode, $settings);
887
	openvpn_restart($mode, $settings);
888 afb07cf1 Scott Ullrich
}
889
890 add2e3f7 Scott Ullrich
// Resync and restart all VPNs
891 c7f60193 Ermal
function openvpn_resync_all($interface = "") {
892 d799787e Matthew Grooms
	global $g, $config;
893 267ab13f Ermal Luçi
894 7734aea6 Andrew Thompson
	if ($g['platform'] == 'jail')
895
		return;
896 a8f538a8 jim-p
	openvpn_create_dirs();
897 3cb54b54 Matthew Grooms
898 34bc1324 Matthew Grooms
	if (!is_array($config['openvpn']))
899
		$config['openvpn'] = array();
900
901 15b414e6 Matthew Grooms
/*
902 34bc1324 Matthew Grooms
	if (!$config['openvpn']['dh-parameters']) {
903
		echo "Configuring OpenVPN Parameters ...\n";
904 035e4289 Matthew Grooms
		$dh_parameters = openvpn_create_dhparams(1024);
905 34bc1324 Matthew Grooms
		$dh_parameters = base64_encode($dh_parameters);
906
		$config['openvpn']['dh-parameters'] = $dh_parameters;
907 c67dd94e Bill Marquette
		write_config("OpenVPN DH parameters");
908 34bc1324 Matthew Grooms
	}
909
910
	$path_ovdh = $g['varetc_path']."/openvpn/dh-parameters";
911
	if (!file_exists($path_ovdh)) {
912
		$dh_parameters = $config['openvpn']['dh-parameters'];
913
		$dh_parameters = base64_decode($dh_parameters);
914
		file_put_contents($path_ovdh, $dh_parameters);
915
	}
916 15b414e6 Matthew Grooms
*/
917 739c9efd Ermal
	if ($interface <> "")
918 a82e6d37 Chris Buechler
		log_error("Resyncing OpenVPN instances for interface " . convert_friendly_interface_to_friendly_descr($interface) . ".");
919 739c9efd Ermal
	else
920 a82e6d37 Chris Buechler
		log_error("Resyncing OpenVPN instances."); 
921 34bc1324 Matthew Grooms
922 c7f60193 Ermal
	if (is_array($config['openvpn']['openvpn-server'])) {
923
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
924 739c9efd Ermal
			if ($interface <> "" && $interface != $settings['interface'])
925 c7f60193 Ermal
				continue;
926 dc408939 Matthew Grooms
			openvpn_resync('server', $settings);
927 c7f60193 Ermal
		}
928
	}
929 5b237745 Scott Ullrich
930 c7f60193 Ermal
	if (is_array($config['openvpn']['openvpn-client'])) {
931
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
932 739c9efd Ermal
			if ($interface <> "" && $interface != $settings['interface'])
933 c7f60193 Ermal
				continue;
934 dc408939 Matthew Grooms
			openvpn_resync('client', $settings);
935 c7f60193 Ermal
		}
936
	}
937 afb07cf1 Scott Ullrich
938 d799787e Matthew Grooms
	if (is_array($config['openvpn']['openvpn-csc']))
939 dc408939 Matthew Grooms
		foreach ($config['openvpn']['openvpn-csc'] as & $settings)
940
			openvpn_resync_csc($settings);
941 afb07cf1 Scott Ullrich
942 5b237745 Scott Ullrich
}
943 702a4702 Scott Ullrich
944 99cc103b Phil Davis
// Resync and restart all VPNs using a gateway group.
945
function openvpn_resync_gwgroup($gwgroupname = "") {
946
	global $g, $config;
947
948
	if ($gwgroupname <> "") {
949
		if (is_array($config['openvpn']['openvpn-server'])) {
950
			foreach ($config['openvpn']['openvpn-server'] as & $settings) {
951
				if ($gwgroupname == $settings['interface']) {
952
					log_error("Resyncing OpenVPN for gateway group " . $gwgroupname . " server " . $settings["description"] . ".");
953
					openvpn_resync('server', $settings);
954
				}
955
			}
956
		}
957
958
		if (is_array($config['openvpn']['openvpn-client'])) {
959
			foreach ($config['openvpn']['openvpn-client'] as & $settings) {
960
				if ($gwgroupname == $settings['interface']) {
961
					log_error("Resyncing OpenVPN for gateway group " . $gwgroupname . " client " . $settings["description"] . ".");
962
					openvpn_resync('client', $settings);
963
				}
964
			}
965
		}
966
967
		// Note: no need to resysnc Client Specific (csc) here, as changes to the OpenVPN real interface do not effect these.
968
969
	} else
970
		log_error("openvpn_resync_gwgroup called with null gwgroup parameter."); 
971
}
972
973 453d9c96 jim-p
function openvpn_get_active_servers($type="multipoint") {
974 71ca2cb2 Ermal
	global $config, $g;
975
976 53663f57 jim-p
	$servers = array();
977
	if (is_array($config['openvpn']['openvpn-server'])) {
978
		foreach ($config['openvpn']['openvpn-server'] as & $settings) {
979 6b2dcac5 Ermal
			if (empty($settings) || isset($settings['disable']))
980
				continue;
981
982 53663f57 jim-p
			$prot = $settings['protocol'];
983
			$port = $settings['local_port'];
984
	
985
			$server = array();
986 95305736 jim-p
			$server['port'] = ($settings['local_port']) ? $settings['local_port'] : 1194;
987 41be629f jim-p
			$server['mode'] = $settings['mode'];
988 53663f57 jim-p
			if ($settings['description'])
989
				$server['name'] = "{$settings['description']} {$prot}:{$port}";
990
			else
991
				$server['name'] = "Server {$prot}:{$port}";
992
			$server['conns'] = array();
993 2eaa97b9 jim-p
			$server['vpnid'] = $settings['vpnid'];
994
			$server['mgmt'] = "server{$server['vpnid']}";
995
			$socket = "unix://{$g['varetc_path']}/openvpn/{$server['mgmt']}.sock";
996 453d9c96 jim-p
			list($tn, $sm) = explode('/', $settings['tunnel_network']);
997
998
			if ((($server['mode'] == "p2p_shared_key") || ($sm >= 30) ) && ($type == "p2p"))
999 95305736 jim-p
				$servers[] = openvpn_get_client_status($server, $socket);
1000 453d9c96 jim-p
			elseif (($server['mode'] != "p2p_shared_key") && ($type == "multipoint") && ($sm < 30))
1001 95305736 jim-p
				$servers[] = openvpn_get_server_status($server, $socket);
1002 453d9c96 jim-p
1003 95305736 jim-p
		}
1004
	}
1005
	return $servers;
1006
}
1007 b0140675 Ermal
1008 95305736 jim-p
function openvpn_get_server_status($server, $socket) {
1009
	$errval;
1010
	$errstr;
1011
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1012
	if ($fp) {
1013
		stream_set_timeout($fp, 1);
1014
1015
		/* send our status request */
1016
		fputs($fp, "status 2\n");
1017
1018
		/* recv all response lines */
1019
		while (!feof($fp)) {
1020
1021
			/* read the next line */
1022
			$line = fgets($fp, 1024);
1023
1024
			$info = stream_get_meta_data($fp);
1025
			if ($info['timed_out'])
1026
				break;
1027
1028
			/* parse header list line */
1029
			if (strstr($line, "HEADER"))
1030
				continue;
1031
1032
			/* parse end of output line */
1033
			if (strstr($line, "END") || strstr($line, "ERROR"))
1034
				break;
1035
1036
			/* parse client list line */
1037
			if (strstr($line, "CLIENT_LIST")) {
1038
				$list = explode(",", $line);
1039 53663f57 jim-p
				$conn = array();
1040 95305736 jim-p
				$conn['common_name'] = $list[1];
1041
				$conn['remote_host'] = $list[2];
1042
				$conn['virtual_addr'] = $list[3];
1043
				$conn['bytes_recv'] = $list[4];
1044
				$conn['bytes_sent'] = $list[5];
1045
				$conn['connect_time'] = $list[6];
1046 53663f57 jim-p
				$server['conns'][] = $conn;
1047
			}
1048 ec970b50 jim-p
			/* parse routing table lines */
1049
			if (strstr($line, "ROUTING_TABLE")) {
1050
				$list = explode(",", $line);
1051
				$conn = array();
1052
				$conn['virtual_addr'] = $list[1];
1053
				$conn['common_name'] = $list[2];
1054
				$conn['remote_host'] = $list[3];
1055
				$conn['last_time'] = $list[4];
1056
				$server['routes'][] = $conn;
1057
			}
1058 53663f57 jim-p
		}
1059 95305736 jim-p
1060
		/* cleanup */
1061
		fclose($fp);
1062
	} else {
1063
		$conn = array();
1064
		$conn['common_name'] = "[error]";
1065 2eaa97b9 jim-p
		$conn['remote_host'] = "Unable to contact daemon";
1066
		$conn['virtual_addr'] = "Service not running?";
1067 95305736 jim-p
		$conn['bytes_recv'] = 0;
1068
		$conn['bytes_sent'] = 0;
1069
		$conn['connect_time'] = 0;
1070
		$server['conns'][] = $conn;
1071 53663f57 jim-p
	}
1072 95305736 jim-p
	return $server;
1073 53663f57 jim-p
}
1074
1075
function openvpn_get_active_clients() {
1076 71ca2cb2 Ermal
	global $config, $g;
1077
1078 53663f57 jim-p
	$clients = array();
1079
	if (is_array($config['openvpn']['openvpn-client'])) {
1080
		foreach ($config['openvpn']['openvpn-client'] as & $settings) {
1081
	
1082 6b2dcac5 Ermal
			if (empty($settings) || isset($settings['disable']))
1083
				continue;
1084
1085 53663f57 jim-p
			$prot = $settings['protocol'];
1086 95305736 jim-p
			$port = ($settings['local_port']) ? ":{$settings['local_port']}" : "";
1087 53663f57 jim-p
	
1088
			$client = array();
1089
			$client['port'] = $settings['local_port'];
1090
			if ($settings['description'])
1091 95305736 jim-p
				$client['name'] = "{$settings['description']} {$prot}{$port}";
1092 53663f57 jim-p
			else
1093 95305736 jim-p
				$client['name'] = "Client {$prot}{$port}";
1094 53663f57 jim-p
	
1095 2eaa97b9 jim-p
			$client['vpnid'] = $settings['vpnid'];
1096
			$client['mgmt'] = "client{$client['vpnid']}";
1097
			$socket = "unix://{$g['varetc_path']}/openvpn/{$client['mgmt']}.sock";
1098 53663f57 jim-p
			$client['status']="down";
1099 95305736 jim-p
1100
			$clients[] = openvpn_get_client_status($client, $socket);
1101
		}
1102
	}
1103
	return $clients;
1104
}
1105
1106
function openvpn_get_client_status($client, $socket) {
1107
	$errval;
1108
	$errstr;
1109
	$fp = @stream_socket_client($socket, $errval, $errstr, 1);
1110
	if ($fp) {
1111
		stream_set_timeout($fp, 1);
1112
		/* send our status request */
1113
		fputs($fp, "state 1\n");
1114
1115
		/* recv all response lines */
1116
		while (!feof($fp)) {
1117
			/* read the next line */
1118
			$line = fgets($fp, 1024);
1119
1120
			$info = stream_get_meta_data($fp);
1121
			if ($info['timed_out'])
1122
				break;
1123
1124
			/* Get the client state */
1125
			if (strstr($line,"CONNECTED")) {
1126
				$client['status']="up";
1127
				$list = explode(",", $line);
1128
1129
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1130
				$client['virtual_addr']  = $list[3];
1131
				$client['remote_host'] = $list[4];
1132
			}
1133 453d9c96 jim-p
			if (strstr($line,"CONNECTING")) {
1134
				$client['status']="connecting";
1135
			}
1136
			if (strstr($line,"ASSIGN_IP")) {
1137
				$client['status']="waiting";
1138
				$list = explode(",", $line);
1139
1140
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1141
				$client['virtual_addr']  = $list[3];
1142
			}
1143
			if (strstr($line,"RECONNECTING")) {
1144
				$client['status']="reconnecting";
1145
				$list = explode(",", $line);
1146
1147
				$client['connect_time']  = date("D M j G:i:s Y", $list[0]);
1148
				$client['status'] .= "; " . $list[2];
1149
			}
1150 95305736 jim-p
			/* parse end of output line */
1151
			if (strstr($line, "END") || strstr($line, "ERROR"))
1152
				break;
1153
		}
1154
1155
		/* If up, get read/write stats */
1156
		if (strcmp($client['status'], "up") == 0) {
1157
			fputs($fp, "status 2\n");
1158
			/* recv all response lines */
1159
			while (!feof($fp)) {
1160
				/* read the next line */
1161
				$line = fgets($fp, 1024);
1162
1163
				$info = stream_get_meta_data($fp);
1164
				if ($info['timed_out'])
1165
					break;
1166
1167
				if (strstr($line,"TCP/UDP read bytes")) {
1168
					$list = explode(",", $line);
1169
					$client['bytes_recv'] = $list[1];
1170 53663f57 jim-p
				}
1171 95305736 jim-p
1172
				if (strstr($line,"TCP/UDP write bytes")) {
1173
					$list = explode(",", $line);
1174
					$client['bytes_sent'] = $list[1];
1175 53663f57 jim-p
				}
1176 95305736 jim-p
1177
				/* parse end of output line */
1178
				if (strstr($line, "END"))
1179
					break;
1180 53663f57 jim-p
			}
1181
		}
1182 95305736 jim-p
1183
		fclose($fp);
1184
1185
	} else {
1186
		$DisplayNote=true;
1187 2eaa97b9 jim-p
		$client['remote_host'] = "Unable to contact daemon";
1188
		$client['virtual_addr'] = "Service not running?";
1189 95305736 jim-p
		$client['bytes_recv'] = 0;
1190
		$client['bytes_sent'] = 0;
1191
		$client['connect_time'] = 0;
1192 53663f57 jim-p
	}
1193 95305736 jim-p
	return $client;
1194 53663f57 jim-p
}
1195 8e022a76 jim-p
1196
function openvpn_refresh_crls() {
1197
	global $g, $config;
1198
1199 a8f538a8 jim-p
	openvpn_create_dirs();
1200 8e022a76 jim-p
1201
	if (is_array($config['openvpn']['openvpn-server'])) {
1202
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1203
			if (empty($settings))
1204
				continue;
1205
			if (isset($settings['disable']))
1206
				continue;
1207
			// Write the settings for the keys
1208
			switch($settings['mode']) {
1209
				case 'p2p_tls':
1210
				case 'server_tls':
1211
				case 'server_tls_user':
1212
				case 'server_user':
1213
					if (!empty($settings['crlref'])) {
1214
						$crl = lookup_crl($settings['crlref']);
1215 728003c8 jim-p
						crl_update($crl);
1216 8e022a76 jim-p
						$fpath = $g['varetc_path']."/openvpn/server{$settings['vpnid']}.crl-verify";
1217
						file_put_contents($fpath, base64_decode($crl['text']));
1218
						@chmod($fpath, 0644);
1219
					}
1220
					break;
1221
			}
1222
		}
1223
	}
1224
}
1225
1226 a8f538a8 jim-p
function openvpn_create_dirs() {
1227
	global $g;
1228
	if (!is_dir("{$g['varetc_path']}/openvpn"))
1229
		safe_mkdir("{$g['varetc_path']}/openvpn", 0750);
1230
	if (!is_dir("{$g['varetc_path']}/openvpn-csc"))
1231
		safe_mkdir("{$g['varetc_path']}/openvpn-csc", 0750);
1232
}
1233
1234 91c44185 jim-p
function openvpn_get_interface_ip($ip, $mask) {
1235
	$baselong = ip2long32($ip) & ip2long($mask);
1236
	$ip1 = long2ip32($baselong + 1);
1237
	$ip2 = long2ip32($baselong + 2);
1238
	return array($ip1, $ip2);
1239
}
1240
1241
function openvpn_get_interface_ipv6($ipv6, $prefix) {
1242
	$basev6 = gen_subnetv6($ipv6, $prefix);
1243
	// Is there a better way to do this math?
1244
	$ipv6_arr = explode(':', $basev6);
1245
	$last = hexdec(array_pop($ipv6_arr));
1246 fe9c774d Phil Davis
	$ipv6_1 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 1)));
1247
	$ipv6_2 = Net_IPv6::compress(Net_IPv6::uncompress(implode(':', $ipv6_arr) . ':' . dechex($last + 2)));
1248 91c44185 jim-p
	return array($ipv6_1, $ipv6_2);
1249
}
1250
1251
function openvpn_clear_route($mode, $settings) {
1252
	if (empty($settings['tunnel_network']))
1253
		return;
1254
	list($ip, $cidr) = explode('/', $settings['tunnel_network']);
1255
	$mask = gen_subnet_mask($cidr);
1256 6ca938cf jim-p
	$clear_route = false;
1257
1258 91c44185 jim-p
	switch($settings['mode']) {
1259 6ca938cf jim-p
		case 'shared_key':
1260
			$clear_route = true;
1261
			break;
1262 91c44185 jim-p
		case 'p2p_tls':
1263
		case 'p2p_shared_key':
1264 6d0b9fe9 jim-p
			if ($cidr == 30)
1265 6ca938cf jim-p
				$clear_route = true;
1266 91c44185 jim-p
			break;
1267
	}
1268 6ca938cf jim-p
1269 6d0b9fe9 jim-p
	if ($clear_route && !empty($ip) && !empty($mask)) {
1270 6ca938cf jim-p
		list($ip1, $ip2) = openvpn_get_interface_ip($ip, $mask);
1271
		$ip_to_clear = ($mode == "server") ? $ip1 : $ip2;
1272 615d7f0a Ermal
		/* XXX: Family for route? */
1273 6ca938cf jim-p
		mwexec("/sbin/route -q delete {$ip_to_clear}");
1274
	}
1275 91c44185 jim-p
}
1276
1277 a28d40cb jim-p
function openvpn_gen_routes($value, $ipproto = "ipv4", $push = false) {
1278
	$routes = "";
1279
	if (empty($value))
1280
		return "";
1281
	$networks = explode(',', $value);
1282
1283
	foreach ($networks as $network) {
1284
		if ($ipproto == "ipv4")
1285
			$route = openvpn_gen_route_ipv4($network);
1286
		else
1287
			$route = openvpn_gen_route_ipv6($network);
1288
1289
		if ($push)
1290
			$routes .= "push \"{$route}\"\n";
1291
		else
1292
			$routes .= "{$route}\n";
1293
	}
1294
	return $routes;
1295
}
1296
1297
function openvpn_gen_route_ipv4($network) {
1298
	list($ip, $mask) = explode('/', trim($network));
1299
	$mask = gen_subnet_mask($mask);
1300
	return "route $ip $mask";
1301
}
1302
1303
function openvpn_gen_route_ipv6($network) {
1304
	list($ipv6, $prefix) = explode('/', trim($network));
1305
	if (empty($prefix))
1306
		$prefix = "128";
1307
	return "route-ipv6 ${ipv6}/${prefix}";
1308
}
1309
1310 699125b1 jim-p
function openvpn_get_settings($mode, $vpnid) {
1311
	global $config;
1312
1313
	if (is_array($config['openvpn']['openvpn-server'])) {
1314
		foreach ($config['openvpn']['openvpn-server'] as $settings) {
1315
			if (isset($settings['disable']))
1316
				continue;
1317
1318
			if ($vpnid != 0 && $vpnid == $settings['vpnid'])
1319
				return $settings;
1320
		}
1321
	}
1322
1323
	if (is_array($config['openvpn']['openvpn-client'])) {
1324
		foreach ($config['openvpn']['openvpn-client'] as $settings) {
1325
			if (isset($settings['disable']))
1326
				continue;
1327
1328
			if ($vpnid != 0 && $vpnid == $settings['vpnid'])
1329
				return $settings;
1330
		}
1331
	}
1332
1333
	return array();
1334
}
1335
1336
function openvpn_restart_by_vpnid($mode, $vpnid) {
1337
	$settings = openvpn_get_settings($mode, $vpnid);
1338
	openvpn_restart($mode, $settings);
1339
}
1340
1341 756720e2 Pierre POMES
?>