如何在Python中ssh over http代理?

时间:2012-05-07 20:42:11

标签: python ssh paramiko http-tunneling

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

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

使用或不使用开瓶器有没有办法使用paramiko(或Python ssh模块)获得相同的效果? This post似乎暗示了这一点,但我不知道如何。

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

2 个答案:

答案 0 :(得分:5)

您可以通过sock中的SSHClient.connect(hostname,username,password,...,sock)参数将任何预先建立的会话用于paramiko。

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

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

CONNECT

输出:

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()

here are关于如何隧道通过代理的其他一些资源。只需执行建立隧道所需的任何内容并将套接字传递给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

答案 1 :(得分:1)

paraproxy,它为Paramiko实现了代理支持。

您链接到Paramiko可以在任意套接字上运行的建议的帖子,但情况似乎并非如此。实际上,paraproxy通过完成替换paramiko中的特定方法来工作,因为现有代码只是调用socket.socket()来获取套接字,并且不提供在代理中挂钩的任何方式。