<?php

########## This script requires preinstallation of php 5.2.0 or higher and pip-zip prior to running
########## This script installs PIA VPN using OpenVPN and sets up a killswitch using iptables
########## This script needs to be run as root.

###################################################################################################################################
############################################################ VARIABLES ############################################################
###################################################################################################################################

$PiaUsername = "username";                                                      // PIA Username
$PiaPassword = "password";                                                      // PIA Password

// Name of the network interface
$NetworkInterfaceName = "enp0s3";                                               // Network interface name

// UDP Ports that are left open.  Default ports are 53 for DNS and 1197 for VPN which are both UDP.  Ports may differ
$Port1Number="53";
$Port1Type="UDP";
$Port2Number="1197";
$Port2Type="UDP";

$OpenVpnLocation = "/etc/openvpn/";                                             // Location where the openvpn files are going to be located
$LocalZipFile = "openvpn-strong.zip";                                           // Local zip file name
$url = "https://www.privateinternetaccess.com/openvpn/openvpn-strong.zip";      // Online zip file URL
$LocationName="ca_toronto.ovpn";                                                // Openvpn filename for the country

$VpnConfigFilename = "vpn.conf";                                                //VPN Config filename
$CredentialFilename = "login";                                                  // Login credentials stored in this file

$OldPattern = "auth-user-pass";
$NewPattern = "auth-user-pass ${OpenVpnLocation}${CredentialFilename}";

//Helps to ensure no DNS leaks
$DataAppend1 = "script-security 2" . "\nup ${OpenVpnLocation}update-resolv-conf" . "\ndown ${OpenVpnLocation}update-resolv-conf";

$LogFileName = dirname(__FILE__) . "/" . basename(__FILE__, ".php") . ".log";   // Most outputs are logged this file

###################################################################################################################################
###################################################################################################################################
###################################################################################################################################

// DateTime outputs

        function givemeDateTimeNow() {
            $output = "\n************************************\n";
            $output .= date('m/d/Y h:i:s a', time());
            $output .= "\n************************************\n";
            return $output;
        }

// Determine if package is installed

        function isPackageInstalled($packageName) {
            $output = shell_exec("dpkg-query -W --showformat='\${Status}\n' $packageName");
            return strpos($output, "install ok installed") !== false;
        }

// Runs the command and outputs to the log function

        function runThis($thisCommand) {
            GLOBAL $LogFileName;
            $output = shell_exec($thisCommand);
            file_put_contents($LogFileName,$output,FILE_APPEND);
        }

// Log function to echo and put text to a file

        function logThis($output,$EchoMe) {
            GLOBAL $LogFileName;
            if ($EchoMe) echo "$output\n";
            file_put_contents($LogFileName,"\n$output\n\n",FILE_APPEND);
        }

// Installs software using the isPackageInstalled function

        function installSoftware($packageName) {
            GLOBAL $LogFileName;
            if (!isPackageInstalled($packageName)) {
              logThis("[Installing $packageName]", true);
              $output = shell_exec("apt-get install $packageName -y");
              file_put_contents($LogFileName,$output,FILE_APPEND);
          }
        }

// Start, Stop, or Enable service

        function workService($serviceName, $enterState) {
            GLOBAL $LogFileName;
            logThis("[Running systemctl $enterState $serviceName]",true);
            $output = shell_exec("systemctl $enterState $serviceName");
            file_put_contents($LogFileName,$output,FILE_APPEND);
        }

// Verify if running as root

        if (posix_getuid() !== 0) {
            exit("Ending script.  Not running as root.\n");
        };

// Run updates

        logThis(givemeDateTimeNow(),false);

        logThis("[Running Update]",true);
        runThis('apt-get update -y');

        logThis("[Running Upgrade]",true);
        runThis('apt-get upgrade -y');

// Verify if zip is installed

        if (!isPackageInstalled('php-zip')) {
            installSoftware('php-zip');
            exit("\ust installed php-zip. Restart the script\n");
        }

// Install needed software

        installSoftware('ifupdown');
        installSoftware('openvpn');
        installSoftware('resolvconf');

        logThis("[PreDownloading iptables-persistent]",true);
        runThis('apt-get install --download-only iptables-persistent -y');

// Get VPN zip file

        $output = file_get_contents($url);
        file_put_contents($LocalZipFile, $output);

// Start and Enable resolvconf service to start on boot

        workService('resolvconf.service','start');
        workService('resolvconf.service','enable');

// Extract zip file into place

        $output = new ZipArchive;
        if ($output->open($LocalZipFile) === TRUE) {
            logThis("[Unzipping file $LocalZipFile into $OpenVpnLocation]",true);
            $output->extractTo($OpenVpnLocation);
            $output->close();
        } else {
            exit ("Exiting script. Unzip failed\n");
        }

// Delete the original zip file

        logThis("[Deleting Zip File $LocalZipFile]",true);
        unlink($LocalZipFile);

