Python Twisted 中间人攻击实现
我需要做的是一种“中间人”的实现:我需要一个服务器,它可以接收来自客户端的连接(这些连接传输的是不同长度的二进制数据),然后把这些数据转发给它连接的另一个服务器(就像一个客户端一样),接着再把从那个服务器收到的数据发送回客户端。
这个服务器实际上就像是客户端和服务器之间的桥梁,负责传递它们之间交换的数据(这是一种流式数据,所以它会不断地从一边接收数据,然后发送到另一边)。
这个服务器是固定的,所以它的地址可以直接写死在代码里;但是当某个客户端断开连接时,这个服务器也必须断开与“真实”服务器的连接。
我一直在寻找解决方案,但找不到这样一个简单问题的例子。
我写的代码实际上是可以工作的,但我还没找到如何在服务器部分放一个引用,告诉它“这是你对应的客户端”,或者在客户端中放一个引用,告诉它“这是你的服务器”。这是我的代码:
#!/usr/bin/env python
from twisted.internet import protocol, reactor
from twisted.protocols import basic
client = None
server = None
class ServerProtocol(protocol.Protocol):
def connectionMade(self):
global server
factory = protocol.ClientFactory()
factory.protocol = ClientProtocol
server = self
reactor.connectTCP('localhost', 1324, factory)
def dataReceived(self, data):
global client
client.transport.write(data)
class ClientProtocol(protocol.Protocol):
def connectionMade(self):
global client
# Here's the instance of the client
client = self
def dataReceived(self, data):
global server
server.transport.write(data)
def main():
import sys
from twisted.python import log
log.startLogging(sys.stdout)
factory = protocol.ServerFactory()
factory.protocol = ServerProtocol
# Here's the instance of the server
server = ServerProtocol
reactor.listenTCP(2593, factory)
reactor.run()
if __name__ == '__main__':
main()
现在,关键是这个实例不能放在全局对象中,而应该放在这两个类里面:怎么做呢?
2 个回答
我自己解决了这个问题,为了将来参考(或者帮助其他遇到同样问题的人),我把我用来解决它的代码放在这里。
我觉得我自己的解决方案和jedwards提供的方案都可以用;现在我只需要再多研究一下他的方案,以确保我做的事情是正确的:这是我第一次使用Twisted框架,学习别人的解决方案是学习新东西的好方法! :)
#!/usr/bin/env python
from twisted.internet import protocol, reactor
from twisted.protocols import basic
class ServerProtocol(protocol.Protocol):
def __init__(self):
self.buffer = None
self.client = None
def connectionMade(self):
factory = protocol.ClientFactory()
factory.protocol = ClientProtocol
factory.server = self
reactor.connectTCP('gameserver16.gamesnet.it', 2593, factory)
def dataReceived(self, data):
if (self.client != None):
self.client.write(data)
else:
self.buffer = data
def write(self, data):
self.transport.write(data)
print 'Server: ' + data.encode('hex')
class ClientProtocol(protocol.Protocol):
def connectionMade(self):
self.factory.server.client = self
self.write(self.factory.server.buffer)
self.factory.server.buffer = ''
def dataReceived(self, data):
self.factory.server.write(data)
def write(self, data):
self.transport.write(data)
print 'Client: ' + data.encode('hex')
def main():
import sys
from twisted.python import log
log.startLogging(sys.stdout)
factory = protocol.ServerFactory()
factory.protocol = ServerProtocol
reactor.listenTCP(2593, factory)
reactor.run()
if __name__ == '__main__':
main()
考虑一下这个方法
#!/usr/bin/env python
import sys
from twisted.internet import reactor
from twisted.internet.protocol import ServerFactory, ClientFactory, Protocol
from twisted.protocols import basic
from twisted.python import log
LISTEN_PORT = 2593
SERVER_PORT = 1234
class ServerProtocol(Protocol):
def connectionMade(self):
reactor.connectTCP('localhost', SERVER_PORT, MyClientFactory(self))
def dataReceived(self, data):
self.clientProtocol.transport.write(data)
class ClientProtocol(Protocol):
def connectionMade(self):
# Pass ServerProtocol a ref. to ClientProtocol
self.serverProtocol.clientProtocol = self;
def dataReceived(self, data):
self.serverProtocol.transport.write(data)
class MyServerFactory(ServerFactory):
protocol = ServerProtocol
def buildProtocol(self, addr):
# Create ServerProtocol
p = ServerFactory.buildProtocol(self, addr)
return p
class MyClientFactory(ClientFactory):
protocol = ClientProtocol
def __init__(self, serverProtocol_):
self.serverProtocol = serverProtocol_
def buildProtocol(self, addr):
# Create ClientProtocol
p = ClientFactory.buildProtocol(self,addr)
# Pass ClientProtocol a ref. to ServerProtocol
p.serverProtocol = self.serverProtocol
return p
def main():
log.startLogging(sys.stdout)
reactor.listenTCP(LISTEN_PORT, MyServerFactory())
reactor.run()
if __name__ == '__main__':
main()
ServerProtocol 实例会把自己传给 MyClientFactory 的构造函数,这样 MyClientFactory 就知道它要和哪个 ServerProtocol 关联了。
同样,当 ClientProtocol 连接建立后,它会用自己对 ServerProtocol 的引用,告诉 ServerProtocol 它要使用哪个 ClientProtocol。
注意:这段代码没有错误检查,所以如果出现问题(比如,真实的服务器没有在监听),你可能会遇到 NoneType 的错误。
重要的代码行是:
reactor.connectTCP('localhost', SERVER_PORT, MyClientFactory(self))
#...
def __init__(self, serverProtocol_):
self.serverProtocol = serverProtocol_
在这里,你把 ServerProtocol 的引用传给 MyClientFactory 的构造函数。它会把这个引用存储在一个成员变量中。这样,当客户端工厂创建 ClientProtocol 时,就可以把这个引用传递下去:
# Pass ClientProtocol a ref. to ServerProtocol
p.serverProtocol = self.serverProtocol
然后,一旦你的脚本和 真实 服务器建立了连接,事情就反过来了。ClientProtocol 会把自己的引用给 ServerProtocol:
# Pass ServerProtocol a ref. to ClientProtocol
self.serverProtocol.clientProtocol = self;
最后,两个协议会利用彼此存储的引用来发送接收到的数据:
def dataReceived(self, data):
self.clientProtocol.transport.write(data)
#...
def dataReceived(self, data):
self.serverProtocol.transport.write(data)