Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

    
66
	$curwanip = get_current_wan_address();
67

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

    
75
	if ($g['booting']) {
76
		if (!isset($ipseccfg['enable']))
77
			return 0;
78

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

    
84
		/* wait for process to die */
85
		sleep(2);
86

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

    
91
	/* flush SPD and SAD */
92
	mwexec("/usr/sbin/setkey -FP");
93
	mwexec("/usr/sbin/setkey -F");
94

    
95
	if (isset($ipseccfg['enable'])) {
96

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

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

    
107
		if ((is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel'])) ||
108
				isset($ipseccfg['mobileclients']['enable'])) {
109

    
110
			if (is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel'])) {
111

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

    
119
				$spdconf = "";
120

    
121
				$spdconf .= "spdadd {$lansa}/{$lansn} {$lanip}/32 any -P in none;\n";
122
				$spdconf .= "spdadd {$lanip}/32 {$lansa}/{$lansn} any -P out none;\n";
123

    
124
				foreach ($ipseccfg['tunnel'] as $tunnel) {
125

    
126
					if (isset($tunnel['disabled']))
127
						continue;
128

    
129
					$ep = vpn_endpoint_determine($tunnel, $curwanip);
130
					if (!$ep)
131
						continue;
132

    
133
					vpn_localnet_determine($tunnel['local-subnet'], $sa, $sn);
134

    
135
					if(isset($tunnel['creategif'])) {
136
						$number_of_gifs = find_last_gif_device();
137
						$number_of_gifs++;
138
						$curwanip = get_current_wan_address();
139
						mwexec("/sbin/ifconfig gif" . $number_of_gifs . " tunnel" . $curwanip . " " . $tunnel['remote-gateway']);
140
						mwexec("/sbin/ifconfig gif" . $number_of_gifs . " {$lansa}/{$lansn} {$lanip}/32");
141
					}
142

    
143
					$spdconf .= "spdadd {$sa}/{$sn} " .
144
						"{$tunnel['remote-subnet']} any -P out ipsec " .
145
						"{$tunnel['p2']['protocol']}/tunnel/{$ep}-" .
146
						"{$tunnel['remote-gateway']}/unique;\n";
147

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

    
154
				fwrite($fd, $spdconf);
155
				fclose($fd);
156

    
157
				/* load SPD */
158
				mwexec("/usr/sbin/setkey -c < {$g['varetc_path']}/spd.conf");
159
			}
160

    
161
			/* generate racoon.conf */
162
			$fd = fopen("{$g['varetc_path']}/racoon.conf", "w");
163
			if (!$fd) {
164
				printf("Error: cannot open racoon.conf in vpn_ipsec_configure().\n");
165
				return 1;
166
			}
167

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

    
170
			if (is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel']))
171
				foreach ($ipseccfg['tunnel'] as $tunnel) {
172

    
173
				if (isset($tunnel['disabled']))
174
					continue;
175

    
176
				$ep = vpn_endpoint_determine($tunnel, $curwanip);
177
				if (!$ep)
178
					continue;
179

    
180
				vpn_localnet_determine($tunnel['local-subnet'], $sa, $sn);
181

    
182
				if (isset($tunnel['p1']['myident']['myaddress'])) {
183
					$myidentt = "address";
184
					$myident = $ep;
185
				} else if (isset($tunnel['p1']['myident']['address'])) {
186
					$myidentt = "address";
187
					$myident = $tunnel['p1']['myident']['address'];
188
				} else if (isset($tunnel['p1']['myident']['fqdn'])) {
189
					$myidentt = "fqdn";
190
					$myident = $tunnel['p1']['myident']['fqdn'];
191
				} else if (isset($tunnel['p1']['myident']['ufqdn'])) {
192
					$myidentt = "user_fqdn";
193
					$myident = $tunnel['p1']['myident']['ufqdn'];
194
 				}
195

    
196
				$racoonconf .= <<<EOD
197
remote {$tunnel['remote-gateway']} \{
198
	exchange_mode {$tunnel['p1']['mode']};
199
	my_identifier {$myidentt} "{$myident}";
200
	peers_identifier address {$tunnel['remote-gateway']};
201
	initial_contact on;
202
	support_proxy on;
203
	proposal_check obey;
204

    
205
	proposal \{
206
		encryption_algorithm {$tunnel['p1']['encryption-algorithm']};
207
		hash_algorithm {$tunnel['p1']['hash-algorithm']};
208
		authentication_method pre_shared_key;
209
		dh_group {$tunnel['p1']['dhgroup']};
210

    
211
EOD;
212
				if ($tunnel['p1']['lifetime'])
213
					$racoonconf .= "		lifetime time {$tunnel['p1']['lifetime']} secs;\n";
214

    
215
				$racoonconf .= "	}\n";
216

    
217
				if ($tunnel['p1']['lifetime'])
218
					$racoonconf .= "	lifetime time {$tunnel['p1']['lifetime']} secs;\n";
219

    
220
				$racoonconf .= "}\n\n";
221

    
222
				$p2ealgos = join(",", $tunnel['p2']['encryption-algorithm-option']);
223
				$p2halgos = join(",", $tunnel['p2']['hash-algorithm-option']);
224

    
225
				$racoonconf .= <<<EOD
226
sainfo address {$sa}/{$sn} any address {$tunnel['remote-subnet']} any \{
227
	encryption_algorithm {$p2ealgos};
228
	authentication_algorithm {$p2halgos};
229
	compression_algorithm deflate;
230

    
231
EOD;
232

    
233
				if ($tunnel['p2']['pfsgroup'])
234
					$racoonconf .= "	pfs_group {$tunnel['p2']['pfsgroup']};\n";
235

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

    
239
				$racoonconf .= "}\n\n";
240
			}
241

    
242
			/* mobile clients? */
243
			if (isset($ipseccfg['mobileclients']['enable'])) {
244

    
245
				$tunnel = $ipseccfg['mobileclients'];
246

    
247
				if (isset($tunnel['p1']['myident']['myaddress'])) {
248
					$myidentt = "address";
249
					$myident = $curwanip;
250
				} else if (isset($tunnel['p1']['myident']['address'])) {
251
					$myidentt = "address";
252
					$myident = $tunnel['p1']['myident']['address'];
253
				} else if (isset($tunnel['p1']['myident']['fqdn'])) {
254
					$myidentt = "fqdn";
255
					$myident = $tunnel['p1']['myident']['fqdn'];
256
				} else if (isset($tunnel['p1']['myident']['ufqdn'])) {
257
					$myidentt = "user_fqdn";
258
					$myident = $tunnel['p1']['myident']['ufqdn'];
259
 				}
260

    
261
				$racoonconf .= <<<EOD
262
remote anonymous \{
263
	exchange_mode {$tunnel['p1']['mode']};
264
	my_identifier {$myidentt} "{$myident}";
265
	initial_contact on;
266
	passive on;
267
	generate_policy on;
268
	support_proxy on;
269
	proposal_check obey;
270

    
271
	proposal \{
272
		encryption_algorithm {$tunnel['p1']['encryption-algorithm']};
273
		hash_algorithm {$tunnel['p1']['hash-algorithm']};
274
		authentication_method pre_shared_key;
275
		dh_group {$tunnel['p1']['dhgroup']};
276

    
277
EOD;
278
				if ($tunnel['p1']['lifetime'])
279
					$racoonconf .= "		lifetime time {$tunnel['p1']['lifetime']} secs;\n";
280

    
281
				$racoonconf .= "	}\n";
282

    
283
				if ($tunnel['p1']['lifetime'])
284
					$racoonconf .= "	lifetime time {$tunnel['p1']['lifetime']} secs;\n";
285

    
286
				$racoonconf .= "}\n\n";
287

    
288
				$p2ealgos = join(",", $tunnel['p2']['encryption-algorithm-option']);
289
				$p2halgos = join(",", $tunnel['p2']['hash-algorithm-option']);
290

    
291
				$racoonconf .= <<<EOD
292
sainfo anonymous \{
293
	encryption_algorithm {$p2ealgos};
294
	authentication_algorithm {$p2halgos};
295
	compression_algorithm deflate;
296

    
297
EOD;
298

    
299
				if ($tunnel['p2']['pfsgroup'])
300
					$racoonconf .= "	pfs_group {$tunnel['p2']['pfsgroup']};\n";
301

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

    
305
				$racoonconf .= "}\n\n";
306
			}
307

    
308
			fwrite($fd, $racoonconf);
309
			fclose($fd);
310

    
311
			/* generate psk.txt */
312
			$fd = fopen("{$g['varetc_path']}/psk.txt", "w");
313
			if (!$fd) {
314
				printf("Error: cannot open psk.txt in vpn_ipsec_configure().\n");
315
				return 1;
316
			}
317

    
318
			$pskconf = "";
319

    
320
			if (is_array($ipseccfg['tunnel'])) {
321
				foreach ($ipseccfg['tunnel'] as $tunnel) {
322
					if (isset($tunnel['disabled']))
323
						continue;
324
					$pskconf .= "{$tunnel['remote-gateway']}	 {$tunnel['p1']['pre-shared-key']}\n";
325
				}
326
			}
327

    
328
			/* add PSKs for mobile clients */
329
			if (is_array($ipseccfg['mobilekey'])) {
330
				foreach ($ipseccfg['mobilekey'] as $key) {
331
					$pskconf .= "{$key['ident']}	{$key['pre-shared-key']}\n";
332
				}
333
			}
334

    
335
			fwrite($fd, $pskconf);
336
			fclose($fd);
337
			chmod("{$g['varetc_path']}/psk.txt", 0600);
338

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

    
342
			foreach ($ipseccfg['tunnel'] as $tunnel) {
343
				if (isset($tunnel['auto'])) {
344
					$remotehost = substr($tunnel['remote-subnet'],0,strpos($tunnel['remote-subnet'],"/"));
345
					$srchost = vpn_endpoint_determine($tunnel, $curwanip);
346
					if ($srchost)
347
						mwexec_bg("/sbin/ping -c 1 -S {$srchost} {$remotehost}");
348
				}
349
			}
350
		}
351
	}
352

    
353
	if (!$g['booting']) {
354
		/* reload the filter */
355
		filter_configure();
356
	}
357

    
358
	if ($g['booting'])
359
		echo "done\n";
360

    
361
	return 0;
362
}
363

    
364
function vpn_pptpd_configure() {
365
	global $config, $g;
366

    
367
	$syscfg = $config['system'];
368
	$pptpdcfg = $config['pptpd'];
369

    
370
	if ($g['booting']) {
371
		if (!$pptpdcfg['mode'] || ($pptpdcfg['mode'] == "off"))
372
			return 0;
373

    
374
		echo "Configuring PPTP VPN service... ";
375
	} else {
376
		/* kill mpd */
377
		killbypid("{$g['varrun_path']}/mpd-vpn.pid");
378

    
379
		/* wait for process to die */
380
		sleep(2);
381

    
382
		/* remove mpd.conf, if it exists */
383
		unlink_if_exists("{$g['varetc_path']}/mpd-vpn/mpd.conf");
384
		unlink_if_exists("{$g['varetc_path']}/mpd-vpn/mpd.links");
385
		unlink_if_exists("{$g['varetc_path']}/mpd-vpn/mpd.secret");
386
	}
387

    
388
	/* make sure mpd-vpn directory exists */
389
	if (!file_exists("{$g['varetc_path']}/mpd-vpn"))
390
		mkdir("{$g['varetc_path']}/mpd-vpn");
391

    
392
	switch ($pptpdcfg['mode']) {
393

    
394
		case 'server':
395

    
396
			/* write mpd.conf */
397
			$fd = fopen("{$g['varetc_path']}/mpd-vpn/mpd.conf", "w");
398
			if (!$fd) {
399
				printf("Error: cannot open mpd.conf in vpn_pptpd_configure().\n");
400
				return 1;
401
			}
402

    
403
			$mpdconf = <<<EOD
404
pptpd:
405

    
406
EOD;
407

    
408
			for ($i = 0; $i < $g['n_pptp_units']; $i++) {
409
				$mpdconf .= "	load pt{$i}\n";
410
			}
411

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

    
414
				$clientip = long2ip(ip2long($pptpdcfg['remoteip']) + $i);
415
				$ngif = "ng" . ($i+1);
416

    
417
				$mpdconf .= <<<EOD
418

    
419
pt{$i}:
420
	new -i {$ngif} pt{$i} pt{$i}
421
	set ipcp ranges {$pptpdcfg['localip']}/32 {$clientip}/32
422
	load pts
423

    
424
EOD;
425
			}
426

    
427
			$mpdconf .= <<<EOD
428

    
429
pts:
430
	set iface disable on-demand
431
	set iface enable proxy-arp
432
	set iface enable tcpmssfix
433
	set iface idle 1800
434
	set iface up-script /usr/local/sbin/vpn-linkup
435
	set iface down-script /usr/local/sbin/vpn-linkdown
436
	set bundle enable multilink
437
	set bundle enable crypt-reqd
438
	set link yes acfcomp protocomp
439
	set link no pap chap
440
	set link enable chap-msv2
441
	set link mtu 1460
442
	set link keep-alive 10 60
443
	set ipcp yes vjcomp
444
	set bundle enable compression
445
	set ccp yes mppc
446
	set ccp yes mpp-e128
447
	set ccp yes mpp-stateless
448

    
449
EOD;
450

    
451
			if (!isset($pptpdcfg['req128'])) {
452
				$mpdconf .= <<<EOD
453
	set ccp yes mpp-e40
454
	set ccp yes mpp-e56
455

    
456
EOD;
457
			}
458

    
459
			if (isset($config['dnsmasq']['enable'])) {
460
				$mpdconf .= "	set ipcp dns " . $config['interfaces']['lan']['ipaddr'];
461
				if ($syscfg['dnsserver'][0])
462
					$mpdconf .= " " . $syscfg['dnsserver'][0];
463
				$mpdconf .= "\n";
464
			} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
465
				$mpdconf .= "	set ipcp dns " . join(" ", $syscfg['dnsserver']) . "\n";
466
			}
467

    
468
			if (isset($pptpdcfg['radius']['enable'])) {
469
				$mpdconf .= <<<EOD
470
	set radius server {$pptpdcfg['radius']['server']} "{$pptpdcfg['radius']['secret']}"
471
	set radius retries 3
472
	set radius timeout 10
473
	set bundle enable radius-auth
474
	set bundle disable radius-fallback
475

    
476
EOD;
477

    
478
				if (isset($pptpdcfg['radius']['accounting'])) {
479
					$mpdconf .= <<<EOD
480
	set bundle enable radius-acct
481

    
482
EOD;
483
				}
484
			}
485

    
486
			fwrite($fd, $mpdconf);
487
			fclose($fd);
488

    
489
			/* write mpd.links */
490
			$fd = fopen("{$g['varetc_path']}/mpd-vpn/mpd.links", "w");
491
			if (!$fd) {
492
				printf("Error: cannot open mpd.links in vpn_pptpd_configure().\n");
493
				return 1;
494
			}
495

    
496
			$mpdlinks = "";
497

    
498
			for ($i = 0; $i < $g['n_pptp_units']; $i++) {
499
				$mpdlinks .= <<<EOD
500

    
501
pt{$i}:
502
	set link type pptp
503
	set pptp enable incoming
504
	set pptp disable originate
505
	set pptp disable windowing
506
	set pptp self 127.0.0.1
507

    
508
EOD;
509
			}
510

    
511
			fwrite($fd, $mpdlinks);
512
			fclose($fd);
513

    
514
			/* write mpd.secret */
515
			$fd = fopen("{$g['varetc_path']}/mpd-vpn/mpd.secret", "w");
516
			if (!$fd) {
517
				printf("Error: cannot open mpd.secret in vpn_pptpd_configure().\n");
518
				return 1;
519
			}
520

    
521
			$mpdsecret = "";
522

    
523
			if (is_array($pptpdcfg['user'])) {
524
				foreach ($pptpdcfg['user'] as $user)
525
					$mpdsecret .= "{$user['name']} \"{$user['password']}\" {$user['ip']}\n";
526
			}
527

    
528
			fwrite($fd, $mpdsecret);
529
			fclose($fd);
530
			chmod("{$g['varetc_path']}/mpd-vpn/mpd.secret", 0600);
531

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

    
535
			break;
536

    
537
		case 'redir':
538
			break;
539
	}
540

    
541
	if (!$g['booting']) {
542
		/* reload the filter */
543
		filter_configure();
544
	}
545

    
546
	if ($g['booting'])
547
		echo "done\n";
548

    
549
	return 0;
550
}
551

    
552
function vpn_localnet_determine($adr, &$sa, &$sn) {
553
	global $config, $g;
554

    
555
	if (isset($adr)) {
556
		if ($adr['network']) {
557
			switch ($adr['network']) {
558
				case 'lan':
559
					$sn = $config['interfaces']['lan']['subnet'];
560
					$sa = gen_subnet($config['interfaces']['lan']['ipaddr'], $sn);
561
					break;
562
			}
563
		} else if ($adr['address']) {
564
			list($sa,$sn) = explode("/", $adr['address']);
565
			if (is_null($sn))
566
				$sn = 32;
567
		}
568
	} else {
569
		$sn = $config['interfaces']['lan']['subnet'];
570
		$sa = gen_subnet($config['interfaces']['lan']['ipaddr'], $sn);
571
	}
572
}
573

    
574
function vpn_endpoint_determine($tunnel, $curwanip) {
575

    
576
	global $g, $config;
577

    
578
	if ((!$tunnel['interface']) || ($tunnel['interface'] == "wan")) {
579
		if ($curwanip)
580
			return $curwanip;
581
		else
582
			return null;
583
	} else if ($tunnel['interface'] == "lan") {
584
		return $config['interfaces']['lan']['ipaddr'];
585
	} else {
586
		$oc = $config['interfaces'][$tunnel['interface']];
587

    
588
		if (isset($oc['enable']) && $oc['if']) {
589
			return $oc['ipaddr'];
590
		}
591
	}
592

    
593
	return null;
594
}
595

    
596
?>
(13-13/14)