18a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen#!/usr/bin/env python 28a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen 38a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen"""This starts an SSH tunnel to a given host. If the SSH process ever dies then 48a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chenthis script will detect that and restart it. I use this under Cygwin to keep 58a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chenopen encrypted tunnels to port 25 (SMTP), port 143 (IMAP4), and port 110 68a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen(POP3). I set my mail client to talk to localhost and I keep this script 78a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chenrunning in the background. 88a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen 98a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny ChenNote that this is a rather stupid script at the moment because it just looks to 108a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chensee if any ssh process is running. It should really make sure that our specific 118a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chenssh process is running. The problem is that ssh is missing a very useful 128a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chenfeature. It has no way to report the process id of the background daemon that 138a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chenit creates with the -f command. This would be a really useful script if I could 148a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chenfigure a way around this problem. """ 158a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen 168a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chenimport pexpect 178a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chenimport getpass 188a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chenimport time 198a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen 208a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen# SMTP:25 IMAP4:143 POP3:110 218a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chentunnel_command = 'ssh -C -N -f -L 25:127.0.0.1:25 -L 143:127.0.0.1:143 -L 110:127.0.0.1:110 %(user)@%(host)' 228a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chenhost = raw_input('Hostname: ') 238a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chenuser = raw_input('Username: ') 248a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny ChenX = getpass.getpass('Password: ') 258a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen 268a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chendef get_process_info (): 278a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen 288a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen # This seems to work on both Linux and BSD, but should otherwise be considered highly UNportable. 298a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen 308a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen ps = pexpect.run ('ps ax -O ppid') 318a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen pass 328a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chendef start_tunnel (): 338a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen try: 348a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen ssh_tunnel = pexpect.spawn (tunnel_command % globals()) 358a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen ssh_tunnel.expect ('password:') 368a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen time.sleep (0.1) 378a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen ssh_tunnel.sendline (X) 388a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen time.sleep (60) # Cygwin is slow to update process status. 398a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen ssh_tunnel.expect (pexpect.EOF) 408a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen 418a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen except Exception, e: 428a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen print str(e) 438a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen 448a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chendef main (): 458a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen 468a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen while True: 478a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen ps = pexpect.spawn ('ps') 488a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen time.sleep (1) 498a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen index = ps.expect (['/usr/bin/ssh', pexpect.EOF, pexpect.TIMEOUT]) 508a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen if index == 2: 518a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen print 'TIMEOUT in ps command...' 528a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen print str(ps) 538a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen time.sleep (13) 548a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen if index == 1: 558a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen print time.asctime(), 568a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen print 'restarting tunnel' 578a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen start_tunnel () 588a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen time.sleep (11) 598a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen print 'tunnel OK' 608a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen else: 618a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen # print 'tunnel OK' 628a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen time.sleep (7) 638a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen 648a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chenif __name__ == '__main__': 658a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen main () 668a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen 678a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen# This was for older SSH versions that didn't have -f option 688a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen#tunnel_command = 'ssh -C -n -L 25:%(host)s:25 -L 110:%(host)s:110 %(user)s@%(host)s -f nothing.sh' 698a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen#nothing_script = """#!/bin/sh 708a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen#while true; do sleep 53; done 718a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen#""" 728a3c0430323c28c1fbe8ceecd2cd8e58b64a9295Johnny Chen 73