Project

General

Profile

Download (15.9 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 = "";
169

    
170
			if($config['ipsec']['interface'] <> "") {
171
				if(does_interface_exist($config['ipsec']['interface']) == true) {
172
					$interface_ip = find_interface_ip($config['ipsec']['interface']);
173
					$racoonconf .= <<<EOD
174
listen {
175
	isakmp {$interface_ip} [500];
176
}
177

    
178
EOD;
179
				}
180

    
181
			}
182

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

    
185
			if (is_array($ipseccfg['tunnel']) && count($ipseccfg['tunnel']))
186
				foreach ($ipseccfg['tunnel'] as $tunnel) {
187

    
188
				if (isset($tunnel['disabled']))
189
					continue;
190

    
191
				$ep = vpn_endpoint_determine($tunnel, $curwanip);
192
				if (!$ep)
193
					continue;
194

    
195
				vpn_localnet_determine($tunnel['local-subnet'], $sa, $sn);
196

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

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

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

    
226
EOD;
227
				if ($tunnel['p1']['lifetime'])
228
					$racoonconf .= "		lifetime time {$tunnel['p1']['lifetime']} secs;\n";
229

    
230
				$racoonconf .= "	}\n";
231

    
232
				if ($tunnel['p1']['lifetime'])
233
					$racoonconf .= "	lifetime time {$tunnel['p1']['lifetime']} secs;\n";
234

    
235
				$racoonconf .= "}\n\n";
236

    
237
				$p2ealgos = join(",", $tunnel['p2']['encryption-algorithm-option']);
238
				$p2halgos = join(",", $tunnel['p2']['hash-algorithm-option']);
239

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

    
246
EOD;
247

    
248
				if ($tunnel['p2']['pfsgroup'])
249
					$racoonconf .= "	pfs_group {$tunnel['p2']['pfsgroup']};\n";
250

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

    
254
				$racoonconf .= "}\n\n";
255
			}
256

    
257
			/* mobile clients? */
258
			if (isset($ipseccfg['mobileclients']['enable'])) {
259

    
260
				$tunnel = $ipseccfg['mobileclients'];
261

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

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

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

    
292
EOD;
293
				if ($tunnel['p1']['lifetime'])
294
					$racoonconf .= "		lifetime time {$tunnel['p1']['lifetime']} secs;\n";
295

    
296
				$racoonconf .= "	}\n";
297

    
298
				if ($tunnel['p1']['lifetime'])
299
					$racoonconf .= "	lifetime time {$tunnel['p1']['lifetime']} secs;\n";
300

    
301
				$racoonconf .= "}\n\n";
302

    
303
				$p2ealgos = join(",", $tunnel['p2']['encryption-algorithm-option']);
304
				$p2halgos = join(",", $tunnel['p2']['hash-algorithm-option']);
305

    
306
				$racoonconf .= <<<EOD
307
sainfo anonymous \{
308
	encryption_algorithm {$p2ealgos};
309
	authentication_algorithm {$p2halgos};
310
	compression_algorithm deflate;
311

    
312
EOD;
313

    
314
				if ($tunnel['p2']['pfsgroup'])
315
					$racoonconf .= "	pfs_group {$tunnel['p2']['pfsgroup']};\n";
316

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

    
320
				$racoonconf .= "}\n\n";
321
			}
322

    
323
			fwrite($fd, $racoonconf);
324
			fclose($fd);
325

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

    
333
			$pskconf = "";
334

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

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

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

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

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

    
368
	if (!$g['booting']) {
369
		/* reload the filter */
370
		filter_configure();
371
	}
372

    
373
	if ($g['booting'])
374
		echo "done\n";
375

    
376
	return 0;
377
}
378

    
379
function vpn_pptpd_configure() {
380
	global $config, $g;
381

    
382
	$syscfg = $config['system'];
383
	$pptpdcfg = $config['pptpd'];
384

    
385
	if ($g['booting']) {
386
		if (!$pptpdcfg['mode'] || ($pptpdcfg['mode'] == "off"))
387
			return 0;
388

    
389
		echo "Configuring PPTP VPN service... ";
390
	} else {
391
		/* kill mpd */
392
		killbypid("{$g['varrun_path']}/mpd-vpn.pid");
393

    
394
		/* wait for process to die */
395
		sleep(2);
396

    
397
		/* remove mpd.conf, if it exists */
398
		unlink_if_exists("{$g['varetc_path']}/mpd-vpn/mpd.conf");
399
		unlink_if_exists("{$g['varetc_path']}/mpd-vpn/mpd.links");
400
		unlink_if_exists("{$g['varetc_path']}/mpd-vpn/mpd.secret");
401
	}
402

    
403
	/* make sure mpd-vpn directory exists */
404
	if (!file_exists("{$g['varetc_path']}/mpd-vpn"))
405
		mkdir("{$g['varetc_path']}/mpd-vpn");
406

    
407
	switch ($pptpdcfg['mode']) {
408

    
409
		case 'server':
410

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

    
418
			$mpdconf = <<<EOD
419
pptpd:
420

    
421
EOD;
422

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

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

    
429
				$clientip = long2ip(ip2long($pptpdcfg['remoteip']) + $i);
430
				$ngif = "ng" . ($i+1);
431

    
432
				$mpdconf .= <<<EOD
433

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

    
439
EOD;
440
			}
441

    
442
			$mpdconf .= <<<EOD
443

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

    
464
EOD;
465

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

    
471
EOD;
472
			}
473

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

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

    
491
EOD;
492

    
493
				if (isset($pptpdcfg['radius']['accounting'])) {
494
					$mpdconf .= <<<EOD
495
	set bundle enable radius-acct
496

    
497
EOD;
498
				}
499
			}
500

    
501
			fwrite($fd, $mpdconf);
502
			fclose($fd);
503

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

    
511
			$mpdlinks = "";
512

    
513
			for ($i = 0; $i < $g['n_pptp_units']; $i++) {
514
				$mpdlinks .= <<<EOD
515

    
516
pt{$i}:
517
	set link type pptp
518
	set pptp enable incoming
519
	set pptp disable originate
520
	set pptp disable windowing
521
	set pptp self 127.0.0.1
522

    
523
EOD;
524
			}
525

    
526
			fwrite($fd, $mpdlinks);
527
			fclose($fd);
528

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

    
536
			$mpdsecret = "";
537

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

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

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

    
550
			break;
551

    
552
		case 'redir':
553
			break;
554
	}
555

    
556
	if (!$g['booting']) {
557
		/* reload the filter */
558
		filter_configure();
559
	}
560

    
561
	if ($g['booting'])
562
		echo "done\n";
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
?>
(13-13/14)