Archive for November, 2010
Network Location Switching
Been quite a long time since my last post, and I am not going to try to catch things up. But I did want to archive this information:
At work, we have an http proxy - an idea from the 18th century it seems. So I have to have two Network Locations (one for normal configurations, another for the work proxy). We also use Cisco AnyConnect VPN to connect from home.
I had been using MarcoPolo for switching locations. This worked great for home and work, but I wasn’t happy with how it worked with the VPN. All I could do was detect if the VPN application was running or not - so I couldn’t leave the VPN app open and connect/disconnect. Also, the process was to launch the VPN app, wait for MarcoPolo to switch the network to VPN, make sure it was stable (not switching back and forth), and then connect to the VPN. Disconnecting has to be followed by exiting the VPN else MarcoPolo wouldn’t switch things back to my no-proxy Location.
I took inspiration from this and created a LaunchAgent and a simple script to switch Network Locations.
The LaunchAgent plist file goes in ~/Library/LaunchAgents/com.srednal.netswitch.plist, and looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.srednal.netswitch</string>
<key>EnableGlobbing</key>
<true/>
<key>ProgramArguments</key>
<array>
<string>~/bin/netswitch</string>
</array>
<key>WatchPaths</key>
<array>
<string>/Library/Preferences/SystemConfiguration</string>
</array>
</dict>
</plist>
The script, in ~/bin/netswitch, is something like this (names and addresses may have been changed):
#!/usr/bin/env ruby
# Test network and switch locations based on vpn and ip address
require 'ipaddr'
# see if VPN is connected
def vpn?
connected = false
IO.popen( '/opt/cisco/vpn/bin/vpn status' ) do |out|
out.each do |line|
connected = true if line =~ />> state: Connected/
end
end
connected
end
# are we on work network?
def work?
# Work IP will be within 10.345.678.00/24 - obviously this is something you need to tweak
work = IPAddr.new('10.345.678.00/24')
work.include?(local_ip)
end
# lookup local ip addr
def local_ip
orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily
UDPSocket.open do |s|
s.connect '74.125.45.99', 1 # IP is anything
s.addr.last
end
ensure
Socket.do_not_reverse_lookup = orig
end
# set network location config
def location(name)
system "/usr/sbin/scselect '#{name}'"
end
if __FILE__ == $0
# let things settle down
sleep 2
if (vpn? || work?) then
location 'Proxy'
else
location 'Automatic'
end
end
The script can be run manually to test things. Then load the launch agent with launchctl load ~/Library/LaunchAgents/com.srednal.netswitch.plist.
After I got that working, I went into the Info.plist file of the AnyConnect client app, and added (to the dict element)
<key>LSUIElement</key> <string>1</string>
That makes the Dock icon go away (but leaves the icon in the status bar), so now I can leave the AnyConnect client running and just connect/disconnect as needed - the LaunchAgent and script keep my network location set right.
1 comment