vpn.inc 20.1 KB
Newer Older
Ad Schellevis's avatar
Ad Schellevis committed
1 2 3
<?php

/*
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 * Coypright (C) 2016 Franco Fichtner <franco@opnsense.org>
 * Copyright (C) 2008 Shrew Soft Inc
 * Copyright (C) 2008 Ermal Luçi
 * Copyright (C) 2004 Scott Ullrich
 * Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
Ad Schellevis's avatar
Ad Schellevis committed
32

33 34 35 36 37
function vpn_configure()
{
    return array(
        'vpn_pptpd_configure',
        'vpn_pppoes_configure',
38
        'vpn_l2tp_configure',
39 40 41
    );
}

42 43 44 45 46 47
function vpn_services()
{
    global $config;

    $services = array();

48
    if (isset($config['pptpd']['mode']) && $config['pptpd']['mode'] == 'server') {
49 50 51
        $services[] = array(
            'description' => gettext('PPTP Server'),
            'pidfile' => '/var/run/pptp-vpn.pid',
52 53 54 55
            'php' => array(
                'restart' => array('vpn_pptpd_configure'),
                'start' => array('vpn_pptpd_configure'),
            ),
56 57
            'name' => 'pptpd',
        );
58 59
    }

60
    if (isset($config['l2tp']['mode']) && $config['l2tp']['mode'] == 'server') {
61 62 63
        $services[] = array(
            'description' => gettext('L2TP Server'),
            'pidfile' => '/var/run/l2tp-vpn.pid',
64 65 66 67
            'php' => array(
                'restart' => array('vpn_l2tp_configure'),
                'start' => array('vpn_l2tp_configure'),
            ),
68 69
            'name' => 'l2tpd',
        );
70 71
    }

72 73
    if (isset($config['pppoes']['pppoe'])) {
        foreach ($config['pppoes']['pppoe'] as $pppoecfg) {
74
            if (isset($pppoecfg['mode']) && $pppoecfg['mode'] == 'server') {
75 76 77 78 79
                $services[] = array(
                    'description' => gettext('PPPoE Server') . ': ' . htmlspecialchars($pppoecfg['descr']),
                    'php' => array(
                        'restart' => array('vpn_pppoe_configure_by_id'),
                        'start' => array('vpn_pppoe_configure_by_id'),
80
                        'args' => array('id'),
81 82
                    ),
                    'pidfile' => "/var/run/pppoe{$pppoecfg['pppoeid']}-vpn.pid",
83
                    'id' => $pppoecfg['pppoeid'],
84 85 86
                    'name' => 'pppoed',
                );
            }
Ad Schellevis's avatar
Ad Schellevis committed
87
        }
88
    }
89

90
    return $services;
91 92
}

93 94 95 96 97 98 99 100 101 102 103 104 105
/**
 * request syslog facilities for this plugin
 * @return array
 */
function vpn_syslog()
{
    $logfacilities = array();
    $logfacilities['pptps'] = array("facility" => array('pptps'), "remote" => null);
    $logfacilities['poes'] = array("facility" => array('poes'), "remote" => null);
    $logfacilities['l2tps'] = array("facility" => array('l2tps'), "remote" => null);
    return $logfacilities;
}

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
function vpn_link_scripts($rootdir, $logtype)
{
    $up = <<<'EOD'
#!/bin/sh

/usr/bin/logger -p local3.info "login,%s,$4,$5"

EOD;
    $down = <<<'EOD'
#!/bin/sh

/usr/bin/logger -p local3.info "logout,%s,$4,$5"

/sbin/pfctl -i $1 -Fs
/sbin/pfctl -K $4/32

EOD;

    file_put_contents($rootdir . '/linkup', sprintf($up, $logtype));
    file_put_contents($rootdir . '/linkdown', sprintf($down, $logtype));

    chmod($rootdir . '/linkup', 0755);
    chmod($rootdir . '/linkdown', 0755);
}