// Change directory

        logThis("[Changing directory to $OpenVpnLocation]",true);
        chdir($OpenVpnLocation);

// Create credential file

        $output = fopen($CredentialFilename, "w");
        if ($output) {
                logThis("[Creating Credential File $CredentialFilename]",true);
                fwrite($output, $PiaUsername . PHP_EOL);
                fwrite($output, $PiaPassword . PHP_EOL);
                fclose($output);
        } else {
            exit ("Exiting script. Unable to create $CredentialFilename\n");
        }

// Update permissions on the credential file

        logThis("[Changing permissions on $CredentialFilename]",true);
        chmod($CredentialFilename, 0500);

// Copy the openvpn file into the appropriate filename

        logThis("[Copying $LocationName to $VpnConfigFilename]",true);
        copy($LocationName, $VpnConfigFilename);

// Update to have auth with login in the VpnConfigFilename

        logThis("Updating $VpnConfigFilename with login file]",true);
        $fileContent = file_get_contents($VpnConfigFilename);
        $newFileContent = str_replace($OldPattern, $NewPattern, $fileContent);
        file_put_contents($VpnConfigFilename, $newFileContent);

// Helps to ensure no DNS leaks

        logThis("[Updating $VpnConfigFilename to help ensure no DNS leaks]",true);
        $myfile = file_put_contents($VpnConfigFilename, $DataAppend1.PHP_EOL,FILE_APPEND | LOCK_EX);

// Enable openvpn with the config file to start automatically

        $FileNameParts = pathinfo($VpnConfigFilename);
        $VpnConfigFileBasename = $FileNameParts['filename']; // filename is only since PHP 5.2.0        //Baasename is the filename without the extension
        workService("openvpn@$VpnConfigFileBasename","enable");

// Clearing out old IP tables rules

        logThis("[Clear out the old IP tables rules]",true);
        runThis("iptables -F");
        runThis("iptables -t nat -F");
        runThis("iptables -t mangle -F");
        runThis("iptables -X");

// Allow loopback device (internal communication)

        logThis("[Updating iptables to allow for loopback device (internal communication)]",true);
        runThis("iptables -A INPUT -i lo -j ACCEPT");
        runThis("iptables -A OUTPUT -o lo -j ACCEPT");

// Allow all local traffic.

        logThis("[Updating iptables to allow for all local traffic]",true);
        runThis("iptables -A INPUT -s 10.0.0.0/8 -j ACCEPT");
        runThis("iptables -A OUTPUT -d 10.0.0.0/8 -j ACCEPT");
        runThis("iptables -A INPUT -s 172.16.0.0/12 -j ACCEPT");
        runThis("iptables -A OUTPUT -d 172.16.0.0/12 -j ACCEPT");
        runThis("iptables -A INPUT -s 192.168.0.0/16 -j ACCEPT");
        runThis("iptables -A OUTPUT -d 192.168.0.0/16 -j ACCEPT");

// Allow VPN establishment with only 2 ports open, 1 for DNS and 1 for VPN
// If establishing thru an IP and not DNS, the ones with port 53 can be removed
// Port may be different depending on the VPN

        logThis("[Updating iptables to allow for 2 ports of communication]",true);
        runThis("iptables -A INPUT -p $Port1Type --sport $Port1Number -j ACCEPT");
        runThis("iptables -A OUTPUT -p $Port1Type --dport $Port1Number -j ACCEPT");
        runThis("iptables -A INPUT -p $Port2Type --sport $Port2Number -j ACCEPT");
        runThis("iptables -A OUTPUT -p $Port2Type --dport $Port2Number -j ACCEPT");

// Accept all TUN connections (tun = VPN tunnel)

        logThis("[Updating iptables to allow for all TUN connection traffic]",true);
        runThis("iptables -A OUTPUT -o tun+ -j ACCEPT");
        runThis("iptables -A INPUT -i tun+ -j ACCEPT");

// Set default policies to drop all communication unless specifically allowed

        logThis("[Updating iptable to drop all communication unless specifically allowed]",true);
        runThis("iptables -P INPUT DROP");
        runThis("iptables -P OUTPUT DROP");
        runThis("iptables -P FORWARD DROP");

// Bring up and down the network inteface with pauses

        logThis("[Bringin up and down the network interface]",true);
        runThis("ip link set $NetworkInterfaceName down");
        runThis("ip link set $NetworkInterfaceName up");

// Stopping and starting openvpn service with pauses

        workService('openvpn','stop');
        sleep(5);

        workService('openvpn','start');
        sleep(5);

// Installing iptables-persistent to save iptable rules on reboot

        runThis("echo iptables-persistent iptables-persistent/autosave_v4 boolean true | sudo debconf-set-selections");
        runThis("echo iptables-persistent iptables-persistent/autosave_v6 boolean true | sudo debconf-set-selections");
        installSoftware('iptables-persistent');

// Turning on netfilter-persistent and setting to start on restart

        runThis("netfilter-persistent save");
        workService('netfilter-persistent','enable');

?>