如何使用 Twisted 创建非 http 代理

发布于 2024-11-14 18:35:47 字数 215 浏览 0 评论 0原文

如何使用 Twisted 创建非 http 代理。相反,我想为完全由二进制数据组成的泰拉瑞亚协议执行此操作。我看到他们有一个内置的 HTTP 连接代理,但这个应用程序需要更像一个转发到设定服务器的入口点(几乎像 IRC 上的 BNC)。 我不知道如何从一个连接读取数据并将其发送到另一个连接。

我已经尝试使用套接字来完成此任务,但是阻塞接收和发送方法不能很好地工作,因为两个连接需要同时处于活动状态。

How can I create a non-http proxy with Twisted. Instead I would like to do it for the Terraria protocol which is made entirely of binary data. I see that they have a built-in proxy for HTTP connections, but this application needs to act more like an entry point which is forwarded to a set server (almost like a BNC on IRC).
I can't figure out how to read the data off of one connection and send it to the other connection.

I have already tried using a socket for this task, but the blocking recv and send methods do not work well as two connections need to be live at the same time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

倾城°AllureLove 2024-11-21 18:35:47

在 Twisted 中创建代理有多种不同的方法。基本技术建立在对等互连的基础上,通过在两个不同的端口上采用两种不同的协议,并以某种方式将它们粘合在一起,以便它们可以相互交换数据。

最简单的代理是端口转发器。 Twisted 附带端口转发器实现,请参阅 http://twistedmatrix.com/documents/current/ api/twisted.protocols.portforward.html 用于(未记录的)类 ProxyClientProxyServer,尽管实际源位于 http://twistedmatrix.com/trac/browser/tags/releases/ twisted-11.0.0/twisted/protocols/portforward.py 可能更适合阅读。从那里,我们可以看到 Twisted 中代理的基本技术:

def dataReceived(self, data):
    self.peer.transport.write(data)

当代理协议接收到数据时,它会将其发送给另一端的对等点。就是这样!很简单。当然,您通常需要一些额外的设置...让我们看一下我之前编写的几个代理。

这是 Darklight 的代理,是我编写的一个小型点对点系统。它正在与后端服务器通信,并且仅在数据与预定义标头不匹配时才代理数据。您可以看到它使用 ProxyClientFactory 和端点(基本上是花哨的 ClientCreator)来启动代理,当它接收到数据时,它有机会在继续之前检查它,或者保持代理或切换协议。

class DarkServerProtocol(Protocol):
    """
    Shim protocol for servers.
    """

    peer = None
    buf = ""

    def __init__(self, endpoint):
        self.endpoint = endpoint
        print "Protocol created..."

    def challenge(self, challenge):
        log.msg("Challenged: %s" % challenge)
        # ...omitted for brevity...
        return is_valid(challenge)

    def connectionMade(self):
        pcf = ProxyClientFactory()
        pcf.setServer(self)
        d = self.endpoint.connect(pcf)
        d.addErrback(lambda failure: self.transport.loseConnection())

        self.transport.pauseProducing()

    def setPeer(self, peer):
        # Our proxy passthrough has succeeded, so we will be seeing data
        # coming through shortly.
        log.msg("Established passthrough")
        self.peer = peer

    def dataReceived(self, data):
        self.buf += data

        # Examine whether we have received a challenge.
        if self.challenge(self.buf):
            # Excellent; change protocol.
            p = DarkAMP()
            p.factory = self.factory
            self.transport.protocol = p
            p.makeConnection(self.transport)
        elif self.peer:
            # Well, go ahead and send it through.
            self.peer.transport.write(data)

