如何在 Python Paramiko 中通过 HTTP 代理 ssh? [英] How to ssh over HTTP proxy in Python Paramiko?

查看:527
本文介绍了如何在 Python Paramiko 中通过 HTTP 代理 ssh?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在改编一个 Python 脚本,使其独立于操作系统并在 Windows 上运行.我已将其 ssh 系统调用更改为对 paramiko 函数的调用.我遇到了 http 代理身份验证的问题.在 Unix(实际上是 Cygwin)环境中,我会使用 ~/.ssh/config

I am adapting a Python script to be OS independent and run on Windows. I have changed its ssh system calls to calls to paramiko functions. I am stuck with the issue of http proxy authentication. In Unix (actually Cygwin) environment I would use ~/.ssh/config

Host *
    ProxyCommand corkscrew http-proxy.example.com 8080 %h %p

有没有办法通过使用或不使用开瓶器的 paramiko(或 Python ssh 模块)获得相同的结果?这篇文章 似乎暗示了这一点,但我不知道如何.

Is there a way to obtain the same using paramiko (or the Python ssh module) either using or not using corkscrew? This post seems to suggest that, but I don't know how.

注意:我在防火墙后面,只允许我使用端口 80.我需要控制 Amazon ec2 实例,所以我在这些机器上配置了 sshd 服务器以侦听端口 80.在我的 cygwin+corkscrew 中一切正常原型,但我想要一个无需 Cygwin 即可运行的 Python 脚本.

Note: I am behind a firewall that allows me to use only port 80. I need to control Amazon ec2 instances so I configured the sshd server on those machines to listen to port 80. Everything is working fine in my cygwin+corkscrew prototype, but I would like to have a Python script that works without Cygwin.

推荐答案

您可以通过 SSHClient.connect(hostname,username,密码,...,袜子).

以下是通过 HTTP-Proxy-Tunnel (HTTP-CONNECT) 建立 SSH 隧道的代码片段.首先建立与代理的连接,并指示代理连接到 localhost:22.结果是建立的会话上的 TCP 隧道通常用于隧道 SSL,但可用于任何基于 tcp 的协议.

Below is a code-snippet that tunnels SSH via HTTP-Proxy-Tunnel (HTTP-CONNECT). At first the connection to the proxy is established and the proxy is instructed to connect to localhost:22. The result is a TCP tunnel over the established session that is usually used to tunnel SSL but can be used for any tcp based protocol.

此方案适用于 tinyproxy 的默认安装,其中 Allow ConnectPort 22/etc 中设置/tinyproxy.conf.在我的示例中,代理和 sshd 在同一台主机上运行,​​但您只需要任何允许您CONNECT 到您的 ssh 端口的代理.通常这仅限于端口 443(提示:如果您让 sshd 监听 443,这将适用于大多数公共代理,即使出于互操作和安全原因我不建议这样做).如果这最终允许您绕过防火墙,则取决于采用的防火墙类型.如果不涉及 DPI/SSL 拦截功能,您应该没问题.如果涉及 SSL 拦截,您仍然可以尝试通过 ssl 或作为 HTTP 有效负载的一部分对其进行隧道传输 :)

This scenario works with a default installation of tinyproxy with Allow <yourIP> and ConnectPort 22 being set in /etc/tinyproxy.conf. The proxy and the sshd are running on the same host in my example but all you need is any proxy that allows you to CONNECT to your ssh port. Usually this is restricted to port 443 (hint: if you make your sshd listen on 443 this will work with most of the public proxies even thought I do not recommend to do this for interop and security reasons). If this ultimately allows you to bypass your firewall depends on what kind of firewall is employed. If there's no DPI/SSL-Interception features involved, you should be fine. If there's SSL-Interception involved you could still try to tunnel it via ssl or as part of HTTP payload :)

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)

here are some other resources on how to tunnel through proxies. Just do whatever is needed to establish your tunnel and pass the socket to SSHClient.connect(...,sock)

这篇关于如何在 Python Paramiko 中通过 HTTP 代理 ssh?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