Вы можете использовать любой предустановленный сеанс для paramiko через параметр sock
в SSHClient.connect(hostname,username,password,...,sock)
.
Ниже приведен фрагмент кода, который туннелирует SSH через HTTP-Proxy-Tunnel (HTTP-CONNECT). Сначала устанавливается соединение с прокси, и прокси получает указание подключиться к localhost: 22. Результатом является TCP-туннель через установленный сеанс, который обычно используется для туннелирования SSL, но может использоваться для любого протокола на основе tcp.
Этот сценарий работает с установкой по умолчанию tinyproxy
, где Allow <yourIP>
и ConnectPort 22
установлены в /etc/tinyproxy.conf
. В моем примере прокси и sshd работают на одном хосте, но все, что вам нужно, это любой прокси, который позволяет CONNECT
подключаться к вашему ssh-порту. Обычно это ограничено портом 443 (подсказка: если вы заставите свой sshd слушать на 443, это будет работать с большинством общедоступных прокси, даже если я не рекомендую делать это из соображений взаимодействия и безопасности). Если это в конечном итоге позволяет вам обойти ваш брандмауэр, зависит от того, какой тип брандмауэра используется. Если не задействованы функции перехвата DPI / SSL, все будет в порядке. Если есть SSL-перехват, вы все равно можете попробовать туннелировать его через ssl или как часть полезной нагрузки HTTP :)
import paramiko
import socket
import logging
logging.basicConfig(loglevel=logging.DEBUG)
LOG = logging.getLogger("xxx")
def http_proxy_tunnel_connect(proxy, target,timeout=None):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout)
sock.connect(proxy)
LOG.debug("connected")
cmd_connect = "CONNECT %s:%d HTTP/1.1\r\n\r\n"%target
LOG.debug("--> %s"%repr(cmd_connect))
sock.sendall(cmd_connect)
response = []
sock.settimeout(2) # quick hack - replace this with something better performing.
try:
# in worst case this loop will take 2 seconds if not response was received (sock.timeout)
while True:
chunk = sock.recv(1024)
if not chunk: # if something goes wrong
break
response.append(chunk)
if "\r\n\r\n" in chunk: # we do not want to read too far ;)
break
except socket.error, se:
if "timed out" not in se:
response=[se]
response = ''.join(response)
LOG.debug("<-- %s"%repr(response))
if not "200 connection established" in response.lower():
raise Exception("Unable to establish HTTP-Tunnel: %s"%repr(response))
return sock
if __name__=="__main__":
LOG.setLevel(logging.DEBUG)
LOG.debug("--start--")
sock = http_proxy_tunnel_connect(proxy=("192.168.139.128",8888),
target=("192.168.139.128",22),
timeout=50)
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname="192.168.139.128",sock=sock, username="xxxx", password="xxxxx")
print "#> whoami \n%s"% ssh.exec_command("whoami")[1].read()
выход:
DEBUG:xxx:--start--
DEBUG:xxx:connected
DEBUG:xxx:--> 'CONNECT 192.168.139.128:22 HTTP/1.1\r\n\r\n'
DEBUG:xxx:<-- 'HTTP/1.0 200 Connection established\r\nProxy-agent: tinyproxy/1.8.3\r\n\r\n'
#> whoami
root
здесь другие ресурсы о том, как туннелировать через прокси. Просто сделайте все необходимое для создания туннеля и передайте сокет SSHClient.connect(...,sock)
person
tintin
schedule
17.11.2015