这是一个相当复杂的代码块,它需要两个 StatefulProtocol 并将它们相当有力地粘合在一起。这是来自 VNC 代理(准确地说是 https://code.osuosl.org/projects/twisted-vncauthproxy),它需要其协议在准备加入之前执行大量预身份验证操作。这种代理是最坏的情况;为了速度,您不想与通过代理的数据进行交互,但您需要事先进行一些设置。

def start_proxying(result):
    """
    Callback to start proxies.
    """

    log.msg("Starting proxy")
    client_result, server_result = result
    success = True
    client_success, client = client_result
    server_success, server = server_result

    if not client_success:
        success = False
        log.err("Had issues on client side...")
        log.err(client)

    if not server_success:
        success = False
        log.err("Had issues on server side...")
        log.err(server)

    if not success:
        log.err("Had issues connecting, disconnecting both sides")
        if not isinstance(client, Failure):
            client.transport.loseConnection()
        if not isinstance(server, Failure):
            server.transport.loseConnection()
        return

    server.dataReceived = client.transport.write
    client.dataReceived = server.transport.write
    # Replay last bits of stuff in the pipe, if there's anything left.
    data = server._sful_data[1].read()
    if data:
        client.transport.write(data)
    data = client._sful_data[1].read()
    if data:
        server.transport.write(data)

    server.transport.resumeProducing()
    client.transport.resumeProducing()
    log.msg("Proxying started!")

所以,既然我已经解释了……

我也写了《Bravo》。如http://www.bravoserver.org/。所以我对《我的世界》有所了解,进而对泰拉瑞亚有所了解。您可能想要解析两侧通过代理发送的数据包,因此您的实际代理可能一开始看起来像这样,但当您开始了解所代理的数据时,它会迅速发展。希望这足以让您开始!

There are several different ways to create proxies in Twisted. The basic technique is built on peering, by taking two different protocols, on two different ports, and somehow gluing them together so that they can exchange data with each other.

The simplest proxy is a port-forwarder. Twisted ships with a port-forwarder implementation, see http://twistedmatrix.com/documents/current/api/twisted.protocols.portforward.html for the (underdocumented) classes ProxyClient and ProxyServer, although the actual source at http://twistedmatrix.com/trac/browser/tags/releases/twisted-11.0.0/twisted/protocols/portforward.py might be more useful to read through. From there, we can see the basic technique of proxying in Twisted:

def dataReceived(self, data):
    self.peer.transport.write(data)

When a proxying protocol receives data, it puts it out to the peer on the other side. That's it! Quite simple. Of course, you'll usually need some extra setup... Let's look at a couple of proxies I've written before.

This is a proxy for Darklight, a little peer-to-peer system I wrote. It is talking to a backend server, and it wants to only proxy data if the data doesn't match a predefined header. You can see that it uses ProxyClientFactory and endpoints (fancy ClientCreator, basically) to start proxying, and when it receives data, it has an opportunity to examine it before continuing, either to keep proxying or to switch protocols.

class DarkServerProtocol(Protocol):
    """
    Shim protocol for servers.
    """

    peer = None
    buf = ""

    def __init__(self, endpoint):
        self.endpoint = endpoint
        print "Protocol created..."

    def challenge(self, challenge):
        log.msg("Challenged: %s" % challenge)
        # ...omitted for brevity...
        return is_valid(challenge)

    def connectionMade(self):
        pcf = ProxyClientFactory()
        pcf.setServer(self)
        d = self.endpoint.connect(pcf)
        d.addErrback(lambda failure: self.transport.loseConnection())

        self.transport.pauseProducing()

    def setPeer(self, peer):
        # Our proxy passthrough has succeeded, so we will be seeing data
        # coming through shortly.
        log.msg("Established passthrough")
        self.peer = peer

    def dataReceived(self, data):
        self.buf += data

        # Examine whether we have received a challenge.
        if self.challenge(self.buf):
            # Excellent; change protocol.
            p = DarkAMP()
            p.factory = self.factory
            self.transport.protocol = p
            p.makeConnection(self.transport)
        elif self.peer:
            # Well, go ahead and send it through.
            self.peer.transport.write(data)

This is a rather complex chunk of code which takes two StatefulProtocols and glues them together rather forcefully. This is from a VNC proxy (https://code.osuosl.org/projects/twisted-vncauthproxy to be precise), which needs its protocols to do a lot of pre-authentication stuff before they are ready to be joined. This kind of proxy is the worst case; for speed, you don't want to interact with the data going over the proxy, but you need to do some setup beforehand.

def start_proxying(result):
    """
    Callback to start proxies.
    """

    log.msg("Starting proxy")
    client_result, server_result = result
    success = True
    client_success, client = client_result
    server_success, server = server_result

    if not client_success:
        success = False
        log.err("Had issues on client side...")
        log.err(client)

    if not server_success:
        success = False
        log.err("Had issues on server side...")
        log.err(server)

    if not success:
        log.err("Had issues connecting, disconnecting both sides")
        if not isinstance(client, Failure):
            client.transport.loseConnection()
        if not isinstance(server, Failure):
            server.transport.loseConnection()
        return

    server.dataReceived = client.transport.write
    client.dataReceived = server.transport.write
    # Replay last bits of stuff in the pipe, if there's anything left.
    data = server._sful_data[1].read()
    if data:
        client.transport.write(data)
    data = client._sful_data[1].read()
    if data:
        server.transport.write(data)

    server.transport.resumeProducing()
    client.transport.resumeProducing()
    log.msg("Proxying started!")

So, now that I've explained that...

I also wrote Bravo. As in, http://www.bravoserver.org/. So I know a bit about Minecraft, and thus about Terraria. You will probably want to parse the packets coming through your proxy on both sides, so your actual proxying might start out looking like this, but it will quickly evolve as you begin to understand the data you're proxying. Hopefully this is enough to get you started!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文