131 132
function vpn_pptpd_configure()
{
Franco Fichtner's avatar
Franco Fichtner committed
133
    global $config;
134

Franco Fichtner's avatar
Franco Fichtner committed
135 136
    $syscfg = $config['system'];
    $pptpdcfg = $config['pptpd'];
137

Franco Fichtner's avatar
Franco Fichtner committed
138
    killbypid('/var/run/pptp-vpn.pid', 'TERM', true);
139
    mwexec('rm -rf /var/etc/pptp-vpn');
140

Franco Fichtner's avatar
Franco Fichtner committed
141 142 143
    if (!isset($pptpdcfg['mode']) || $pptpdcfg['mode'] == 'off') {
        return 0;
    }
144

Franco Fichtner's avatar
Franco Fichtner committed
145 146 147
    if (file_exists('/var/run/booting')) {
        echo gettext("Configuring PPTP VPN service...");
    }
148

Franco Fichtner's avatar
Franco Fichtner committed
149 150 151 152
    if (empty($pptpdcfg['n_pptp_units'])) {
        log_error("Something wrong in the PPTPd configuration. Preventing starting the daemon because issues would arise.");
        return;
    }
153

Franco Fichtner's avatar
Franco Fichtner committed
154 155
    switch ($pptpdcfg['mode']) {
        case 'server':
156 157 158
            mkdir('/var/etc/pptp-vpn');
            vpn_link_scripts('/var/etc/pptp-vpn', 'pptp');

Franco Fichtner's avatar
Franco Fichtner committed
159 160 161 162 163 164
            $fd = fopen('/var/etc/pptp-vpn/mpd.conf', 'w');
            if (!$fd) {
                printf(gettext("Error: cannot open mpd.conf in vpn_pptpd_configure().") . "\n");
                return 1;
            }

165 166
            $iprange = $pptpdcfg['remoteip'] . ' ';
            $iprange .= long2ip32(ip2long($pptpdcfg['remoteip']) + $pptpdcfg['n_pptp_units'] - 1);
Ad Schellevis's avatar
Ad Schellevis committed
167

168 169
            $mpdconf = <<<EOD
startup:
Ad Schellevis's avatar
Ad Schellevis committed
170

171 172
pptps:
  set ippool add pool1 {$iprange}
Ad Schellevis's avatar
Ad Schellevis committed
173

174
  create bundle template B
175 176 177 178
  set iface disable on-demand
  set iface enable proxy-arp
  set iface enable tcpmssfix
  set iface idle 1800
179 180
  set iface up-script /var/etc/pptp-vpn/linkup
  set iface down-script /var/etc/pptp-vpn/linkdown
181
  set ipcp ranges {$pptpdcfg['localip']}/32 ippool pool1
182
  set ipcp yes vjcomp
Ad Schellevis's avatar
Ad Schellevis committed
183 184

EOD;
Franco Fichtner's avatar
Franco Fichtner committed
185 186 187 188 189 190 191 192 193 194

            if (isset($pptpdcfg["wins"]) && $pptpdcfg['wins'] != "") {
                $mpdconf  .=  "  set ipcp nbns {$pptpdcfg['wins']}\n";
            }
            if (!empty($pptpdcfg['dns1'])) {
                $mpdconf .= "  set ipcp dns " . $pptpdcfg['dns1'];
                if (!empty($pptpdcfg['dns2'])) {
                    $mpdconf .= " " . $pptpdcfg['dns2'];
                }
                $mpdconf .= "\n";
195
            } elseif (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
Franco Fichtner's avatar
Franco Fichtner committed
196
                $mpdconf .= "  set ipcp dns " . get_interface_ip("lan");
197
                if (isset($syscfg['dnsserver'][0])) {
Franco Fichtner's avatar
Franco Fichtner committed
198 199 200
                    $mpdconf .= " " . $syscfg['dnsserver'][0];
                }
                $mpdconf .= "\n";
201
            } elseif (isset($syscfg['dnsserver'][0])) {
Franco Fichtner's avatar
Franco Fichtner committed
202 203 204
                $mpdconf .= "  set ipcp dns " . join(" ", $syscfg['dnsserver']) . "\n";
            }

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
            $mpdconf .= <<<EOD

  set bundle enable crypt-reqd
  set bundle enable compression
  set ccp yes mppc
  set mppc yes e128
  set mppc yes stateless

EOD;

            if (!isset($pptpdcfg['req128'])) {
                $mpdconf .=<<<EOD
  set mppc yes e40
  set mppc yes e56

EOD;
            }

            $mpdconf .= <<<EOD

  create link template L pptp
  set link action bundle B
  set link enable multilink
  set link yes acfcomp protocomp
229
  set link no pap chap eap
230 231 232
  set link enable chap-msv2
  set link mtu 1460
  set link keep-alive 10 60
233
  set pptp self {$pptpdcfg['localip']}
234 235 236 237
  set link enable incoming

EOD;

Franco Fichtner's avatar
Franco Fichtner committed
238 239 240 241
            if (isset($pptpdcfg['radius']['server']['enable'])) {
                $authport = (isset($pptpdcfg['radius']['server']['port']) && strlen($pptpdcfg['radius']['server']['port']) > 1) ? $pptpdcfg['radius']['server']['port'] : 1812;
                $acctport = $authport + 1;
                $mpdconf .=<<<EOD
242
  set radius server {$pptpdcfg['radius']['server']['ip']} "{$pptpdcfg['radius']['server']['secret']}" {$authport} {$acctport}
Ad Schellevis's avatar
Ad Schellevis committed
243 244

EOD;
Franco Fichtner's avatar
Franco Fichtner committed
245 246 247 248
                if (isset($pptpdcfg['radius']['server2']['enable'])) {
                    $authport = (isset($pptpdcfg['radius']['server2']['port']) && strlen($pptpdcfg['radius']['server2']['port']) > 1) ? $pptpdcfg['radius']['server2']['port'] : 1812;
                    $acctport = $authport + 1;
                    $mpdconf .=<<<EOD
249
  set radius server {$pptpdcfg['radius']['server2']['ip']} "{$pptpdcfg['radius']['server2']['secret2']}" {$authport} {$acctport}
Ad Schellevis's avatar
Ad Schellevis committed
250 251

EOD;
Franco Fichtner's avatar
Franco Fichtner committed
252 253
                }
                $mpdconf .=<<<EOD
254 255 256
  set radius retries 3
  set radius timeout 10
  set auth enable radius-auth
Ad Schellevis's avatar
Ad Schellevis committed
257 258 259

EOD;

Franco Fichtner's avatar
Franco Fichtner committed
260 261
                if (isset($pptpdcfg['radius']['accounting'])) {
                    $mpdconf .=<<<EOD
262 263
  set auth enable radius-acct
  set radius acct-update 300
Ad Schellevis's avatar
Ad Schellevis committed
264 265

EOD;
Franco Fichtner's avatar
Franco Fichtner committed
266 267
                }
            }
Ad Schellevis's avatar
Ad Schellevis committed
268

Franco Fichtner's avatar
Franco Fichtner committed
269 270 271
            fwrite($fd, $mpdconf);
            fclose($fd);
            unset($mpdconf);
Ad Schellevis's avatar
Ad Schellevis committed
272

Franco Fichtner's avatar
Franco Fichtner committed
273 274 275 276 277
            $fd = fopen('/var/etc/pptp-vpn/mpd.secret', 'w');
            if (!$fd) {
                printf(gettext("Error: cannot open mpd.secret in vpn_pptpd_configure().") . "\n");
                return 1;
            }
Ad Schellevis's avatar
Ad Schellevis committed
278

Franco Fichtner's avatar
Franco Fichtner committed
279
            $mpdsecret = "";
Ad Schellevis's avatar
Ad Schellevis committed
280

Franco Fichtner's avatar
Franco Fichtner committed
281 282 283 284 285 286 287 288 289 290 291 292 293
            if (is_array($pptpdcfg['user'])) {
                foreach ($pptpdcfg['user'] as $user) {
                    $pass = str_replace('\\', '\\\\', $user['password']);
                    $pass = str_replace('"', '\"', $pass);
                    $mpdsecret .= "{$user['name']} \"{$pass}\" {$user['ip']}\n";
                }
            }

            fwrite($fd, $mpdsecret);
            fclose($fd);
            unset($mpdsecret);
            chmod('/var/etc/pptp-vpn/mpd.secret', 0600);

294
            /* fixed to WAN elsewhere, no need to extend, but at least make it work */
Franco Fichtner's avatar
Franco Fichtner committed
295 296 297 298 299
            legacy_netgraph_attach(get_real_interface('wan'));

            mwexec('/usr/local/sbin/mpd5 -b -d /var/etc/pptp-vpn -p /var/run/pptp-vpn.pid -s pptps pptps');

            break;
Ad Schellevis's avatar
Ad Schellevis committed
300

Franco Fichtner's avatar
Franco Fichtner committed
301 302 303
        case 'redir':
            break;
    }
Ad Schellevis's avatar
Ad Schellevis committed
304

Franco Fichtner's avatar
Franco Fichtner committed
305 306 307
    if (file_exists('/var/run/booting')) {
        echo gettext("done") . "\n";
    }
Ad Schellevis's avatar
Ad Schellevis committed
308

Franco Fichtner's avatar
Franco Fichtner committed
309
    return 0;
Ad Schellevis's avatar
Ad Schellevis committed
310 311
}

