Project

General

Profile

Download (15.9 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/* $Id$ */
3
/*
4
	vpn.inc
5
	Copyright (C) 2004 Scott Ullrich
6
	All rights reserved.
7

    
8
	originally part of m0n0wall (http://m0n0.ch/wall)
9
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
10
	All rights reserved.
11

    
12
	Redistribution and use in source and binary forms, with or without
13
	modification, are permitted provided that the following conditions are met:
14

    
15
	1. Redistributions of source code must retain the above copyright notice,
16
	   this list of conditions and the following disclaimer.
17

    
18
	2. Redistributions in binary form must reproduce the above copyright
19
	   notice, this list of conditions and the following disclaimer in the
20
	   documentation and/or other materials provided with the distribution.
21

    
22
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
24
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
26
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
	POSSIBILITY OF SUCH DAMAGE.
32
*/
33

    
34
/* include all configuration functions */
35
require_once("functions.inc");
36

    
37
function find_last_gif_device() {
38
        $last_gif_found = -1;
39
        if (!($fp = popen("/sbin/ifconfig -l", "r"))) return -1;
40
        $ifconfig_data = fread($fp, 4096);
41
        pclose($fp);
42
        $ifconfig_array = split(" ", $ifconfig_data);
43
        foreach ($ifconfig_array as $ifconfig) {
44
                ereg("gif(.)", $ifconfig, $regs);
45
                if($regs[0]) {
46
                        if($regs[0] > $last_gif_found)
47
                                $last_gif_found = $regs[1];
48
                }
49
        }
50
        return $last_gif_found;
51
}
52

    
53
function vpn_ipsec_configure($ipchg = false) {
54
	global $config, $g;
55

    
56
	if(isset($config['ipsec']['preferredoldsa'])) {
57
		mwexec("/sbin/sysctl net.key.preferred_oldsa=0");
58
	} else {
59
		mwexec("/sbin/sysctl -w net.key.preferred_oldsa=-30");
60
	}
61

    
62
	$number_of_gifs = find_last_gif_device();
63
	for($x=0; $x<$number_of_gifs; $x++) {
64
		mwexec("/sbin/ifconfig gif" . $x . " delete");
65
	}
66

    
67
	$curwanip = get_current_wan_address();
68
		if($config['ipsec']['ip'] <> "")
69
			$curwanip = $config['ipsec']['ip'];
70

    
71
	$syscfg = $config['system'];
72
	$ipseccfg = $config['ipsec'];
73
	$lancfg = $config['interfaces']['lan'];
74
	$lanip = $lancfg['ipaddr'];
75
	$lansa = gen_subnet($lancfg['ipaddr'], $lancfg['subnet']);
76
	$lansn = $lancfg['subnet'];
77

    
78
	if ($g['booting']) {
79
		if (!isset($ipseccfg['enable']))
80
			return 0;
81

    
82
		echo "Configuring IPsec VPN... ";
83
	} else {
84
		/* kill racoon */
85
		killbypid("{$g['varrun_path']}/racoon.pid");
86

    
87
		/* wait for process to die */
88
		sleep(2);
89

    
90
		/* send a SIGKILL to be sure */
91
		sigkillbypid("{$g['varrun_path']}/racoon.pid", "KILL");
92
	}
93

    
94
	/* flush SPD and SAD */
95
	mwexec("/usr/sbin/setkey -FP");
96
	mwexec("/usr/sbin/setkey -F");
97

    
98
	if (isset($ipseccfg['enable'])) {
99

    
100
		/* fastforwarding is not compatible with ipsec tunnels */
101
		system("/sbin/sysctl net.inet.ip.fastforwarding=0 >/dev/null 2>&1");
102

    
103
		if (!$curwanip) {
104
			/* IP address not configured yet, exit */
105
			if ($g['booting'])
106
				echo "done.\n";
107
			return 0;
108
		}
109

    
110
		if ((is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel'])) ||
111
				isset($ipseccfg['mobileclients']['enable'])) {
112

    
113
			if (is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel'])) {
114

    
115
				/* generate spd.conf */
116
				$fd = fopen("{$g['varetc_path']}/spd.conf", "w");
117
				if (!$fd) {
118
					printf("Error: cannot open spd.conf in vpn_ipsec_configure().\n");
119
					return 1;
120
				}
121

    
122
				$spdconf = "";
123

    
124
				$spdconf .= "spdadd {$lansa}/{$lansn} {$lanip}/32 any -P in none;\n";
125
				$spdconf .= "spdadd {$lanip}/32 {$lansa}/{$lansn} any -P out none;\n";
126

    
127
				foreach ($ipseccfg['tunnel'] as $tunnel) {
128

    
129
					if (isset($tunnel['disabled']))
130
						continue;
131

    
132
					$ep = vpn_endpoint_determine($tunnel, $curwanip);
133
					if (!$ep)
134
						continue;
135

    
136
					vpn_localnet_determine($tunnel['local-subnet'], $sa, $sn);
137

    
138
					if(isset($tunnel['creategif'])) {
139
						$number_of_gifs = find_last_gif_device();
140
						$number_of_gifs++;
141
						$curwanip = get_current_wan_address();
142
						if($config['ipsec']['ip'] <> "")
143
							$curwanip = $config['ipsec']['ip'];
144
						mwexec("/sbin/ifconfig gif" . $number_of_gifs . " tunnel" . $curwanip . " " . $tunnel['remote-gateway']);
145
						mwexec("/sbin/ifconfig gif" . $number_of_gifs . " {$lansa}/{$lansn} {$lanip}/32");
146
					}
147

    
148
					$spdconf .= "spdadd {$sa}/{$sn} " .
149
						"{$tunnel['remote-subnet']} any -P out ipsec " .
150
						"{$tunnel['p2']['protocol']}/tunnel/{$ep}-" .
151
						"{$tunnel['remote-gateway']}/unique;\n";
152

    
153
					$spdconf .= "spdadd {$tunnel['remote-subnet']} " .
154
						"{$sa}/{$sn} any -P in ipsec " .
155
						"{$tunnel['p2']['protocol']}/tunnel/{$tunnel['remote-gateway']}-" .
156
						"{$ep}/unique;\n";
157
				}
158

    
159
				fwrite($fd, $spdconf);
160
				fclose($fd);
161

    
162
				/* load SPD */
163
				mwexec("/usr/sbin/setkey -c < {$g['varetc_path']}/spd.conf");
164
			}
165

    
166
			/* generate racoon.conf */
167
			$fd = fopen("{$g['varetc_path']}/racoon.conf", "w");
168
			if (!$fd) {
169
				printf("Error: cannot open racoon.conf in vpn_ipsec_configure().\n");
170
				return 1;
171
			}
172

    
173
			$racoonconf = "";
174

    
175
			if($config['ipsec']['ip'] <> "") {
176

    
177
				$interface_ip = $config['ipsec']['ip'];
178
				$racoonconf .= <<<EOD
179
listen {
180
	isakmp {$interface_ip} [500];
181
}
182

    
183
EOD;
184
			}
185

    
186
			$racoonconf .= "path pre_shared_key \"{$g['varetc_path']}/psk.txt\";\n\n";
187

    
188
			if (is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel']))
189
				foreach ($ipseccfg['tunnel'] as $tunnel) {
190

    
191
				if (isset($tunnel['disabled']))
192
					continue;
193

    
194
				$ep = vpn_endpoint_determine($tunnel, $curwanip);
195
				if (!$ep)
196
					continue;
197

    
198
				vpn_localnet_determine($tunnel['local-subnet'], $sa, $sn);
199

    
200
				if (isset($tunnel['p1']['myident']['myaddress'])) {
201
					$myidentt = "address";
202
					$myident = $ep;
203
				} else if (isset($tunnel['p1']['myident']['address'])) {
204
					$myidentt = "address";
205
					$myident = $tunnel['p1']['myident']['address'];
206
				} else if (isset($tunnel['p1']['myident']['fqdn'])) {
207
					$myidentt = "fqdn";
208
					$myident = $tunnel['p1']['myident']['fqdn'];
209
				} else if (isset($tunnel['p1']['myident']['ufqdn'])) {
210
					$myidentt = "user_fqdn";
211
					$myident = $tunnel['p1']['myident']['ufqdn'];
212
 				}
213

    
214
				$racoonconf .= <<<EOD
215
remote {$tunnel['remote-gateway']} \{
216
	exchange_mode {$tunnel['p1']['mode']};
217
	my_identifier {$myidentt} "{$myident}";
218
	peers_identifier address {$tunnel['remote-gateway']};
219
	initial_contact on;
220
	support_proxy on;
221
	proposal_check obey;
222

    
223
	proposal \{
224
		encryption_algorithm {$tunnel['p1']['encryption-algorithm']};
225
		hash_algorithm {$tunnel['p1']['hash-algorithm']};
226
		authentication_method pre_shared_key;
227
		dh_group {$tunnel['p1']['dhgroup']};
228

    
229
EOD;
230
				if ($tunnel['p1']['lifetime'])
231
					$racoonconf .= "		lifetime time {$tunnel['p1']['lifetime']} secs;\n";
232

    
233
				$racoonconf .= "	}\n";
234

    
235
				if ($tunnel['p1']['lifetime'])
236
					$racoonconf .= "	lifetime time {$tunnel['p1']['lifetime']} secs;\n";
237

    
238
				$racoonconf .= "}\n\n";
239

    
240
				$p2ealgos = join(",", $tunnel['p2']['encryption-algorithm-option']);
241
				$p2halgos = join(",", $tunnel['p2']['hash-algorithm-option']);
242

    
243
				$racoonconf .= <<<EOD
244
sainfo address {$sa}/{$sn} any address {$tunnel['remote-subnet']} any \{
245
	encryption_algorithm {$p2ealgos};
246
	authentication_algorithm {$p2halgos};
247
	compression_algorithm deflate;
248

    
249
EOD;
250

    
251
				if ($tunnel['p2']['pfsgroup'])
252
					$racoonconf .= "	pfs_group {$tunnel['p2']['pfsgroup']};\n";
253

    
254
				if ($tunnel['p2']['lifetime'])
255
					$racoonconf .= "	lifetime time {$tunnel['p2']['lifetime']} secs;\n";
256

    
257
				$racoonconf .= "}\n\n";
258
			}
259

    
260
			/* mobile clients? */
261
			if (isset($ipseccfg['mobileclients']['enable'])) {
262

    
263
				$tunnel = $ipseccfg['mobileclients'];
264

    
265
				if (isset($tunnel['p1']['myident']['myaddress'])) {
266
					$myidentt = "address";
267
					$myident = $curwanip;
268
				} else if (isset($tunnel['p1']['myident']['address'])) {
269
					$myidentt = "address";
270
					$myident = $tunnel['p1']['myident']['address'];
271
				} else if (isset($tunnel['p1']['myident']['fqdn'])) {
272
					$myidentt = "fqdn";
273
					$myident = $tunnel['p1']['myident']['fqdn'];
274
				} else if (isset($tunnel['p1']['myident']['ufqdn'])) {
275
					$myidentt = "user_fqdn";
276
					$myident = $tunnel['p1']['myident']['ufqdn'];
277
 				}
278

    
279
				$racoonconf .= <<<EOD
280
remote anonymous \{
281
	exchange_mode {$tunnel['p1']['mode']};
282
	my_identifier {$myidentt} "{$myident}";
283
	initial_contact on;
284
	passive on;
285
	generate_policy on;
286
	support_proxy on;
287
	proposal_check obey;
288

    
289
	proposal \{
290
		encryption_algorithm {$tunnel['p1']['encryption-algorithm']};
291
		hash_algorithm {$tunnel['p1']['hash-algorithm']};
292
		authentication_method pre_shared_key;
293
		dh_group {$tunnel['p1']['dhgroup']};
294

    
295
EOD;
296
				if ($tunnel['p1']['lifetime'])
297
					$racoonconf .= "		lifetime time {$tunnel['p1']['lifetime']} secs;\n";
298

    
299
				$racoonconf .= "	}\n";
300

    
301
				if ($tunnel['p1']['lifetime'])
302
					$racoonconf .= "	lifetime time {$tunnel['p1']['lifetime']} secs;\n";
303

    
304
				$racoonconf .= "}\n\n";
305

    
306
				$p2ealgos = join(",", $tunnel['p2']['encryption-algorithm-option']);
307
				$p2halgos = join(",", $tunnel['p2']['hash-algorithm-option']);
308

    
309
				$racoonconf .= <<<EOD
310
sainfo anonymous \{
311
	encryption_algorithm {$p2ealgos};
312
	authentication_algorithm {$p2halgos};
313
	compression_algorithm deflate;
314

    
315
EOD;
316

    
317
				if ($tunnel['p2']['pfsgroup'])
318
					$racoonconf .= "	pfs_group {$tunnel['p2']['pfsgroup']};\n";
319

    
320
				if ($tunnel['p2']['lifetime'])
321
					$racoonconf .= "	lifetime time {$tunnel['p2']['lifetime']} secs;\n";
322

    
323
				$racoonconf .= "}\n\n";
324
			}
325

    
326
			fwrite($fd, $racoonconf);
327
			fclose($fd);
328

    
329
			/* generate psk.txt */
330
			$fd = fopen("{$g['varetc_path']}/psk.txt", "w");
331
			if (!$fd) {
332
				printf("Error: cannot open psk.txt in vpn_ipsec_configure().\n");
333
				return 1;
334
			}
335

    
336
			$pskconf = "";
337

    
338
			if (is_array($ipseccfg['tunnel'])) {
339
				foreach ($ipseccfg['tunnel'] as $tunnel) {
340
					if (isset($tunnel['disabled']))
341
						continue;
342
					$pskconf .= "{$tunnel['remote-gateway']}	 {$tunnel['p1']['pre-shared-key']}\n";
343
				}
344
			}
345

    
346
			/* add PSKs for mobile clients */
347
			if (is_array($ipseccfg['mobilekey'])) {
348
				foreach ($ipseccfg['mobilekey'] as $key) {
349
					$pskconf .= "{$key['ident']}	{$key['pre-shared-key']}\n";
350
				}
351
			}
352

    
353
			fwrite($fd, $pskconf);
354
			fclose($fd);
355
			chmod("{$g['varetc_path']}/psk.txt", 0600);
356

    
357
			/* start racoon */
358
			mwexec("/usr/local/sbin/racoon -d -f {$g['varetc_path']}/racoon.conf");
359

    
360
			if(is_array($ipseccfg['tunnel']))
361
				foreach ($ipseccfg['tunnel'] as $tunnel) {
362
					if (isset($tunnel['auto'])) {
363
						$remotehost = substr($tunnel['remote-subnet'],0,strpos($tunnel['remote-subnet'],"/"));
364
						$srchost = vpn_endpoint_determine($tunnel, $curwanip);
365
						if ($srchost)
366
							mwexec_bg("/sbin/ping -c 1 -S {$srchost} {$remotehost}");
367
					}
368
				}
369
		}
370
	}
371

    
372
	if (!$g['booting']) {
373
		/* reload the filter */
374
		filter_configure();
375
	}
376

    
377
	if ($g['booting'])
378
		echo "done.\n";
379

    
380
	return 0;
381
}
382

    
383
function vpn_pptpd_configure() {
384
	global $config, $g;
385

    
386
	$syscfg = $config['system'];
387
	$pptpdcfg = $config['pptpd'];
388

    
389
	if ($g['booting']) {
390
		if (!$pptpdcfg['mode'] || ($pptpdcfg['mode'] == "off"))
391
			return 0;
392

    
393
		echo "Configuring PPTP VPN... ";
394
	} else {
395
		/* kill mpd */
396
		killbypid("{$g['varrun_path']}/mpd-vpn.pid");
397

    
398
		/* wait for process to die */
399
		sleep(2);
400

    
401
		/* remove mpd.conf, if it exists */
402
		unlink_if_exists("{$g['varetc_path']}/mpd-vpn/mpd.conf");
403
		unlink_if_exists("{$g['varetc_path']}/mpd-vpn/mpd.links");
404
		unlink_if_exists("{$g['varetc_path']}/mpd-vpn/mpd.secret");
405
	}
406

    
407
	/* make sure mpd-vpn directory exists */
408
	safe_mkdir("{$g['varetc_path']}/mpd-vpn");
409

    
410
	switch ($pptpdcfg['mode']) {
411

    
412
		case 'server':
413

    
414
			/* write mpd.conf */
415
			$fd = fopen("{$g['varetc_path']}/mpd-vpn/mpd.conf", "w");
416
			if (!$fd) {
417
				printf("Error: cannot open mpd.conf in vpn_pptpd_configure().\n");
418
				return 1;
419
			}
420

    
421
			$mpdconf = <<<EOD
422
pptpd:
423

    
424
EOD;
425

    
426
			for ($i = 0; $i < $g['n_pptp_units']; $i++) {
427
				$mpdconf .= "	load pt{$i}\n";
428
			}
429

    
430
			for ($i = 0; $i < $g['n_pptp_units']; $i++) {
431

    
432
				$clientip = long2ip(ip2long($pptpdcfg['remoteip']) + $i);
433
				$ngif = "ng" . ($i+1);
434

    
435
				$mpdconf .= <<<EOD
436

    
437
pt{$i}:
438
	new -i {$ngif} pt{$i} pt{$i}
439
	set ipcp ranges {$pptpdcfg['localip']}/32 {$clientip}/32
440
	load pts
441

    
442
EOD;
443
			}
444

    
445
			$mpdconf .= <<<EOD
446

    
447
pts:
448
	set iface disable on-demand
449
	set iface enable proxy-arp
450
	set iface enable tcpmssfix
451
	set iface idle 1800
452
	set iface up-script /usr/local/sbin/vpn-linkup
453
	set iface down-script /usr/local/sbin/vpn-linkdown
454
	set bundle enable multilink
455
	set bundle enable crypt-reqd
456
	set link yes acfcomp protocomp
457
	set link no pap chap
458
	set link enable chap-msv2
459
	set link mtu 1460
460
	set link keep-alive 10 60
461
	set ipcp yes vjcomp
462
	set bundle enable compression
463
	set ccp yes mppc
464
	set ccp yes mpp-e128
465
	set ccp yes mpp-stateless
466

    
467
EOD;
468

    
469
			if (!isset($pptpdcfg['req128'])) {
470
				$mpdconf .= <<<EOD
471
	set ccp yes mpp-e40
472
	set ccp yes mpp-e56
473

    
474
EOD;
475
			}
476

    
477
			if (isset($config['dnsmasq']['enable'])) {
478
				$mpdconf .= "	set ipcp dns " . $config['interfaces']['lan']['ipaddr'];
479
				if ($syscfg['dnsserver'][0])
480
					$mpdconf .= " " . $syscfg['dnsserver'][0];
481
				$mpdconf .= "\n";
482
			} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
483
				$mpdconf .= "	set ipcp dns " . join(" ", $syscfg['dnsserver']) . "\n";
484
			}
485

    
486
			if (isset($pptpdcfg['radius']['enable'])) {
487
				$mpdconf .= <<<EOD
488
	set radius server {$pptpdcfg['radius']['server']} "{$pptpdcfg['radius']['secret']}"
489
	set radius retries 3
490
	set radius timeout 10
491
	set bundle enable radius-auth
492
	set bundle disable radius-fallback
493

    
494
EOD;
495

    
496
				if (isset($pptpdcfg['radius']['accounting'])) {
497
					$mpdconf .= <<<EOD
498
	set bundle enable radius-acct
499

    
500
EOD;
501
				}
502
			}
503

    
504
			fwrite($fd, $mpdconf);
505
			fclose($fd);
506

    
507
			/* write mpd.links */
508
			$fd = fopen("{$g['varetc_path']}/mpd-vpn/mpd.links", "w");
509
			if (!$fd) {
510
				printf("Error: cannot open mpd.links in vpn_pptpd_configure().\n");
511
				return 1;
512
			}
513

    
514
			$mpdlinks = "";
515

    
516
			for ($i = 0; $i < $g['n_pptp_units']; $i++) {
517
				$mpdlinks .= <<<EOD
518

    
519
pt{$i}:
520
	set link type pptp
521
	set pptp enable incoming
522
	set pptp disable originate
523
	set pptp disable windowing
524
	set pptp self 127.0.0.1
525

    
526
EOD;
527
			}
528

    
529
			fwrite($fd, $mpdlinks);
530
			fclose($fd);
531

    
532
			/* write mpd.secret */
533
			$fd = fopen("{$g['varetc_path']}/mpd-vpn/mpd.secret", "w");
534
			if (!$fd) {
535
				printf("Error: cannot open mpd.secret in vpn_pptpd_configure().\n");
536
				return 1;
537
			}
538

    
539
			$mpdsecret = "";
540

    
541
			if (is_array($pptpdcfg['user'])) {
542
				foreach ($pptpdcfg['user'] as $user)
543
					$mpdsecret .= "{$user['name']} \"{$user['password']}\" {$user['ip']}\n";
544
			}
545

    
546
			fwrite($fd, $mpdsecret);
547
			fclose($fd);
548
			chmod("{$g['varetc_path']}/mpd-vpn/mpd.secret", 0600);
549

    
550
			/* fire up mpd */
551
			mwexec("/usr/local/sbin/mpd -b -d {$g['varetc_path']}/mpd-vpn -p {$g['varrun_path']}/mpd-vpn.pid pptpd");
552

    
553
			break;
554

    
555
		case 'redir':
556
			break;
557
	}
558

    
559
	if ($g['booting'])
560
		echo "done.\n";
561
	else
562
		filter_configure();
563

    
564
	return 0;
565
}
566

    
567
function vpn_localnet_determine($adr, &$sa, &$sn) {
568
	global $config, $g;
569

    
570
	if (isset($adr)) {
571
		if ($adr['network']) {
572
			switch ($adr['network']) {
573
				case 'lan':
574
					$sn = $config['interfaces']['lan']['subnet'];
575
					$sa = gen_subnet($config['interfaces']['lan']['ipaddr'], $sn);
576
					break;
577
			}
578
		} else if ($adr['address']) {
579
			list($sa,$sn) = explode("/", $adr['address']);
580
			if (is_null($sn))
581
				$sn = 32;
582
		}
583
	} else {
584
		$sn = $config['interfaces']['lan']['subnet'];
585
		$sa = gen_subnet($config['interfaces']['lan']['ipaddr'], $sn);
586
	}
587
}
588

    
589
function vpn_endpoint_determine($tunnel, $curwanip) {
590

    
591
	global $g, $config;
592

    
593
	if ((!$tunnel['interface']) || ($tunnel['interface'] == "wan")) {
594
		if ($curwanip)
595
			return $curwanip;
596
		else
597
			return null;
598
	} else if ($tunnel['interface'] == "lan") {
599
		return $config['interfaces']['lan']['ipaddr'];
600
	} else {
601
		$oc = $config['interfaces'][$tunnel['interface']];
602

    
603
		if (isset($oc['enable']) && $oc['if']) {
604
			return $oc['ipaddr'];
605
		}
606
	}
607

    
608
	return null;
609
}
610

    
611
?>
(14-14/18)