Since my employer’s wireless network is unencrypted and since I use other open WiFi networks with some frequency, I’ve gotten in the habbit of tunneling everything through SSH, using the SOCKS5 proxy mechanism built in to SSH. In WinXP, there’s a nice little program called Tunnelier that makes the setup of the tunnel simple and it reconnects automatically, so the tunneling part is virtually automatic (even though proxy setup is still tricky and/or annoying).
On the Mac, however, I have tried several programs and never really been happy. So I wrote a little AppleScript that not only sets up the SSH tunnel, but also deals with switching my location to set the system’s network settings to use the proxy (the code is after the cut). Combine this with System Proxy for Firefox and all my application traffic goes through the SSH tunnel. Note also that if you’re using a SOCKS5 proxy with Firefox, you probably want to set it to do DNS lookups through the proxy.
This script also stores the info for creating the tunnel (server, login, pw) in the keychain.
Here’s the “library” script where I put the functions to do the underlying work (since I have various different tunnels I use):
-
on startTunnel(targetServer) –returns PID of ssh for killing later
-
tell application "Keychain Scripting"
-
-
set sshTunnelKeys to every Internet key of current keychain whose (name is "autoSSHTunnel") and (server is targetServer)
-
-
if sshTunnelKeys is {} then
-
set sshKey to my makeSSHKeyWithServer(targetServer)
-
else
-
set sshKey to item 1 of sshTunnelKeys
-
end if
-
set user to account of sshKey
-
set passwd to password of sshKey as string
-
set sshHost to server of sshKey as string
-
end tell
-
-
set sshCommand to "ssh -fND 9999 " & user & "@" & sshHost
-
-
set expectScript to "spawn " & sshCommand & "
-
expect assword
-
send \"" & passwd & "\\n\"
-
sleep 1"
-
-
do shell script "/usr/bin/expect -c '" & expectScript & "' &>/dev/null &"
-
-
set tries to 0
-
repeat
-
set tries to tries + 1
-
try
-
set sshPIDstring to (do shell script "sleep 1;bash -c 'ps ax -o pid,tt,command | grep \"??\" | grep \"" & sshCommand & "\" | grep -v grep | grep -v expect'")
-
set sshPID to first word of sshPIDstring
-
set gotPID to true
-
on error
-
set gotPID to false
-
end try
-
if gotPID then
-
exit repeat
-
end if
-
if tries > 10 then
-
exit repeat
-
end if
-
end repeat
-
if gotPID then
-
return sshPID
-
else
-
return false
-
end if
-
end startTunnel
-
-
on setUseTunnel()
-
do shell script "scselect 'Use SOCKS5 Proxy on localhost:9999'"
-
end setUseTunnel
-
-
on clearUseTunnel()
-
do shell script "scselect 'Automatic'"
-
end clearUseTunnel
-
-
on stopTunnel(pid)
-
do shell script "kill " & pid
-
end stopTunnel
-
-
on makeSSHKeyWithServer(targetServer)
-
tell application "Keychain Scripting"
-
repeat
-
set acctBox to display dialog "Enter your SSH login for host " & targetServer & ":" default answer "" buttons {"Cancel", "OK"} default button 2
-
set myAcct to the text returned of acctBox
-
set myButton to the button returned of acctBox
-
if myButton is "Cancel" then
-
–quit
-
else
-
if myAcct is not "" then
-
exit repeat
-
else
-
display dialog "bad login"
-
end if
-
end if
-
end repeat
-
repeat
-
set passBox to display dialog "Enter your password:" default answer "" buttons {"Cancel", "OK"} default button 2 with hidden answer
-
set myPass to the text returned of passBox
-
set myButton to the button returned of passBox
-
if myButton is "Cancel" then
-
–quit
-
else
-
if myPass is not "" then
-
exit repeat
-
else
-
display dialog "can't use blank passwd"
-
end if
-
end if
-
end repeat
-
set newSSHKey to make new Internet key with properties {name:"autoSSHTunnel", account:myAcct, password:myPass, server:targetServer, authentication:default, protocol:SSH}
-
end tell
-
return newSSHKey
-
end makeSSHKeyWithServer
And here’s the actual script I run.
-
property Lib : (path to scripts folder from user domain as text) & "Script Library:"
-
property sshTunnelLib : load script Lib & "ssh_tunnel.scpt" as alias
-
-
sshTunnelLib's setUseTunnel()
-
-
set sshPID to sshTunnelLib's startTunnel("fqdn.of.your.server")
-
if sshPID is not false then
-
set noPIDtxt to ""
-
set buttonTxt to "Kill SSH and Exit"
-
else
-
set noPIDtxt to " (but couldn't get PID)"
-
set buttonTxt to "Exit"
-
end if
-
-
display dialog "SSH-tunneled SOCKS5 proxy running on localhost:9999" & noPIDtxt buttons {buttonTxt}
-
-
if sshPID is not false then
-
sshTunnelLib's stopTunnel(sshPID)
-
end if
-
-
sshTunnelLib's clearUseTunnel()