312 313 314
function vpn_pppoes_configure()
{
    global $config;
Ad Schellevis's avatar
Ad Schellevis committed
315

316 317 318
    if (isset($config['pppoes']['pppoe'])) {
        foreach ($config['pppoes']['pppoe'] as $pppoe) {
            vpn_pppoe_configure($pppoe);
Franco Fichtner's avatar
Franco Fichtner committed
319
        }
320
    }
Ad Schellevis's avatar
Ad Schellevis committed
321 322
}

323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
function vpn_pppoe_configure_by_id($id)
{
    global $config;

    $found = null;

    if (isset($config['pppoes']['pppoe'])) {
        foreach ($config['pppoes']['pppoe'] as $pppoe) {
            if ($id != 0 && $id == $pppoe['pppoeid']) {
                $found = $pppoe;
                break;
            }
        }
    }

    if ($found == null) {
        return;
    }

    vpn_pppoe_configure($found);
}

345 346
function vpn_pppoe_configure(&$pppoecfg)
{
Franco Fichtner's avatar
Franco Fichtner committed
347
    global $config;
Ad Schellevis's avatar
Ad Schellevis committed
348

Franco Fichtner's avatar
Franco Fichtner committed
349
    $syscfg = $config['system'];
Ad Schellevis's avatar
Ad Schellevis committed
350

Franco Fichtner's avatar
Franco Fichtner committed
351
    killbypid("/var/run/pppoe{$pppoecfg['pppoeid']}-vpn.pid", 'TERM', true);
352
    mwexec("rm -rf /var/etc/pppoe{$pppoecfg['pppoeid']}-vpn");
Ad Schellevis's avatar
Ad Schellevis committed
353

Franco Fichtner's avatar
Franco Fichtner committed
354 355 356
    if (!isset($pppoecfg['mode']) || $pppoecfg['mode'] == 'off') {
        return 0;
    }
Ad Schellevis's avatar
Ad Schellevis committed
357

Franco Fichtner's avatar
Franco Fichtner committed
358 359 360
    if (file_exists('/var/run/booting')) {
        echo gettext("Configuring PPPoE VPN service...");
    }
Ad Schellevis's avatar
Ad Schellevis committed
361

362
    switch ($pppoecfg['mode']) {
Franco Fichtner's avatar
Franco Fichtner committed
363
        case 'server':
364 365 366
            mkdir("/var/etc/pppoe{$pppoecfg['pppoeid']}-vpn");
            vpn_link_scripts("/var/etc/pppoe{$pppoecfg['pppoeid']}-vpn", 'poes');

Franco Fichtner's avatar
Franco Fichtner committed
367
            $pppoe_interface = get_real_interface($pppoecfg['interface']);
Ad Schellevis's avatar
Ad Schellevis committed
368

Franco Fichtner's avatar
Franco Fichtner committed
369 370 371 372 373
            $fd = fopen("/var/etc/pppoe{$pppoecfg['pppoeid']}-vpn/mpd.conf", "w");
            if (!$fd) {
                printf(gettext("Error: cannot open mpd.conf in vpn_pppoe_configure().") . "\n");
                return 1;
            }
Ad Schellevis's avatar
Ad Schellevis committed
374

375 376
            $iprange = $pppoecfg['remoteip'] . ' ';
            $iprange .= long2ip32(ip2long($pppoecfg['remoteip']) + $pppoecfg['n_pppoe_units'] - 1);
Ad Schellevis's avatar
Ad Schellevis committed
377

378 379 380
            $iptype = 'ippool pool1';
            if (isset($pppoecfg['radius']['server']['enable']) && isset($pppoecfg['radius']['radiusissueips'])) {
                $iptype = '0.0.0.0/0';
Franco Fichtner's avatar
Franco Fichtner committed
381
            }
Ad Schellevis's avatar
Ad Schellevis committed
382

383 384
            $mpdconf = <<<EOD
startup:
Ad Schellevis's avatar
Ad Schellevis committed
385

386 387 388
poes:
  set ippool add pool1 {$iprange}
  create bundle template B
389 390
  set iface up-script /var/etc/pppoe{$pppoecfg['pppoeid']}-vpn/linkup
  set iface down-script /var/etc/pppoe{$pppoecfg['pppoeid']}-vpn/linkdown
391 392 393 394 395 396
  set iface idle 0
  set iface disable on-demand
  set iface disable proxy-arp
  set iface enable tcpmssfix
  set iface mtu 1500
  set ipcp no vjcomp
397
  set ipcp ranges {$pppoecfg['localip']}/32 {$iptype}
Ad Schellevis's avatar
Ad Schellevis committed
398 399 400

EOD;

Franco Fichtner's avatar
Franco Fichtner committed
401 402 403 404 405 406
            if (!empty($pppoecfg['dns1'])) {
                $mpdconf .= "  set ipcp dns " . $pppoecfg['dns1'];
                if (!empty($pppoecfg['dns2'])) {
                    $mpdconf .= " " . $pppoecfg['dns2'];
                }
                $mpdconf .= "\n";
407
            } elseif (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
Franco Fichtner's avatar
Franco Fichtner committed
408
                $mpdconf .= "  set ipcp dns " . get_interface_ip("lan");
409
                if (isset($syscfg['dnsserver'][0])) {
Franco Fichtner's avatar
Franco Fichtner committed
410 411 412
                    $mpdconf .= " " . $syscfg['dnsserver'][0];
                }
                $mpdconf .= "\n";
413
            } elseif (isset($syscfg['dnsserver'][0])) {
Franco Fichtner's avatar
Franco Fichtner committed
414 415 416
                $mpdconf .= "  set ipcp dns " . join(" ", $syscfg['dnsserver']) . "\n";
            }

417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
            $mpdconf .= <<<EOD

  set bundle enable compression
  set ccp yes mppc
  set mppc yes e40
  set mppc yes e128
  set mppc yes stateless

  create link template L pppoe
  set link action bundle B
  set link no multilink
  set link disable pap
  set link disable eap
  set link enable chap
  set link keep-alive 10 60
  set link max-redial -1
  set link mtu 1492
  set link mru 1492
  set link latency 1
  set pppoe service pppoe{$pppoecfg['pppoeid']}
  set pppoe iface {$pppoe_interface}
  set link enable incoming
  set auth max-logins 1

EOD;

Franco Fichtner's avatar
Franco Fichtner committed
443 444 445 446 447 448 449 450 451 452
            if (isset($pppoecfg['radius']['server']['enable'])) {
                $radiusport = "";
                $radiusacctport = "";
                if (isset($pppoecfg['radius']['server']['port'])) {
                    $radiusport = $pppoecfg['radius']['server']['port'];
                }
                if (isset($pppoecfg['radius']['server']['acctport'])) {
                    $radiusacctport = $pppoecfg['radius']['server']['acctport'];
                }
                $mpdconf .=<<<EOD
453 454 455 456
  set radius server {$pppoecfg['radius']['server']['ip']} "{$pppoecfg['radius']['server']['secret']}" {$radiusport} {$radiusacctport}
  set radius retries 3
  set radius timeout 10
  set auth enable radius-auth
Ad Schellevis's avatar
Ad Schellevis committed
457 458 459

EOD;

Franco Fichtner's avatar
Franco Fichtner committed
460 461
                if (isset($pppoecfg['radius']['accounting'])) {
                    $mpdconf .=<<<EOD
462
  set auth enable radius-acct
Ad Schellevis's avatar
Ad Schellevis committed
463 464

EOD;
Franco Fichtner's avatar
Franco Fichtner committed
465 466
                }
            }
Ad Schellevis's avatar
Ad Schellevis committed
467

Franco Fichtner's avatar
Franco Fichtner committed
468 469 470
            fwrite($fd, $mpdconf);
            fclose($fd);
            unset($mpdconf);
Ad Schellevis's avatar
Ad Schellevis committed
471

Franco Fichtner's avatar
Franco Fichtner committed
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
            if ($pppoecfg['username']) {
                $fd = fopen("/var/etc/pppoe{$pppoecfg['pppoeid']}-vpn/mpd.secret", "w");
                if (!$fd) {
                    printf(gettext("Error: cannot open mpd.secret in vpn_pppoe_configure().") . "\n");
                    return 1;
                }

                $mpdsecret = "\n\n";

                if (!empty($pppoecfg['username'])) {
                    $item = explode(" ", $pppoecfg['username']);
                    foreach ($item as $userdata) {
                        $data = explode(":", $userdata);
                        $mpdsecret .= "{$data[0]} \"" . base64_decode($data[1]) . "\" {$data[2]}\n";
                    }
                }

                fwrite($fd, $mpdsecret);
                fclose($fd);
                unset($mpdsecret);
                chmod("/var/etc/pppoe{$pppoecfg['pppoeid']}-vpn/mpd.secret", 0600);
            }
494

Franco Fichtner's avatar
Franco Fichtner committed
495
            legacy_netgraph_attach($pppoe_interface);
496

Franco Fichtner's avatar
Franco Fichtner committed
497
            mwexec("/usr/local/sbin/mpd5 -b -d /var/etc/pppoe{$pppoecfg['pppoeid']}-vpn -p /var/run/pppoe{$pppoecfg['pppoeid']}-vpn.pid -s poes poes");
498

Franco Fichtner's avatar
Franco Fichtner committed
499 500
            break;
    }
501

Franco Fichtner's avatar
Franco Fichtner committed
502 503 504
    if (file_exists('/var/run/booting')) {
        echo gettext("done") . "\n";
    }
505

Franco Fichtner's avatar
Franco Fichtner committed
506
    return 0;
Ad Schellevis's avatar
Ad Schellevis committed
507 508
}

