Вопрос по ssh, python, paramiko, http-tunneling – Как SSH через HTTP прокси в Python?

1

Я адаптирую скрипт Python, чтобы он не зависел от ОС и работал в Windows. Я изменил его системные вызовы SSH на вызовыparamiko функции. Я застрял с проблемой проверки подлинности прокси http. В среде Unix (на самом деле Cygwin) я бы использовал ~ / .ssh / config

<code>Host *
    ProxyCommand corkscrew http-proxy.example.com 8080 %h %p
</code>

Есть ли способ получить то же самое, используя paramiko (или модуль Python ssh), используя или не используя corkscrew?Эта почта кажется, предлагает это, но я не знаю как.

Примечание: я нахожусь за брандмауэром, который позволяет мне использовать только порт 80. Мне нужно контролировать экземпляры Amazon ec2, поэтому я настроил сервер sshd на этих машинах для прослушивания порта 80. В моем прототипе cygwin + corkscrew все работает нормально, но Я хотел бы иметь скрипт Python, который работает без Cygwin.

Ваш Ответ

2   ответа
1

paraproxy, который реализует поддержку прокси для Paramiko.

Пост, на который вы ссылаетесь, предполагает, что Paramiko может работать через произвольный сокет, но, похоже, это не так. На самом деле paraproxy работает путем завершения замены определенных методов внутри paramiko, поскольку существующий код просто вызываетsocket.socket() получить сокет и не предлагает никакого способа перехвата прокси.

Это все еще демонстрирует технику исправления Paramiko с поддержкой прокси. Надеюсь, кто-то придет с лучшим ответом.
ОП запросил поддержку Windows, но в соответствии с README Paraproxy 1.2: Переносимость Парапрокси требует доменных сокетов unix, чтобы сделать это волшебством. В результате поддержка доступна только для Linux и MacOS (это может измениться в зависимости от спроса на поддержку Win32).
5

через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)

Похожие вопросы