Last active
October 13, 2015 09:23
-
-
Save michaelballantyne/8928195 to your computer and use it in GitHub Desktop.
Yet another Mac SSH SOCKS proxy script. This one handles connection failure properly.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# Public domain. | |
"""A script to establish an SSH SOCKS proxy and enable it in the OS X network configuration. | |
Cleanly handles failure to connect. Kills ssh and removes network configuration on CTRL-C. | |
First argument gives the hostname for use with ssh.""" | |
import subprocess, sys, signal | |
proxy_command_base = ['networksetup', '-setsocksfirewallproxystate', 'Wi-Fi'] | |
host = sys.argv[1] | |
ssh = subprocess.Popen([ | |
'ssh', '-ND', '1080', | |
# Have ssh print 'connected' after successful connection | |
'-o', 'PermitLocalCommand=yes', | |
'-o', "LocalCommand=echo connected", | |
host], | |
stdout=subprocess.PIPE | |
) | |
try: | |
# Only proceed with SOCKS configuration once ssh has connected successfully. | |
# If there was an error, it will have gone to stderr and stdout will be empty. | |
if ssh.stdout.readline() == "connected\n": | |
# Open and keep open a shell with root priviledges. sudo will prompt for password here. | |
admin_shell = subprocess.Popen( | |
['sudo', '-s'], | |
# Line buffered so we're sure the shell gets our commands immediately. | |
bufsize=1, | |
stdin=subprocess.PIPE, | |
# Don't let SIGINT (ctrl-c) kill the shell - we need to use it to clean up. | |
preexec_fn = lambda: signal.signal(signal.SIGINT, signal.SIG_IGN) | |
) | |
try: | |
admin_shell.stdin.write(' '.join(proxy_command_base + ['on']) + \ | |
" && echo 'SOCKS proxy via %s on. CTRL-C to turn off.'\n" % host) | |
# Block here until ssh exits from SIGINT (ctrl-c) or loss of network connection, etc) | |
ssh.wait() | |
# SIGINT will have killed ssh; carry on to clean up SOCKS config. | |
except KeyboardInterrupt: | |
admin_shell.stdin.write(' '.join(proxy_command_base + ['off']) + ' && echo "SOCKS proxy off."\n') | |
admin_shell.stdin.close() | |
admin_shell.wait() | |
finally: | |
# If something goes wrong with the proxy config, make sure we kill ssh. | |
if ssh.poll() is None: | |
ssh.kill() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment