Skip to content

Instantly share code, notes, and snippets.

@u8sand
Last active August 17, 2022 15:32
Show Gist options
  • Save u8sand/0df0f75190717c3963e2bcb6e47e02dc to your computer and use it in GitHub Desktop.
Save u8sand/0df0f75190717c3963e2bcb6e47e02dc to your computer and use it in GitHub Desktop.
A wrapper script for generating proxychains config and running proxychains with a sane command-line interface
#!/bin/python
import sys
import click
import socket
import contextlib
import urllib.parse
import tempfile
from subprocess import Popen
def free_port():
with contextlib.closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
s.bind(('127.0.0.1', 0))
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
return s.getsockname()[1]
@click.command(
context_settings=dict(
ignore_unknown_options=True,
allow_interspersed_args=False,
)
)
@click.option(
'-t', '--chain-type',
default='strict',
show_default=True,
type=click.Choice([
'strict',
'dynamic',
'round_robin',
'random',
]),
help='Chain type as described by proxychains config'
)
@click.option(
'-l', '--chain-len',
type=int,
help='Length of the chain (for random_chain/round_robin_chain)',
)
@click.option(
'--remote-dns-subnet',
type=int,
default=224,
show_default=True,
help='remote_dns_subnet as described by proxychains'
)
@click.option(
'-d', '--proxy-dns',
type=bool,
is_flag=True,
help='proxy_dns as described by proxychains'
)
@click.option(
'-e', '--localnet',
type=str,
multiple=True,
help='localnet as described by proxychains',
)
@click.option(
'-q', '--quiet',
type=bool,
is_flag=True,
help='Quiet mode',
)
@click.option(
'--tcp-read-time-out',
type=int,
default=15000,
show_default=True,
help='tcp_read_time_out as described by proxychains',
)
@click.option(
'--tcp-connect-time-out',
type=int,
default=8000,
show_default=True,
help='tcp_connect_time_out as described by proxychains',
)
@click.option(
'-p', '--proxy',
multiple=True,
type=str,
help='Any socks uris for the proxy list e.g. `-p socks5://host:1002 -p socks4://user:passs@host2:1000`',
)
@click.option(
'-J', '--jump',
help='Jump host(s) for using ssh to setup the proxy server',
)
@click.argument(
'command',
nargs=-1,
type=click.UNPROCESSED,
)
def proxychains(
command,
chain_type,
chain_len,
remote_dns_subnet,
proxy_dns,
localnet,
quiet,
tcp_read_time_out,
tcp_connect_time_out,
proxy,
jump,
):
assert proxy is not None or jump is not None, '-p, --proxy or -J, --jump must be provided'
assert proxy is None or jump is None, 'proxy and jump are mutually exclusive'
if proxy is None:
port = free_port()
*prelim_jumps, final_jump = jump.split(',')
proxy_proc = Popen([
'ssh',
*((f"-J{','.join(prelim_jumps)}",) if prelim_jumps else tuple()),
f"-ND{port}",
final_jump,
], stdout=sys.stdout, stderr=sys.stderr)
proxy = [f"socks5://127.0.0.1:{port}"]
else:
proxy_proc = None
#
config_lines = []
config_lines.append('%s_chain' % (chain_type))
if chain_len is not None: config_lines.append('chain_len %d' % (chain_len))
if remote_dns_subnet is not None: config_lines.append('remote_dns_subnet %d' % (remote_dns_subnet))
if tcp_read_time_out is not None: config_lines.append('tcp_read_time_out %d' % (tcp_read_time_out))
if tcp_connect_time_out is not None: config_lines.append('tcp_connect_time_out %d' % (tcp_connect_time_out))
if localnet is not None: config_lines += ['localnet %s' % (line) for line in localnet]
if proxy_dns: config_lines.append('proxy_dns')
if quiet: config_lines.append('quiet')
config_lines.append('[ProxyList]')
for proxy in proxy:
proxy_uri = urllib.parse.urlparse(proxy)
config_lines.append(
' '.join(map(str, filter(None, (
proxy_uri.scheme,
proxy_uri.hostname,
proxy_uri.port,
proxy_uri.username,
proxy_uri.password,
))))
)
exit_code = 1
with tempfile.NamedTemporaryFile('w') as proxy_config:
print(*config_lines, sep='\n', file=proxy_config.file)
proxy_config.file.close()
with Popen(['proxychains', '-f', proxy_config.name, *command],
stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr) as proc:
exit_code = proc.wait()
if proxy_proc is not None:
proxy_proc.terminate()
sys.exit(exit_code)
if __name__ == '__main__':
proxychains()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment