This will be a longish post. It will be worth it if you're frustrated at having to be in the office to use your 64 bit Windows system because you don't have a real VPN solution available to you.
Since the advent of SSL VPN solutions we've all faced the consuming challenge of making sure we have the right version of a Java client on board, oddball, glue-on, 3rd party 'dual-factor' authentication packages and an assortment of half-baked solutions designed to replace the ubiquitous Cisco VPN 3000 Concentrator and its clients. Even Cisco has had trouble displacing this rock-solid platform and is grasping at any reasonable way to rationalize the retirement of the platform.
To that end, Cisco has not released a VPN 3000 client that is compatible with 64 bit Windows systems and refuses to do so. Instead, you're advised to nag your network engineers to implement one of their ASA systems in the name of SSL VPN (which is one of the most oversold, least satisfactory technical solutions I've ever dealt with). If you find yourself on a 64 bit system and caught in the gap between the 3000 and the SSL solution, this post may be what you're looking for. And I might as well tell you here why it is this might be a challenge:
· VPNC is a Linux application
· You'll have to compile VPNC (holy crap, man!)
· VPNC is a 'split tunnel' client. You have to figure out the routing (I'll help you, honest) because it doesn't do its own routing like you're used to with the Cisco client. Following these steps, you should succeed thanks to some of the automation tools I'll provide
· Making it run in Windows requires you get your virtual dogs wet in a little Linux activity within Cygwin, a sort of Linux shell that runs on Windows
· Stop using Google. Honest to Pete, I actually, stupidly, spent 2 days playing and searching before I realized I should have started by reading the README file included in the VPNC tarball which gave me nearly everything I needed. ALWAYS READ THE README FILE FIRST!!!!
The first thing to tell you is that this isn't going to be the easiest thing you've ever done as a Windows user. The next thing to tell you is that you're going to play with a touch of Linux which should inspire an almost sinful sense of perversity in you. If you don't feel that geeky rush, this may be more than you want to tackle. Don't be surprised if you have to learn a little scripting to make everything work as you expect.
In the interest of full disclosure, most of what you're about to read is not pioneering work by me. It is organized, however. My greatest struggle to get this all working was pulling together what everyone else had done into a reasonable and repeatable set of steps.
So let's jump in with a brief project plan so you can determine if this is what you need to do or if you should sell some of that ram back to Dell and install a 32 bit version of Windows.
Steps to Install and Configure VPNC
I didn't create this (I merely added to it), it's in the VPNC README file...which is the last but most important place it really needs to be:
"==Setting up vpnc on Vista 64bit ==============
1. Install cygwin onto vista. Details here: http://www.cygwin.com/
2. Make sure you install the development options for cygwin to give you access to make and gcc etc
3. Make sure you install libcrypt for cygwin as it is needed in the make process
4. Modify the bash.exe to run as administrator or you will have privilege issues later, this is done on the properties tab of the executable in c:/cygwin/bin
5. Download the latest vpnc tarball from here http://www.unix-ag.uni-kl.de/~massar/vpnc/
6. Unzip and explode the tarball (hint: this part you can search for on Google or Bing)
7. modify tap-win32.h to change #define TAP_COMPONENT_ID "tap0801" to "tap0901" (Not sure if this is necessary but I did it and it is working for me)
8. make (make does a number of things but the end result is it makes an executable file)
9. You should have a shiny new /usr/local/sbin/vpnc.exe
10. In Cygwin, download the pcf2vpnc perl script: wget http://svn.unix-ag.uni-kl.de/vpnc/trunk/pcf2vpnc
11. In Cygwin, make the script executable -> chmod +x pcf2vpnc
12. In Cygwin, convert your .pcf files to work with vpnc -> ./pcf2vpnc cisco.pcf > cisco.conf
13. In Windows, download openvpn from http://openvpn.net/download.html.
14. Run the exe but only install the TAP-Win32 Adapter V9
15. Go to control Panel | Network Connections and rename the TAP device to TAP_ADAPTER
16. create a /etc/vpnc/default.conf file something like this
------------- begin -------------
IPSec gateway YOURGATEWAY
IPSec ID YOURID
IPSec obfuscated secret YOURREALYLONGHEXVALUE #(you can use your cleartext password here if you remove obfuscated)
Xauth username YOURUSERNAME
Xauth password YOURPASSWORD
Interface name my-tap
Interface mode tap
Local Port 0
------------- end ---------------"
Now, let's talk semi-seriously here. This isn't trivial if you haven't played with Linux before. The best thing I can tell you is that Google really is your friend. You will find all sorts of very poorly organized results to help you get through the steps. You *can* do it, though. If I can, you can. After all, I'm only involved with technology because it really pisses me off and the only way I can see to make it better is to work with it. It pays well, too.
You should also know that the default.conf file described above has some things in it which will upset your network and security admins and for good reason. Let me make that worse and better at the same time. If you do not include the Xauth password section in the file, VPNC will ask you your password whenever you attempt to connect. It will work properly with your RSA token, too. The bad part is that this approach to configuration will concern your local security geeks despite the fact you already had a pcf file on your system anyway. Go figure.
Those two teams of people will also be disturbed by the fact that VPNC is a split tunnel solution. What the heck is that? Normally, when you connect to your corporate network, all your network traffic will go through your VPN connection to the office and then out to the Internet as required. This is a dedicated VPN tunnel. VPNC 'splits' this function by erecting the tunnel to your office and its internal networks while allowing all your Internet and local network traffic to be handled at your end of the connection. In other words, only traffic intended to go to the office actually goes there. Because of this, there is risk that while you are connecting to some questionable Internet site you may expose the corporate network to the infection you pick up on your local machine. Of course, you could just as easily get that infection over your dedicated conventional tunnel but you get the point: you're taking on risks and forcing your company to participate in that risk without oversight. Be respectful and responsible by keeping this in mind as you use your company network resources.
Okay then!! You've installed Cygwin, you've installed the TAP adapter, you've done a mild conversion of your PCF file. What next?
Let's attempt to understand how VPNC runs.
VPNC Environment Variables
VPNC manages a small stack of environment variables which you may consume to manage the way it uses the network tunnel. From the VPNC documentation:
VPNGATEWAY -- vpn gateway address (always present)
TUNDEV -- tunnel device (always present)
INTERNAL_IP4_ADDRESS -- address (always present)
INTERNAL_IP4_NETMASK -- netmask (often unset)
INTERNAL_IP4_DNS -- list of dns servers
INTERNAL_IP4_NBNS -- list of wins servers
CISCO_DEF_DOMAIN -- default domain name
CISCO_BANNER -- banner from server
CISCO_SPLIT_INC -- number of networks in split-network-list
CISCO_SPLIT_INC_%d_ADDR -- network address
CISCO_SPLIT_INC_%d_MASK -- subnet mask (for example: 255.255.255.0)
CISCO_SPLIT_INC_%d_MASKLEN -- subnet masklen (for example: 24)
CISCO_SPLIT_INC_%d_PROTOCOL -- protocol (often just 0)
CISCO_SPLIT_INC_%d_SPORT -- source port (often just 0)
CISCO_SPLIT_INC_%d_DPORT -- destination port (often just 0)
According to the README file (there it is again), VPNC has three stages of operation called pre-init, connect and disconnect which are exposed as an environment variable named 'reason'. You may perform actions via script or configuration file during each of these stages. The pre-init stage is executed before the virtual tunnel network adapter (the TAP adapter you installed from OpenVPN) is opened by VPNC. The connect stage is executed after a virtual tunnel is successfully authenticated and erected between your VPN endpoint and your PC. And, naturally, the disconnect phase executes after tearing down the tunnel and releasing control of the TAP adapter.
We can use each of these three stages to our advantage. For instance, I like to leave the TAP adapter disabled to ensure it doesn't cause conflicts in the system routing table by holding IP settings that are no longer valid.
The VPNC documentation also suggests that you include a pointer to a Cygwin shell script in default.conf so that you may describe to VPNC how you want your network routes 'split' to the VPN tunnel . At the end of that script you may shell to other scripts.
My solution looks like this (and executes in this order):
- vpnc.exe compiled and available at /usr/local/sbin
- default.conf stored in /etc/vpnc
- custom-script stored in /etc/vpnc
- vpnc-script stored in /etc/vpnc
- vpnc-script-win.vbs stored in /etc/vpnc
- startvpn stored in ~/ (or, if you don't recognize the tilde character, your user home directory)
The script that is the *most* critical to getting your split routing correct is the vpnc-script-win.vbs file. The basics of this file come from a JScript file created by another VPNC adopter for Vista. There were some functions that just didn't work as the author intended, unfortunately, but the work was an excellent start. Since I'm not a JScript master and in the best spirit of 'adopt and improve', I converted his code to VBScript, recognized the weaknesses of the Cygwin environment and provided some other hacks to make an automated connection sequence.
To date, this has worked with WiFi, physical LAN connections, tethered cell phones and so on. There has been one failure that I haven't managed to identify. Using Sprint's U300 4G adapter with SprintView, I have not been able to succeed in making any network connections once the TAP adapter has a tunnel to the corporate network. There are so many issues with the 64 bit drivers for this adapter, though, that I've decided to wait until those drivers and the SprintView software mature a little more before sacrificing a mound of hair to the problem.
You should know a couple things more about the last script, vpnc-script-win.vbs.
First, it's designed to create a batch file, the contents of which are changed depending on which phase of VPNC operation you're in. This batch file is created in the same location as vpnc-script-win.vbs so you'll need to make sure you have Write and Execute permissions in the location where this script resides. And why is the batch file necessary? Well, as it turns out, it's really easy to foul up StdIn and StdOut screen buffers Cygwin uses to feed the Windows Command Console. If you simply try to shell out Windows commands of more than 255 characters, you'll get some interesting results sometimes. Thus the batch file.
Next, if you run into problems with vpnc using this script, I'll be happy to *try* to help but be aware I'm sharing this solution not as an expert but as someone who has faced the same challenge you have, that we are in the minority of users with our need and almost none of that makes us 'experts' on networking...including me. If you do ask for help, be prepared for a "Heck, I don't know either!". If you want to give me a fighting chance to help, be sure to include all 4 of these configuration files and scripts as well as a clear description of the problem (including error messages).
After copying, pasting, saving scripts, converting your pcf file and merging it into default.conf, just run Cygwin as administrator and run the startvpn shell script.
So, off to the scripts!
~/startvpn
#!/bin/sh
/usr/local/sbin/vpnc --debug 1 --no-detach
#note that debug becomes more useful if set to 2 when troubleshooting. --no-detach
#keeps vpnc in the foreground of execution Cygwin.
#VPNC will die if it becomes unattached.
/etc/vpnc/default.conf
# your TAP network connection:
Interface name TAP_Adapter
# This line tells vpnc that you're doing TAP, not TUNnelling.
Interface mode tap
# For some reason that I don't understand, vpnc doesn't work under cygwin
# unless it's still attached to the console it was running from,
# so don't detach:
No Detach
# Tell vpnc to select a random free port instead of using 500
# 500 will likely already be in use
Local Port 510
## generated by pcf2vpnc
## x and * characters represent my own network information
IPSec ID ****
IPSec gateway xxx.xxx.xxx.xxx
IPSec secret xxxxxxxx
Xauth username chapmang
IKE Authmode psk
Script /etc/vpnc/custom-script
/etc/vpnc/custom-script
#!/bin/sh
# This sets up split networking regardless
# of the concentrators specifications.
# You can add as many routes as you want,
# but you must set the counter $CISCO_SPLIT_INC
# accordingly. In my case, I have 4 subnets to
# split out
# replace xxx and so on with your corp subnets as
# required
export CISCO_SPLIT_INC=4
export CISCO_SPLIT_INC_0_ADDR=10.0.0.0
export CISCO_SPLIT_INC_0_MASK=255.0.0.0
export CISCO_SPLIT_INC_0_MASKLEN=8
export CISCO_SPLIT_INC_1_ADDR=xxx.xxx.x.x
export CISCO_SPLIT_INC_1_MASK=255.255.0.0
export CISCO_SPLIT_INC_1_MASKLEN=16
export CISCO_SPLIT_INC_2_ADDR=xxx.0.0.0
export CISCO_SPLIT_INC_2_MASKLEN=8
export CISCO_SPLIT_INC_2_MASK=255.0.0.0
export CISCO_SPLIT_INC_3_ADDR=xxx.xx.0.0
export CISCO_SPLIT_INC_3_MASKLEN=16
export CISCO_SPLIT_INC_3_MASK=255.255.0.0
. /etc/vpnc/vpnc-script
/etc/vpnc/vpnc-script
#! /bin/sh
cscript `cygpath -w /etc/vpnc/vpnc-script-win.vbs`
/etc/vpnc/vpnc-script-win.vbs
' vpnc-script-win.vbs
'
' Sets up the Network interface and the routes
' needed by vpnc.
' see notes at bottom of script to describe env variables, etc.,
' created by VPNC
'===================CONSTANTS==========================
CONST ForReading = 1, ForWriting = 2, ForAppending = 8
CONST ScriptLog = "PostConf.bat"
'======================================================
strTunnel = "TAP_Adapter"
Set ws = WScript.CreateObject("WScript.Shell")
Set env = ws.Environment("Process")
Set objFSO = CreateObject("scripting.FileSystemObject")
LogFile= ExecutingFrom & ScriptLog
set f = objFSO.OpenTextFile(LogFile, ForWriting, True, -2)
LogAction ("REM" & vbCrLf)
f.close
Select Case (env("reason"))
case "pre-init"
'Enable the interface
wscript.echo "Enabling TAP_Adapter"
setinterface = "netsh interface set interface " & strTunnel & _
" admin=ENABLED"
ws.run setinterface,0,1
wscript.echo setinterface
case "connect"
wscript.echo "CISCO Split Networks: " & _
env("CISCO_SPLIT_INC")
wscript.echo "VPN Gateway: " & _
env("VPNGATEWAY")
wscript.echo "Internal Address: " & _
env("INTERNAL_IP4_ADDRESS")
wscript.echo "Internal Netmask: " & _
env("INTERNAL_IP4_NETMASK")
wscript.echo "Interface:" & Chr(34) & _
env("TUNDEV") & Chr(34)
wscript.echo "Configuring " & _
env("TUNDEV") & " interface..."
setinterface = "netsh interface ip set address " & _
env("TUNDEV") & _
" source=static " & env("INTERNAL_IP4_ADDRESS") & " " & _
env("INTERNAL_IP4_NETMASK")
wscript.echo setinterface
LogAction(setinterface & vbCrLf)
if Len(env("INTERNAL_IP4_NBNS")) > 0 Then
'echo ("WINS: " & env("INTERNAL_IP4_NBNS"))
wins = split(env("INTERNAL_IP4_NBNS"), " ")
for i = 0 to Ubound(wins)
LogAction ("netsh interface ip add wins " & _
(env("TUNDEV") & _
" " & wins(i) & " index=" & (i+1) & vbCrLf))
wscript.echo "netsh interface ip add wins " & _
(env("TUNDEV")) & _
" " & wins(i) & " index=" & (i+1)
next
End if
if Len(env("INTERNAL_IP4_DNS")) > 0 Then
'echo("DNS: " & env("INTERNAL_IP4_DNS"))
dns = Split(env("INTERNAL_IP4_DNS")," ")
for i = 0 to UBound(dns)
dnsrun = "netsh interface ip add dns " & _
env("TUNDEV") & " " & dns(i) & _
" index=" & (i+1)
wscript.echo dnsrun
LogAction(dnsrun & vbCrLf)
next
End if
wscript.echo "Done configuring " & strTunnel &"."
'Add internal network routes
wscript.echo "Configuring network routes..."
if (env("CISCO_SPLIT_INC") <> " ") Then
LogAction ("PING 1.1.1.1 -n 1 -w 6000 >NUL")
for i=0 to env("CISCO_SPLIT_INC")
network = Trim(env("CISCO_SPLIT_INC_" & i & "_ADDR"))
netmask = Trim(env("CISCO_SPLIT_INC_" & i & "_MASK"))
netmasklen = Trim(env("CISCO_SPLIT_INC_" & i & "_MASKLEN"))
strTunnel=Trim(env("TUNDEV"))
strIP=Trim(env("INTERNAL_IP4_ADDRESS"))
strCMD="route add "
If network <> "" Then
LogAction(strCmd & network & " mask " & netmask & " " & strIP)
'stupid pet trick to force the batch file to wait as route
'table updates. Adjust 3000 to match your delay needs
LogAction ("PING 1.1.1.1 -n 1 -w 3000 >NUL")
End If
next
Else
wscript.echo "Gateway did not provide network configuration."
End If
wscript.echo "Route configuration done." & vbCrLf
if env("CISCO_BANNER") <> " " Then
wscript.echo "--------------------------------------------------"
wscript.echo env("CISCO_BANNER")
wscript.echo "--------------------------------------------------"
end if
'Add direct route for the VPN gateway to avoid routing loops
wscript.echo "Adding route for VPN Gateway to avoid routing loops..."
setroute = "route add " & env("VPNGATEWAY") & _
" mask 255.255.255.255 "
LogAction(setroute & vbCrLf)
For i=0 to 50
ws.run LogFile,0,0
Next
wscript.echo "Check " & LogFile & " if you need to confirm route configuration."
case "disconnect"
'Delete direct route for the VPN gateway
LogAction("route delete " & env("VPNGATEWAY") & _
" mask 255.255.255.255")
wscript.echo "Removing networks..."
if env("CISCO_SPLIT_INC") Then
for i = 0 to env("CISCO_SPLIT_INC")
network = env("CISCO_SPLIT_INC_" & i & "_ADDR")
netmask = env("CISCO_SPLIT_INC_" & i & "_MASK")
internal = env("INTERNAL_IP4_ADDRESS")
If network <> "" Then
blah = "route delete " & network & " mask " & netmask
LogAction(blah & vbCrLf)
End If
next
end if
setinterface = "netsh interface ip delete address " & _
env("TUNDEV") & _
" " & env("INTERNAL_IP4_ADDRESS")
LogAction(setinterface & vbCrLf)
setinterface = "netsh interface set interface " & _
env("TUNDEV") + " admin=DISABLED"
wscript.echo "VPN Disconnected."
LogAction(setinterface & vbCrLf)
ws.run LogFile,0,0
end select
wscript.quit
'====================================================================
Sub LogAction (strEntry)
Dim strErrMsg, f
On Error Resume Next
set f = objFSO.OpenTextFile(LogFile, ForAppending, True, -2)
f.WriteLine strEntry
f.close
On Error Goto 0
End Sub
'====================================================================
Function ExecutingFrom()
Dim strScriptPath
strScriptPath=Left(wscript.scriptfullname, _
Len(wscript.scriptfullname)-Len(wscript.scriptname))
If Right(strScriptPath,1) <> "\" Then
strScriptPath=strScriptPath & "\"
End If
ExecutingFrom=strScriptPath
End Function