509 510
function vpn_l2tp_configure()
{
Franco Fichtner's avatar
Franco Fichtner committed
511
    global $config;
512

Franco Fichtner's avatar
Franco Fichtner committed
513
    killbypid('/var/run/l2tp-vpn.pid', 'TERM', true);
514
    mwexec('rm -rf /var/etc/l2tp-vpn');
515

Franco Fichtner's avatar
Franco Fichtner committed
516 517 518 519 520 521
    $syscfg = $config['system'];
    if (isset($config['l2tp'])) {
        $l2tpcfg = $config['l2tp'];
    } else {
        return 0;
    }
522

Franco Fichtner's avatar
Franco Fichtner committed
523 524 525 526 527 528 529 530
    if (!isset($l2tpcfg['mode']) || $l2tpcfg['mode'] == 'off') {
        return 0;
    }

    if (file_exists('/var/run/booting')) {
        echo gettext('Configuring L2TP VPN service...');
    }

531
    switch ($l2tpcfg['mode']) {
Franco Fichtner's avatar
Franco Fichtner committed
532 533
        case 'server':

534 535 536
            mkdir('/var/etc/l2tp-vpn');
            vpn_link_scripts('/var/etc/l2tp-vpn', 'l2tp');

Franco Fichtner's avatar
Franco Fichtner committed
537 538 539 540 541
            $fd = fopen("/var/etc/l2tp-vpn/mpd.conf", "w");
            if (!$fd) {
                printf(gettext("Error: cannot open mpd.conf in vpn_l2tp_configure().") . "\n");
                return 1;
            }
Ad Schellevis's avatar
Ad Schellevis committed
542

543 544
            $iprange = $l2tpcfg['remoteip'] . ' ';
            $iprange .= long2ip32(ip2long($l2tpcfg['remoteip']) + $l2tpcfg['n_l2tp_units'] - 1);
Ad Schellevis's avatar
Ad Schellevis committed
545

546 547 548
            $iptype = "ippool pool1";
            if (isset($l2tpcfg['radius']['enable']) && isset($l2tpcfg['radius']['radiusissueips'])) {
                $iptype = "0.0.0.0/0";
Franco Fichtner's avatar
Franco Fichtner committed
549
            }
Ad Schellevis's avatar
Ad Schellevis committed
550

551 552
            $mpdconf = <<<EOD
startup:
Ad Schellevis's avatar
Ad Schellevis committed
553

554 555
l2tps:
  set ippool add pool1 {$iprange}
Ad Schellevis's avatar
Ad Schellevis committed
556

557
  create bundle template B
558 559
  set iface disable on-demand
  set iface enable proxy-arp
560 561
  set iface up-script /var/etc/l2tp-vpn/linkup
  set iface down-script /var/etc/l2tp-vpn/linkdown
562 563
  set ipcp ranges {$l2tpcfg['localip']}/32 {$iptype}
  set ipcp yes vjcomp
Ad Schellevis's avatar
Ad Schellevis committed
564 565 566

EOD;

Franco Fichtner's avatar
Franco Fichtner committed
567 568 569 570 571 572 573 574 575
            if (is_ipaddr($l2tpcfg['wins'])) {
                $mpdconf .= "  set ipcp nbns {$l2tpcfg['wins']}\n";
            }
            if (is_ipaddr($l2tpcfg['dns1'])) {
                $mpdconf .= "  set ipcp dns " . $l2tpcfg['dns1'];
                if (is_ipaddr($l2tpcfg['dns2'])) {
                    $mpdconf .= " " . $l2tpcfg['dns2'];
                }
                $mpdconf .= "\n";
576
            } elseif (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
Franco Fichtner's avatar
Franco Fichtner committed
577
                $mpdconf .= "  set ipcp dns " . get_interface_ip("lan");
578
                if (isset($syscfg['dnsserver'][0])) {
Franco Fichtner's avatar
Franco Fichtner committed
579 580 581
                    $mpdconf .= " " . $syscfg['dnsserver'][0];
                }
                $mpdconf .= "\n";
582
            } elseif (isset($syscfg['dnsserver'][0])) {
Franco Fichtner's avatar
Franco Fichtner committed
583 584 585
                $mpdconf .= "  set ipcp dns " . join(" ", $syscfg['dnsserver']) . "\n";
            }

586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
            if ($l2tpcfg['paporchap'] == "chap") {
                $paporchap = "set link enable chap";
            } else {
                $paporchap = "set link enable pap";
            }

            $mpdconf .= <<<EOD

  set bundle enable crypt-reqd
  set bundle enable compression
  set ccp yes mppc

  create link template L l2tp
  set link action bundle B
  set link enable multilink
  set link yes acfcomp protocomp
  set link no pap chap eap
  {$paporchap}
  set link keep-alive 10 60
  set link mtu 1460
  set l2tp self ${l2tpcfg['localip']}
  set link enable incoming

EOD;

            if (!empty($l2tpcfg['secret'])) {
                $mpdconf .= "  set l2tp secret {$l2tpcfg['secret']}\n";
            }

Franco Fichtner's avatar
Franco Fichtner committed
615 616
            if (isset($l2tpcfg['radius']['enable'])) {
                $mpdconf .=<<<EOD
617 618 619 620
  set radius server {$l2tpcfg['radius']['server']} "{$l2tpcfg['radius']['secret']}"
  set radius retries 3
  set radius timeout 10
  set auth enable radius-auth
Ad Schellevis's avatar
Ad Schellevis committed
621 622 623

EOD;

Franco Fichtner's avatar
Franco Fichtner committed
624 625
                if (isset($l2tpcfg['radius']['accounting'])) {
                    $mpdconf .=<<<EOD
626
  set auth enable radius-acct
Ad Schellevis's avatar
Ad Schellevis committed
627 628

EOD;
Franco Fichtner's avatar
Franco Fichtner committed
629 630
                }
            }
Ad Schellevis's avatar
Ad Schellevis committed
631

Franco Fichtner's avatar
Franco Fichtner committed
632 633 634
            fwrite($fd, $mpdconf);
            fclose($fd);
            unset($mpdconf);
Ad Schellevis's avatar
Ad Schellevis committed
635

Franco Fichtner's avatar
Franco Fichtner committed
636 637 638 639 640
            $fd = fopen("/var/etc/l2tp-vpn/mpd.secret", "w");
            if (!$fd) {
                printf(gettext("Error: cannot open mpd.secret in vpn_l2tp_configure().") . "\n");
                return 1;
            }
Ad Schellevis's avatar
Ad Schellevis committed
641

Franco Fichtner's avatar
Franco Fichtner committed
642
            $mpdsecret = "\n\n";
Ad Schellevis's avatar
Ad Schellevis committed
643

Franco Fichtner's avatar
Franco Fichtner committed
644 645 646 647 648
            if (is_array($l2tpcfg['user'])) {
                foreach ($l2tpcfg['user'] as $user) {
                    $mpdsecret .= "{$user['name']} \"{$user['password']}\" {$user['ip']}\n";
                }
            }
Ad Schellevis's avatar
Ad Schellevis committed
649

Franco Fichtner's avatar
Franco Fichtner committed
650 651 652 653
            fwrite($fd, $mpdsecret);
            fclose($fd);
            unset($mpdsecret);
            chmod('/var/etc/l2tp-vpn/mpd.secret', 0600);
Ad Schellevis's avatar
Ad Schellevis committed
654

Franco Fichtner's avatar
Franco Fichtner committed
655
            legacy_netgraph_attach(get_real_interface($l2tpcfg['interface']));
Ad Schellevis's avatar
Ad Schellevis committed
656

Franco Fichtner's avatar
Franco Fichtner committed
657
            mwexec('/usr/local/sbin/mpd5 -b -d /var/etc/l2tp-vpn -p /var/run/l2tp-vpn.pid -s l2tps l2tps');
Ad Schellevis's avatar
Ad Schellevis committed
658

Franco Fichtner's avatar
Franco Fichtner committed
659 660
            break;
    }
Ad Schellevis's avatar
Ad Schellevis committed
661

Franco Fichtner's avatar
Franco Fichtner committed
662 663 664
    if (file_exists('/var/run/booting')) {
        echo gettext("done") . "\n";
    }
Ad Schellevis's avatar
Ad Schellevis committed
665

Franco Fichtner's avatar
Franco Fichtner committed
666
    return 0;
Ad Schellevis's avatar
Ad Schellevis committed
667
}