Posted by: Dakusan
« on: December 28, 2010, 08:48:27 pm »Originally posted on: 12/28/10
For a number of years now when on insecure network connections I have been routing my computer to the Internet through secure tunnels and VPNs, but I’ve been interested in trying out different types of VPN software lately so I can more easily help secure friends who ask of it. This would mainly include ease of installation and enabling, which partly requires no extra software for them to install.
Unfortunately, Windows 7 and Android (and probably most other software) only support PPTP and L2TP/IPSEC out of the box. While these protocols are good for what they do, everything I have read says OpenVPN is superior to them as a protocol. I was very frustrated to find out how little support OpenVPN actually has today as a standard in the industry, which is to say, you have to use third party clients and it is rarely, if ever, included by default in OSes. The OpenVPN client and server aren’t exactly the easiest to set up either for novices.
So on to the real point of this post. The sample client and server configurations for OpenVPN were set up just how I needed them except they did not include two important options for me: User authentication and full client Internet forwarding/tunneling/gateway routing. Here is how to enable both.
Routing all client traffic (including web-traffic) through the VPN:
- Add the following options to the server configuration file:
- push "redirect-gateway def1" #Tells the client to use the server as its default gateway
- push "dhcp-option DNS 10.8.0.1" #Tells the client to use the server as its DNS Server (DNS Server's IP address dependent on configuration)
- Run the following commands in bash:
- iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE #This command assumes that the VPN subnet is 10.8.0.0/24 (taken from the server directive in the OpenVPN server configuration) and that the local ethernet interface is eth0.
- echo '1' > /proc/sys/net/ipv4/ip_forward #Enable IP Forwarding (This one is not mentioned in the OpenVPN howto)
Adding user authentication (Using alternative authentication methods)
To set up username/password authentication on the server, an authorization script is needed that receives the username/password and returns whether the login information was successful (0) or failed (1). The steps to set up this process are as follows:
- Add the following options to the server configuration file:
- auth-user-pass-verify verify.php via-env #The third argument (method) specifies whether to send the username and password through either a temporary file (via-file) or environment variables (via-env)
- script-security 3 system #Allows OpenVPN to run user scripts and executables and send password authentication information through environment variables. While "system" is deprecated, I had to use it or external commands like ifconfig and route were failing with "failed: could not execute external program"
- Add the following options to the client configuration file:
- auth-user-pass #Request user credentials to log in
- The final step is to create the verify.php (see auth-user-pass-verify configuration above) script which returns whether it was successful, and also outputs its success to stdout, which is added to the OpenVPN log file.
#!/usr/bin/php -q
<?
//Configuration
$ValidUserFile='users.txt'; //This file must be in htpasswd SHA1 format (htpasswd -s)
$Method='via-env'; //via-file or via-env (see auth-user-pass-verify configuration above for more information)
//Get the login info
if($Method=='via-file') //via-file method
{
$LoginInfoFile=trim(file_get_contents('php://stdin')); //Get the file that contains the passed login info from stdin
$LoginInfo=file_get_contents($LoginInfoFile); //Get the passed login info
file_put_contents($LoginInfoFile, str_repeat('x', strlen($LoginInfo))); //Shred the login info file
$LoginInfo=explode("\n", $LoginInfo); //Split into [Username, Password]
$UserName=$LoginInfo[0];
$Password=$LoginInfo[1];
}
else //via-env method
{
$UserName=$_ENV['username'];
$Password=$_ENV['password'];
}
//Test the login info against the valid user file
$UserLine="$UserName:{SHA}".base64_encode(sha1($Password, TRUE)); //Compile what the user line should look like
foreach(file($ValidUserFile, FILE_IGNORE_NEW_LINES) as $Line) //Attempt to match against each line in the file
if($UserLine==$Line) //If credentials match, return success
{
print "Logged in: $UserName\n";
exit(0);
}
//Return failure
print "NOT Logged in: $UserName\n";
exit(1);
?>