How can I maintain local LAN access while connected to Cisco VPN?
When connecting using Cisco VPN, the server has to ability to instruct the client to prevent local LAN access.
Assuming this server-side option cannot be turned off, how can allow local LAN access while connected with a Cisco VPN client?
I used to think it was simply a matter of routes being added that capture LAN traffic with a higher metric, for example:
Network
Destination Netmask Gateway Interface Metric
10.0.0.0 255.255.0.0 10.0.0.3 10.0.0.3 20 <--Local LAN
10.0.0.0 255.255.0.0 192.168.199.1 192.168.199.12 1 <--VPN Link
And trying to delete the 10.0.x.x -> 192.168.199.12
route don't have any effect:
>route delete 10.0.0.0
>route delete 10.0.0.0 mask 255.255.0.0
>route delete 10.0.0.0 mask 255.255.0.0 192.168.199.1
>route delete 10.0.0.0 mask 255.255.0.0 192.168.199.1 if 192.168.199.12
>route delete 10.0.0.0 mask 255.255.0.0 192.168.199.1 if 0x3
And while it still might simply be a routing issue, attempts to add or delete routes fail.
At what level is Cisco VPN client driver doing what in the networking stack that takes overrides a local administrator's ability to administer their machine?
The Cisco VPN client cannot be employing magic. It's still software running on my computer. What mechanism is it using to interfere with my machine's network? What happens when an IP/ICMP packet arrives on the network? Where in the networking stack is the packet getting eaten?
See also
- No internet connection with Cisco VPN
- Cisco VPN Client interrupts connectivity to my LDAP server
- Cisco VPN stops Windows 7 Browsing
- How can I prohibit the creation of a route in Windows XP upon connection to Cisco VPN?
- Rerouting local LAN and Internet traffic when in VPN
- VPN Client "Allow local LAN Access"
- Allow Local LAN Access for VPN Clients on the VPN 3000 Concentrator Configuration Example
- LAN access gone when I connect to VPN
- Windows XP Documentation: Route
Edit: Things I've not yet tried:
>route delete 10.0.*
Update: Since Cisco has abandoned their old client, in favor of AnyConnect (HTTP SSL based VPN), this question, unsolved, can be left as a relic of history.
Going forward, we can try to solve the same problem with their new client.
Best Answer
The problem with Anyconnect is that it first modifies the routing table, then babysits it and fixes it up should you modify it manually. I found a workaround for this. Works with version 3.1.00495, 3.1.05152, 3.1.05170, and probably anything else in the 3.1 family. May work with other versions, at least similar idea should work assuming the code does not get rewritten. Fortunately for us Cisco has put the babysitter "baby is awake" call into a shared library. So the idea is that we prevent action by vpnagentd via LD_PRELOAD.
First we create a file
hack.c
:Note: This code works only with Linux. For applying this solution to a macOS machine, see the macOS adapted version.
Then compile it like this:
Install
libhack.so
into the Cisco library path:Bring down the agent:
Make sure it really is down
If not,
kill -9
just to be sure.If you have
/etc/init.d/vpnagentd
, then fix it up by addingLD_PRELOAD=/opt/cisco/anyconnect/lib/libhack.so
where the underlying executable is being invoked so it looks like this:More modern AnyConnect installations eschew
/etc/init.d/vpnagentd
in favor of/lib/systemd/system/vpnagentd.service
, in which case you'll want something like:Now start the agent:
Fix up iptables, because AnyConnect messes with them:
You may want to do something more advanced here to allow access only to certain LAN hosts.
Now fix up the routes as you please, for example:
Check to see if they are really there:
route -n
A previous, simpler version of this hack gave a function that only did "return 0;" - that poster noted that "The only side effect that I've observed so far is that vpnagentd is using 100% of CPU as reported by top, but overall CPU is only 3% user and 20% system, and the system is perfectly responsive. I straced it, it seems to be doing two selects in a loop when idle returning from both quickly, but it never reads or writes - I suppose the call that I cut out with LD_PRELOAD was supposed to read. There might be a cleaner way to do it, but it is good enough for me so far. If somebody has a better solution, please share."
The problem with the trivial hack is it caused a single cpu core to be 100% all the time, effectively reducing your hardware cpu thread count by one - whether your vpn connection was active or not. I noticed that the selects the code was doing were on a netlink socket, which sends vpnagentd data when the routing table changes. vpnagentd keeps noticing there's a new message on the netlink socket and calls the routeCallBackHandler to deal with it, but since the trivial hack doesn't clear the new message it just keeps getting called again and again. the new code provided above flushes the netlink data so the endless loop which caused the 100% cpu doesn't happen.
If something does not work, do
gdb -p $(pidof vpnagentd)
, once attached:and see which call you are in. Then just guess which one you want to cut out, add it to hack.c and recompile.