Project

General

Profile

Download (12.2 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
require_once('config.inc');
3
require_once('util.inc');
4

    
5

    
6
// Return the list of ciphers OpenVPN supports
7
function openvpn_get_ciphers($pkg) {
8
		foreach ($pkg['fields']['field'] as $i => $field) {
9
			if ($field['fieldname'] == 'crypto') break;
10
		}
11
		$option_array = &$pkg['fields']['field'][$i]['options']['option'];
12
		$ciphers_out = shell_exec('openvpn --show-ciphers | grep "default key" | awk \'{print $1, "(" $2 "-" $3 ")";}\'');
13
		$ciphers = explode("\n", trim($ciphers_out));
14
		sort($ciphers);
15
		foreach ($ciphers as $cipher) {
16
			$value = explode(' ', $cipher);
17
			$value = $value[0];
18
			$option_array[] = array('value' => $value, 'name' => $cipher);
19
		}
20
}
21

    
22

    
23
function openvpn_validate_port($value, $name) {
24
	$value = trim($value);
25
	if (!empty($value) && !(is_numeric($value) && ($value > 0) && ($value < 65535)))
26
		return "The field '$name' must contain a valid port, ranging from 0 to 65535.";
27
	return false;
28
}
29

    
30

    
31
function openvpn_validate_cidr($value, $name) {
32
	$value = trim($value);
33
	if (!empty($value)) {
34
		list($ip, $mask) = explode('/', $value);
35
		if (!is_ipaddr($ip) or !is_numeric($mask) or ($mask > 32) or ($mask < 0))
36
			return "The field '$name' must contain a valid CIDR range.";
37
	}
38
	return false;
39
}
40

    
41

    
42
// Do the input validation
43
function openvpn_validate_input($mode, $post, $input_errors) {
44
	$Mode = ucfirst($mode);
45

    
46
	if ($mode == 'server') {
47
		if ($result = openvpn_validate_port($post['local_port'], 'Local port'))
48
			$input_errors[] = $result;
49

    
50
		if ($result = openvpn_validate_cidr($post['addresspool'], 'Address pool'))
51
			$input_errors[] = $result;
52

    
53
		if ($result = openvpn_validate_cidr($post['local_network'], 'Local network'))
54
			$input_errors[] = $result;
55
	}
56

    
57
	else { // Client mode
58
		if ($result = openvpn_validate_port($post['serverport'], 'Server port'))
59
			$input_errors[] = $result;
60

    
61
		$server_addr = trim($post['serveraddr']);
62
		if (!empty($value) && !(is_domain($server_addr) || is_ipaddr($server_addr)))
63
			$input_errors[] = 'The field \'Server address\' must contain a valid IP address or domain name.';
64

    
65
		if ($result = openvpn_validate_cidr($post['interface_ip'], 'Interface IP'))
66
			$input_errors[] = $result;
67

    
68
		if ($post['auth_method'] == 'shared_key') {
69
			if (empty($post['interface_ip']))
70
				$input_errors[] = 'The field \'Interface IP\' is required.';
71
		}
72
		if (isset($post['proxy_hostname']) && $post['proxy_hostname'] != "") {
73
			if (!is_domain($post['proxy_hostname']) || is_ipaddr($post['proxy_hostname']))
74
				$input_errors[] = 'The field \'Proxy Host\' must contain a valid IP address or domain name.';
75
			if (!is_port($post['proxy_port']))
76
				$input_errors[] = 'The field \'Proxy port\' must contain a valid port number.';
77
			if ($post['protocol'] != "TCP") 
78
				$input_errors[] = 'The protocol must be TCP to use a HTTP proxy server.';
79
		}
80
				
81
	}
82

    
83
	if ($result = openvpn_validate_cidr($post['remote_network'], 'Remote network'))
84
		$input_errors[] = $result;
85

    
86
	if ($_POST['auth_method'] == 'shared_key') {
87
		$reqfields[] = 'shared_key';
88
		$reqfieldsn[] = 'Shared key';
89
	}
90
	else {
91
		$req = explode(' ', "ca_cert {$mode}_cert {$mode}_key");
92
		$reqn = array(	'CA certificate',
93
				ucfirst($mode) . ' certificate',
94
				ucfirst($mode) . ' key');
95
		$reqfields = array_merge($reqfields, $req);
96
		$reqfieldsn = array_merge($reqfieldsn, $reqn);
97
		if ($mode == 'server') {
98
			$reqfields[] = 'dh_params';
99
			$reqfieldsn[] = 'DH parameters';
100
		}
101
	}
102
	do_input_validation($post, $reqfields, $reqfieldsn, &$input_errors);
103

    
104
	$value = trim($post['shared_key']);
105
	$items = array();
106
	if ($_POST['auth_method'] == 'shared_key') {
107
		$items[] = array(	'field' => 'shared_key',
108
					'string' => 'OpenVPN Static key V1',
109
					'name' => 'Shared key');
110
	}
111
	else {
112
		$items[] = array(	'field' => 'ca_cert',
113
					'string' => 'CERTIFICATE',
114
					'name' => 'CA certificate');
115
		$items[] = array(	'field' => "{$mode}_cert",
116
					'string' => 'CERTIFICATE',
117
					'name' => "$Mode certificate");
118
		$items[] = array(	'field' => "{$mode}_key",
119
					'string' => 'RSA PRIVATE KEY',
120
					'name' => "$Mode key");
121
		if ($mode == 'server') {
122
			$items[] = array(	'field' => 'dh_params',
123
						'string' => 'DH PARAMETERS',
124
						'name' => 'DH parameters');
125
			$items[] = array(	'field' => 'crl',
126
						'string' => 'X509 CRL',
127
						'name' => 'CRL');
128
		}
129
	}
130
	foreach ($items as $item) {
131
		$value = trim($_POST[$item['field']]);
132
		$string = $item['string'];
133
		if ($value && (!strstr($value, "-----BEGIN {$string}-----") || !strstr($value, "-----END {$string}-----")))
134
			$input_errors[] = "The field '{$item['name']}' does not appear to be valid";
135
	}
136
}
137

    
138

    
139
function openvpn_validate_input_csc($post, $input_errors) {
140
	if ($result = openvpn_validate_cidr($post['ifconfig_push'], 'Interface IP'))
141
		$input_errors[] = $result;
142
}
143

    
144

    
145
// Rewrite the settings
146
function openvpn_reconfigure($mode, $id) {
147
	global $g, $config;
148

    
149
	$settings = $config['installedpackages']["openvpn$mode"]['config'][$id];
150
	if ($settings['disable']) return;
151

    
152
	// Set the keys up
153
	// Note that the keys' extension is also the directive that goes to the config file
154
	$base_file = $g['varetc_path'] . "/openvpn_{$mode}{$id}.";
155
	$keys = array();
156
	if ($settings['auth_method'] == 'shared_key')
157
		$keys[] = array('field' => 'shared_key', 'ext'  => 'secret', 'directive' => 'secret');
158
	else {
159
		$keys[] = array('field' => 'ca_cert', 'ext' => 'ca', 'directive' => 'ca');
160
		$keys[] = array('field' => "{$mode}_cert", 'ext' => 'cert', 'directive' => 'cert');
161
		$keys[] = array('field' => "{$mode}_key", 'ext' => 'key', 'directive' => 'key');
162
		if ($mode == 'server')
163
			$keys[] = array('field' => 'dh_params', 'ext' => 'dh', 'directive' => 'dh');
164
		if ($settings['crl'])
165
			$keys[] = array('field' => 'crl', 'ext' => 'crl', 'directive' => 'crl-verify');
166
	}
167
	foreach($keys as $key) {
168
		$filename = $base_file . $key['ext'];
169
		file_put_contents($filename, base64_decode($settings[$key['field']]));
170
		chown($filename, 'nobody');
171
		chgrp($filename, 'nobody');
172
	}
173

    
174
	$pidfile = $g['varrun_path'] . "/openvpn_{$mode}{$id}.pid";
175
	$proto = ($settings['protocol'] == 'UDP' ? 'udp' : "tcp-{$mode}");
176
	$cipher = $settings['crypto'];
177
	$openvpn_conf = <<<EOD
178
writepid $pidfile
179
#user nobody
180
#group nobody
181
daemon
182
keepalive 10 60
183
ping-timer-rem
184
persist-tun
185
persist-key
186
dev tun
187
proto $proto
188
cipher $cipher
189

    
190
EOD;
191

    
192
	// Mode-specific stuff
193
	if ($mode == 'server') {
194
		list($ip, $mask) = explode('/', $settings['addresspool']);
195
		$mask = gen_subnet_mask($mask);
196

    
197
		// Using a shared key or not dynamically assigning IPs to the clients
198
		if (($settings['auth_method'] == 'shared_key') || ($settings['nopool'] == 'on')) {
199
			if ($settings['auth_method'] == 'pki') $openvpn_conf .= "tls-server\n";
200

    
201
			$baselong = ip2long($ip) & ip2long($mask);
202
			$ip1 = long2ip($baselong + 1);
203
			$ip2 = long2ip($baselong + 2);
204
			$openvpn_conf .= "ifconfig $ip1 $ip2\n";
205
		}
206
		// Using a PKI
207
		else if ($settings['auth_method'] == 'pki') {
208
			if ($settings['client2client']) $openvpn_conf .= "client-to-client\n";
209
			$openvpn_conf .= "server $ip $mask\n";
210
			$csc_dir = "{$g['varetc_path']}/openvpn_csc";
211
			$openvpn_conf .= "client-config-dir $csc_dir\n";
212
		}
213

    
214
		// We can push routes
215
		if (!empty($settings['local_network'])) {
216
			list($ip, $mask) = explode('/', $settings['local_network']);
217
			$mask = gen_subnet_mask($mask);
218
			$openvpn_conf .= "push \"route $ip $mask\"\n";
219
		}
220

    
221
		// The port we'll listen at
222
		$openvpn_conf .= "lport {$settings['local_port']}\n";
223
	}
224

    
225
	else { // $mode == client
226
		// The remote server
227
		$openvpn_conf .= "remote {$settings['serveraddr']} {$settings['serverport']}\n";
228

    
229
		if ($settings['auth_method'] == 'pki') $openvpn_conf .= "client\n";
230

    
231
		if (!empty($settings['interface_ip'])) {
232
			// Configure the IPs according to the address pool
233
			list($ip, $mask) = explode('/', $settings['interface_ip']);
234
			$mask = gen_subnet_mask($mask);
235
			$baselong = ip2long($ip) & ip2long($mask);
236
			$ip1 = long2ip($baselong + 1);
237
			$ip2 = long2ip($baselong + 2);
238
			$openvpn_conf .= "ifconfig $ip2 $ip1\n";
239
		}
240
		if (isset($settings['proxy_hostname']) && $settings['proxy_hostname'] != "") {
241
			/* ;http-proxy-retry # retry on connection failures */
242
			$openvpn_conf .= "http-proxy {$settings['proxy_hostname']} {$settings['proxy_port']}\n";
243
		}
244
	}
245

    
246
	// Add the routes if they're set
247
	if (!empty($settings['remote_network'])) {
248
		list($ip, $mask) = explode('/', $settings['remote_network']);
249
		$mask = gen_subnet_mask($mask);
250
		$openvpn_conf .= "route $ip $mask\n";
251
	}
252

    
253
	// Write the settings for the keys
254
	foreach ($keys as $key)
255
		$openvpn_conf .= $key['directive'] . ' ' . $base_file . $key['ext'] . "\n";
256

    
257
	if ($settings['use_lzo']) $openvpn_conf .= "comp-lzo\n";
258

    
259
	if ($settings['dynamic_ip']) {
260
		$openvpn_conf .= "persist-remote-ip\n";
261
		$openvpn_conf .= "float\n";
262
	}
263

    
264
	if (!empty($settings['custom_options'])) {
265
		$options = explode(';', $settings['custom_options']);
266
		if (is_array($options)) {
267
			foreach ($options as $option)
268
				$openvpn_conf .= "$option\n";
269
		}
270
		else {
271
			$openvpn_conf .= "{$settings['custom_options']}\n";
272
		}
273
	}
274

    
275
	file_put_contents($g['varetc_path'] . "/openvpn_{$mode}{$id}.conf", $openvpn_conf);
276
}
277

    
278

    
279
function openvpn_resync_csc($id) {
280
	global $g, $config;
281

    
282
	$settings = $config['installedpackages']['openvpncsc']['config'][$id];
283

    
284
	if ($settings['disable'] == 'on') return;
285

    
286
	$conf = '';
287
	if ($settings['block'] == 'on') $conf .= "disable\n";
288
	if ($settings['push_reset'] == 'on') $conf .= "push-reset\n";
289
	if (!empty($settings['ifconfig_push'])) {
290
		list($ip, $mask) = explode('/', $settings['ifconfig_push']);
291
		$baselong = ip2long($ip) & gen_subnet_mask_long($mask);
292
		$conf .= 'ifconfig-push ' . long2ip($baselong + 1) . ' ' . long2ip($baselong + 2) . "\n";
293
	}
294
	if (!empty($settings['custom_options'])) {
295
		$options = explode(';', $settings['custom_options']);
296
		if (is_array($options)) {
297
			foreach ($options as $option)
298
				$conf .= "$option\n";
299
		}
300
		else {
301
			$conf .= "{$settings['custom_options']}\n";
302
		}
303
	}
304

    
305
	openvpn_create_cscdir();
306
	$filename = "{$g['varetc_path']}/openvpn_csc/{$settings['commonname']}";
307
	file_put_contents($filename, $conf);
308
	chown($filename, 'nobody');
309
	chgrp($filename, 'nogroup');
310
}
311

    
312

    
313
function openvpn_restart($mode, $id) {
314
	global $g, $config;
315

    
316
	$pidfile = $g['varrun_path'] . "/openvpn_{$mode}{$id}.pid";
317
	killbypid($pidfile);
318
	sleep(2);
319

    
320
	$settings = $config['installedpackages']["openvpn$mode"]['config'][$id];
321
	if ($settings['disable']) return;
322

    
323
	$configfile = $g['varetc_path'] . "/openvpn_{$mode}{$id}.conf";
324
	mwexec("openvpn --config $configfile");
325
	touch("{$g['tmp_path']}/filter_dirty");
326
}
327

    
328

    
329
// Resync the configuration and restart the VPN 
330
function openvpn_resync($mode, $id) {
331
	openvpn_reconfigure($mode, $id);
332
	openvpn_restart($mode, $id);
333
}
334

    
335
function openvpn_create_cscdir() {
336
	global $g;
337

    
338
	$csc_dir = "{$g['varetc_path']}/openvpn_csc";
339
	if (!is_dir($csc_dir)) {
340
		mkdir($csc_dir);
341
		chown($csc_dir, 'nobody');
342
		chgrp($csc_dir, 'nobody');
343
	}
344
}
345

    
346
// Resync and restart all VPNs
347
function openvpn_resync_all() {
348
	global $config;
349

    
350
	foreach (array('server', 'client') as $mode) {
351
		if (is_array($config['installedpackages']["openvpn$mode"]['config'])) {
352
			foreach ($config['installedpackages']["openvpn$mode"]['config'] as $id => $settings)
353
				openvpn_resync($mode, $id);
354
		}
355
	}
356

    
357
	openvpn_create_cscdir();
358
	if (is_array($config['installedpackages']['openvpncsc']['config'])) {
359
		foreach ($config['installedpackages']['openvpncsc']['config'] as $id => $csc)
360
			openvpn_resync_csc($id);
361
	}
362
}
363

    
364

    
365
function openvpn_print_javascript($mode) {
366
	$javascript = <<<EOD
367
<script language="JavaScript">
368
<!--
369
function onAuthMethodChanged() {
370
	var method = document.iform.auth_method;
371
	var endis = (method.options[method.selectedIndex].value == 'shared_key');
372

    
373
	document.iform.shared_key.disabled = !endis;
374
	document.iform.ca_cert.disabled = endis;
375
	document.iform.{$mode}_cert.disabled = endis;
376
	document.iform.{$mode}_key.disabled = endis;
377

    
378
EOD;
379
	if ($mode == 'server') {
380
		$javascript .= <<<EOD
381
	document.iform.dh_params.disabled = endis;
382
	document.iform.crl.disabled = endis;
383
	document.iform.nopool.disabled = endis;
384
	document.iform.local_network.disabled = endis;
385
	document.iform.client2client.disabled = endis;
386

    
387
EOD;
388
	}
389

    
390
	else { // Client mode
391
		$javascript .= "\tdocument.iform.remote_network.disabled = !endis;\n";
392
	}
393

    
394
	$javascript .= <<<EOD
395
}
396
//-->
397
</script>
398

    
399
EOD;
400
	print($javascript);
401
}
402

    
403

    
404
function openvpn_print_javascript2() {
405
	$javascript = <<<EOD
406
<script language="JavaScript">
407
<!--
408
	onAuthMethodChanged();
409
//-->
410
</script>
411

    
412
EOD;
413
	print($javascript);
414
}
415
?>
(13-13/27)