2718.us blog » location http://2718.us/blog Miscellaneous Technological Geekery Tue, 18 May 2010 02:42:55 +0000 en hourly 1 http://wordpress.org/?v=3.0.4 SSH Tunneling on a Mac http://2718.us/blog/2008/06/13/ssh-tunneling-on-a-mac/ http://2718.us/blog/2008/06/13/ssh-tunneling-on-a-mac/#comments Fri, 13 Jun 2008 22:55:27 +0000 2718.us http://2718.us/blog/?p=45 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):

  1. on startTunnel(targetServer) –returns PID of ssh for killing later
  2.  tell application "Keychain Scripting"
  3.  
  4.   set sshTunnelKeys to every Internet key of current keychain whose (name is "autoSSHTunnel") and (server is targetServer)
  5.  
  6.   if sshTunnelKeys is {} then
  7.    set sshKey to my makeSSHKeyWithServer(targetServer)
  8.   else
  9.    set sshKey to item 1 of sshTunnelKeys
  10.   end if
  11.   set user to account of sshKey
  12.   set passwd to password of sshKey as string
  13.   set sshHost to server of sshKey as string
  14.  end tell
  15.  
  16.  set sshCommand to "ssh -fND 9999 " & user & "@" & sshHost
  17.  
  18.  set expectScript to "spawn " & sshCommand & "
  19. expect assword
  20. send \"" & passwd & "\\n\"
  21. sleep 1"
  22.  
  23.  do shell script "/usr/bin/expect -c '" & expectScript & "' &>/dev/null &"
  24.  
  25.  set tries to 0
  26.  repeat
  27.   set tries to tries + 1
  28.   try
  29.    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'")
  30.    set sshPID to first word of sshPIDstring
  31.    set gotPID to true
  32.   on error
  33.    set gotPID to false
  34.   end try
  35.   if gotPID then
  36.    exit repeat
  37.   end if
  38.   if tries > 10 then
  39.    exit repeat
  40.   end if
  41.  end repeat
  42.  if gotPID then
  43.   return sshPID
  44.  else
  45.   return false
  46.  end if
  47. end startTunnel
  48.  
  49. on setUseTunnel()
  50.  do shell script "scselect 'Use SOCKS5 Proxy on localhost:9999'"
  51. end setUseTunnel
  52.  
  53. on clearUseTunnel()
  54.  do shell script "scselect 'Automatic'"
  55. end clearUseTunnel
  56.  
  57. on stopTunnel(pid)
  58.  do shell script "kill " & pid
  59. end stopTunnel
  60.  
  61. on makeSSHKeyWithServer(targetServer)
  62.  tell application "Keychain Scripting"
  63.   repeat
  64.    set acctBox to display dialog "Enter your SSH login for host " & targetServer & ":" default answer "" buttons {"Cancel", "OK"} default button 2
  65.    set myAcct to the text returned of acctBox
  66.    set myButton to the button returned of acctBox
  67.    if myButton is "Cancel" then
  68.     –quit
  69.    else
  70.     if myAcct is not "" then
  71.      exit repeat
  72.     else
  73.      display dialog "bad login"
  74.     end if
  75.    end if
  76.   end repeat
  77.   repeat
  78.    set passBox to display dialog "Enter your password:" default answer "" buttons {"Cancel", "OK"} default button 2 with hidden answer
  79.    set myPass to the text returned of passBox
  80.    set myButton to the button returned of passBox
  81.    if myButton is "Cancel" then
  82.     –quit
  83.    else
  84.     if myPass is not "" then
  85.      exit repeat
  86.     else
  87.      display dialog "can't use blank passwd"
  88.     end if
  89.    end if
  90.   end repeat
  91.   set newSSHKey to make new Internet key with properties {name:"autoSSHTunnel", account:myAcct, password:myPass, server:targetServer, authentication:default, protocol:SSH}
  92.  end tell
  93.  return newSSHKey
  94. end makeSSHKeyWithServer

And here’s the actual script I run.

  1. property Lib : (path to scripts folder from user domain as text) & "Script Library:"
  2. property sshTunnelLib : load script Lib & "ssh_tunnel.scpt" as alias
  3.  
  4. sshTunnelLib's setUseTunnel()
  5.  
  6. set sshPID to sshTunnelLib's startTunnel("fqdn.of.your.server")
  7. if sshPID is not false then
  8.  set noPIDtxt to ""
  9.  set buttonTxt to "Kill SSH and Exit"
  10. else
  11.  set noPIDtxt to " (but couldn't get PID)"
  12.  set buttonTxt to "Exit"
  13. end if
  14.  
  15. display dialog "SSH-tunneled SOCKS5 proxy running on localhost:9999" & noPIDtxt buttons {buttonTxt}
  16.  
  17. if sshPID is not false then
  18.  sshTunnelLib's stopTunnel(sshPID)
  19. end if
  20.  
  21. sshTunnelLib's clearUseTunnel()
]]>
http://2718.us/blog/2008/06/13/ssh-tunneling-on-a-mac/feed/ 0