1#!/usr/bin/env python 2 3'''This starts an SSH tunnel to a given host. If the SSH process ever dies then 4this script will detect that and restart it. I use this under Cygwin to keep 5open encrypted tunnels to port 25 (SMTP), port 143 (IMAP4), and port 110 6(POP3). I set my mail client to talk to localhost and I keep this script 7running in the background. 8 9Note that this is a rather stupid script at the moment because it just looks to 10see if any ssh process is running. It should really make sure that our specific 11ssh process is running. The problem is that ssh is missing a very useful 12feature. It has no way to report the process id of the background daemon that 13it creates with the -f command. This would be a really useful script if I could 14figure a way around this problem. 15 16PEXPECT LICENSE 17 18 This license is approved by the OSI and FSF as GPL-compatible. 19 http://opensource.org/licenses/isc-license.txt 20 21 Copyright (c) 2012, Noah Spurrier <noah@noah.org> 22 PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY 23 PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE 24 COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. 25 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 26 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 27 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 28 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 29 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 30 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 31 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 32 33''' 34 35from __future__ import print_function 36 37from __future__ import absolute_import 38 39import pexpect 40import getpass 41import time 42 43 44try: 45 raw_input 46except NameError: 47 raw_input = input 48 49 50# SMTP:25 IMAP4:143 POP3:110 51tunnel_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)' 52host = raw_input('Hostname: ') 53user = raw_input('Username: ') 54X = getpass.getpass('Password: ') 55 56def get_process_info (): 57 58 # This seems to work on both Linux and BSD, but should otherwise be considered highly UNportable. 59 60 ps = pexpect.run ('ps ax -O ppid') 61 pass 62 63def start_tunnel (): 64 65 try: 66 ssh_tunnel = pexpect.spawn (tunnel_command % globals()) 67 ssh_tunnel.expect ('password:') 68 time.sleep (0.1) 69 ssh_tunnel.sendline (X) 70 time.sleep (60) # Cygwin is slow to update process status. 71 ssh_tunnel.expect (pexpect.EOF) 72 73 except Exception as e: 74 print(str(e)) 75 76def main (): 77 78 while True: 79 ps = pexpect.spawn ('ps') 80 time.sleep (1) 81 index = ps.expect (['/usr/bin/ssh', pexpect.EOF, pexpect.TIMEOUT]) 82 if index == 2: 83 print('TIMEOUT in ps command...') 84 print(str(ps)) 85 time.sleep (13) 86 if index == 1: 87 print(time.asctime(), end=' ') 88 print('restarting tunnel') 89 start_tunnel () 90 time.sleep (11) 91 print('tunnel OK') 92 else: 93 # print 'tunnel OK' 94 time.sleep (7) 95 96if __name__ == '__main__': 97 98 main () 99 100# This was for older SSH versions that didn't have -f option 101#tunnel_command = 'ssh -C -n -L 25:%(host)s:25 -L 110:%(host)s:110 %(user)s@%(host)s -f nothing.sh' 102#nothing_script = '''#!/bin/sh 103#while true; do sleep 53; done 104#''' 105 106