2010-05-01 22:15:37 +02:00
|
|
|
#!/usr/bin/env python
|
2010-05-02 05:14:42 +02:00
|
|
|
import sys, os, re
|
2011-01-11 13:52:02 +01:00
|
|
|
import helpers, options, client, server, firewall, hostwatch, ssnet
|
2011-01-01 07:54:07 +01:00
|
|
|
import compat.ssubprocess as ssubprocess
|
2010-05-02 08:23:42 +02:00
|
|
|
from helpers import *
|
2010-05-02 03:14:19 +02:00
|
|
|
|
|
|
|
|
|
|
|
# list of:
|
|
|
|
# 1.2.3.4/5 or just 1.2.3.4
|
|
|
|
def parse_subnets(subnets_str):
|
|
|
|
subnets = []
|
|
|
|
for s in subnets_str:
|
2010-05-02 03:30:59 +02:00
|
|
|
m = re.match(r'(\d+)(?:\.(\d+)\.(\d+)\.(\d+))?(?:/(\d+))?$', s)
|
2010-05-02 03:14:19 +02:00
|
|
|
if not m:
|
2010-05-02 08:23:42 +02:00
|
|
|
raise Fatal('%r is not a valid IP subnet format' % s)
|
2010-05-02 03:14:19 +02:00
|
|
|
(a,b,c,d,width) = m.groups()
|
|
|
|
(a,b,c,d) = (int(a or 0), int(b or 0), int(c or 0), int(d or 0))
|
|
|
|
if width == None:
|
|
|
|
width = 32
|
|
|
|
else:
|
|
|
|
width = int(width)
|
|
|
|
if a > 255 or b > 255 or c > 255 or d > 255:
|
2010-05-02 08:23:42 +02:00
|
|
|
raise Fatal('%d.%d.%d.%d has numbers > 255' % (a,b,c,d))
|
2010-05-02 03:14:19 +02:00
|
|
|
if width > 32:
|
2010-05-02 08:23:42 +02:00
|
|
|
raise Fatal('*/%d is greater than the maximum of 32' % width)
|
2010-05-02 03:14:19 +02:00
|
|
|
subnets.append(('%d.%d.%d.%d' % (a,b,c,d), width))
|
|
|
|
return subnets
|
|
|
|
|
|
|
|
|
|
|
|
# 1.2.3.4:567 or just 1.2.3.4 or just 567
|
|
|
|
def parse_ipport(s):
|
|
|
|
s = str(s)
|
|
|
|
m = re.match(r'(?:(\d+)\.(\d+)\.(\d+)\.(\d+))?(?::)?(?:(\d+))?$', s)
|
|
|
|
if not m:
|
2010-05-02 08:23:42 +02:00
|
|
|
raise Fatal('%r is not a valid IP:port format' % s)
|
2010-05-02 03:14:19 +02:00
|
|
|
(a,b,c,d,port) = m.groups()
|
|
|
|
(a,b,c,d,port) = (int(a or 0), int(b or 0), int(c or 0), int(d or 0),
|
|
|
|
int(port or 0))
|
|
|
|
if a > 255 or b > 255 or c > 255 or d > 255:
|
2010-05-02 08:23:42 +02:00
|
|
|
raise Fatal('%d.%d.%d.%d has numbers > 255' % (a,b,c,d))
|
2010-05-02 03:14:19 +02:00
|
|
|
if port > 65535:
|
2010-05-02 08:23:42 +02:00
|
|
|
raise Fatal('*:%d is greater than the maximum of 65535' % port)
|
2010-05-02 03:14:19 +02:00
|
|
|
if a == None:
|
|
|
|
a = b = c = d = 0
|
|
|
|
return ('%d.%d.%d.%d' % (a,b,c,d), port)
|
|
|
|
|
2010-05-02 02:03:50 +02:00
|
|
|
|
|
|
|
optspec = """
|
2010-05-04 19:07:51 +02:00
|
|
|
sshuttle [-l [ip:]port] [-r [username@]sshserver[:port]] <subnets...>
|
2010-05-02 03:14:19 +02:00
|
|
|
sshuttle --server
|
2011-01-01 07:54:07 +01:00
|
|
|
sshuttle --firewall <port> <subnets...>
|
|
|
|
sshuttle --hostwatch
|
2010-05-02 02:03:50 +02:00
|
|
|
--
|
2011-01-11 13:52:02 +01:00
|
|
|
f,disable-fullness turn off fullness checking (could 10x bandwidth on high latency link)
|
2011-01-01 06:21:17 +01:00
|
|
|
l,listen= transproxy to this ip address and port number [127.0.0.1:0]
|
Added new --auto-hosts and --seed-hosts options to the client.
Now if you use --auto-hosts (-H), the client will ask the server to spawn a
hostwatcher to add names. That, in turn, will send names back to the
server, which sends them back to the client, which sends them to the
firewall subprocess, which will write them to /etc/hosts. Whew!
Only the firewall process can write to /etc/hosts, of course, because only
he's running as root.
Since the name discovery process is kind of slow, we cache the names in
~/.sshuttle.hosts on the remote server.
Right now, most of the names are discovered using nmblookup and smbclient,
as well as by reading the existing entries in /etc/hosts. What would really
be nice would be to query active directory or mdns somehow... but I don't
really know how those work, so this is what you get for now :) It's pretty
neat, at least.
2010-05-08 09:03:12 +02:00
|
|
|
H,auto-hosts scan for remote hostnames and update local /etc/hosts
|
|
|
|
N,auto-nets automatically determine subnets to route
|
2011-01-01 07:25:03 +01:00
|
|
|
python= path to python interpreter on the remote server [python]
|
2010-05-02 02:03:50 +02:00
|
|
|
r,remote= ssh hostname (and optional username) of remote sshuttle server
|
2010-07-15 20:07:01 +02:00
|
|
|
x,exclude= exclude this subnet (can be used more than once)
|
2010-05-02 08:14:20 +02:00
|
|
|
v,verbose increase debug message verbosity
|
2010-11-09 09:17:01 +01:00
|
|
|
e,ssh-cmd= the command to use to connect to the remote [ssh]
|
Added new --auto-hosts and --seed-hosts options to the client.
Now if you use --auto-hosts (-H), the client will ask the server to spawn a
hostwatcher to add names. That, in turn, will send names back to the
server, which sends them back to the client, which sends them to the
firewall subprocess, which will write them to /etc/hosts. Whew!
Only the firewall process can write to /etc/hosts, of course, because only
he's running as root.
Since the name discovery process is kind of slow, we cache the names in
~/.sshuttle.hosts on the remote server.
Right now, most of the names are discovered using nmblookup and smbclient,
as well as by reading the existing entries in /etc/hosts. What would really
be nice would be to query active directory or mdns somehow... but I don't
really know how those work, so this is what you get for now :) It's pretty
neat, at least.
2010-05-08 09:03:12 +02:00
|
|
|
seed-hosts= with -H, use these hostnames for initial scan (comma-separated)
|
2011-01-01 07:54:07 +01:00
|
|
|
D,daemon run in the background as a daemon
|
|
|
|
syslog send log messages to syslog (default if you use --daemon)
|
|
|
|
pidfile= pidfile name (only if using --daemon) [./sshuttle.pid]
|
2010-09-04 07:58:44 +02:00
|
|
|
server (internal use only)
|
|
|
|
firewall (internal use only)
|
|
|
|
hostwatch (internal use only)
|
2010-05-02 02:03:50 +02:00
|
|
|
"""
|
|
|
|
o = options.Options('sshuttle', optspec)
|
|
|
|
(opt, flags, extra) = o.parse(sys.argv[1:])
|
|
|
|
|
2011-01-01 07:54:07 +01:00
|
|
|
if opt.daemon:
|
|
|
|
opt.syslog = 1
|
2010-05-02 08:14:20 +02:00
|
|
|
helpers.verbose = opt.verbose
|
2011-01-11 13:52:02 +01:00
|
|
|
ssnet.no_fullness = opt.disable_fullness
|
2010-05-02 08:23:42 +02:00
|
|
|
try:
|
|
|
|
if opt.server:
|
2010-05-08 07:30:34 +02:00
|
|
|
if len(extra) != 0:
|
|
|
|
o.fatal('no arguments expected')
|
2010-05-02 08:23:42 +02:00
|
|
|
sys.exit(server.main())
|
2010-05-05 04:05:49 +02:00
|
|
|
elif opt.firewall:
|
2010-05-08 02:02:04 +02:00
|
|
|
if len(extra) != 1:
|
|
|
|
o.fatal('exactly one argument expected')
|
2011-01-01 09:06:04 +01:00
|
|
|
sys.exit(firewall.main(int(extra[0]), opt.syslog))
|
2010-05-08 07:30:34 +02:00
|
|
|
elif opt.hostwatch:
|
|
|
|
sys.exit(hostwatch.hw_main(extra))
|
2010-05-02 08:23:42 +02:00
|
|
|
else:
|
2010-05-08 02:02:04 +02:00
|
|
|
if len(extra) < 1 and not opt.auto_nets:
|
|
|
|
o.fatal('at least one subnet (or -N) expected')
|
2010-07-15 20:07:01 +02:00
|
|
|
includes = extra
|
|
|
|
excludes = ['127.0.0.0/8']
|
|
|
|
for k,v in flags:
|
|
|
|
if k in ('-x','--exclude'):
|
|
|
|
excludes.append(v)
|
2010-05-02 08:23:42 +02:00
|
|
|
remotename = opt.remote
|
|
|
|
if remotename == '' or remotename == '-':
|
|
|
|
remotename = None
|
Added new --auto-hosts and --seed-hosts options to the client.
Now if you use --auto-hosts (-H), the client will ask the server to spawn a
hostwatcher to add names. That, in turn, will send names back to the
server, which sends them back to the client, which sends them to the
firewall subprocess, which will write them to /etc/hosts. Whew!
Only the firewall process can write to /etc/hosts, of course, because only
he's running as root.
Since the name discovery process is kind of slow, we cache the names in
~/.sshuttle.hosts on the remote server.
Right now, most of the names are discovered using nmblookup and smbclient,
as well as by reading the existing entries in /etc/hosts. What would really
be nice would be to query active directory or mdns somehow... but I don't
really know how those work, so this is what you get for now :) It's pretty
neat, at least.
2010-05-08 09:03:12 +02:00
|
|
|
if opt.seed_hosts and not opt.auto_hosts:
|
|
|
|
o.fatal('--seed-hosts only works if you also use -H')
|
|
|
|
if opt.seed_hosts:
|
|
|
|
sh = re.split(r'[\s,]+', (opt.seed_hosts or "").strip())
|
|
|
|
elif opt.auto_hosts:
|
|
|
|
sh = []
|
|
|
|
else:
|
|
|
|
sh = None
|
2010-05-02 08:23:42 +02:00
|
|
|
sys.exit(client.main(parse_ipport(opt.listen or '0.0.0.0:0'),
|
2010-11-09 09:17:01 +01:00
|
|
|
opt.ssh_cmd,
|
2010-05-02 08:23:42 +02:00
|
|
|
remotename,
|
2010-11-09 09:17:01 +01:00
|
|
|
opt.python,
|
Added new --auto-hosts and --seed-hosts options to the client.
Now if you use --auto-hosts (-H), the client will ask the server to spawn a
hostwatcher to add names. That, in turn, will send names back to the
server, which sends them back to the client, which sends them to the
firewall subprocess, which will write them to /etc/hosts. Whew!
Only the firewall process can write to /etc/hosts, of course, because only
he's running as root.
Since the name discovery process is kind of slow, we cache the names in
~/.sshuttle.hosts on the remote server.
Right now, most of the names are discovered using nmblookup and smbclient,
as well as by reading the existing entries in /etc/hosts. What would really
be nice would be to query active directory or mdns somehow... but I don't
really know how those work, so this is what you get for now :) It's pretty
neat, at least.
2010-05-08 09:03:12 +02:00
|
|
|
sh,
|
2010-05-08 02:02:04 +02:00
|
|
|
opt.auto_nets,
|
2010-07-15 20:07:01 +02:00
|
|
|
parse_subnets(includes),
|
2010-12-05 13:05:35 +01:00
|
|
|
parse_subnets(excludes),
|
2011-01-01 07:54:07 +01:00
|
|
|
opt.syslog, opt.daemon, opt.pidfile))
|
2010-05-02 08:23:42 +02:00
|
|
|
except Fatal, e:
|
|
|
|
log('fatal: %s\n' % e)
|
|
|
|
sys.exit(99)
|
|
|
|
except KeyboardInterrupt:
|
2010-05-03 01:29:03 +02:00
|
|
|
log('\n')
|
|
|
|
log('Keyboard interrupt: exiting.\n')
|
2010-05-02 08:23:42 +02:00
|
|
|
sys.exit(1)
|