Skip to content

feature: add source address support via paramiko sock #323

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions webssh/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,12 @@ def get_port(self):
raise InvalidValueError('Invalid port: {}'.format(value))
return port

def get_source_address(self):
value = self.get_argument('source_address', u'')
if value and not is_valid_ip_address(value):
raise InvalidValueError('Invalid source ip address: {}'.format(value))
return value

def lookup_hostname(self, hostname, port):
key = hostname if port == 22 else '[{}]:{}'.format(hostname, port)

Expand All @@ -395,6 +401,7 @@ def get_args(self):
privatekey, filename = self.get_privatekey()
passphrase = self.get_argument('passphrase', u'')
totp = self.get_argument('totp', u'')
source_address = self.get_argument('source_address', u'')

if isinstance(self.policy, paramiko.RejectPolicy):
self.lookup_hostname(hostname, port)
Expand All @@ -405,7 +412,7 @@ def get_args(self):
pkey = None

self.ssh_client.totp = totp
args = (hostname, port, username, password, pkey)
args = (hostname, port, username, password, pkey, source_address)
logging.debug(args)

return args
Expand Down Expand Up @@ -451,8 +458,23 @@ def ssh_connect(self, args):
dst_addr = args[:2]
logging.info('Connecting to {}:{}'.format(*dst_addr))

sock = None
source_address = args[5]
if source_address:
logging.info('Connecting source address socket')
sock = socket.socket()
sock.settimeout(options.timeout) # Set a timeout on blocking socket operations
try:
sock.bind((source_address, 0))
except OSError:
raise InvalidValueError('Unable to bind source address {} socket'.format(source_address))
try:
sock.connect(dst_addr)
except socket.error:
raise ValueError('Unable to connect source address socket to {}:{}'.format(*dst_addr))

try:
ssh.connect(*args, timeout=options.timeout)
ssh.connect(*args, sock=sock, timeout=options.timeout)
except socket.error:
raise ValueError('Unable to connect to {}:{}'.format(*dst_addr))
except paramiko.BadAuthenticationType:
Expand Down
2 changes: 2 additions & 0 deletions webssh/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@
<input class="form-control" type="password" id="totp" name="totp" value="">
</div>
<div class="col">
<label for="source_address">Source Address (optional)</label>
<input class="form-control" type="text" id="source_address" name="source_address" value="">
</div>
</div>
<input type="hidden" id="term" name="term" value="xterm-256color">
Expand Down