[英]How can I implement port forwarding in a Paramiko server?
当您以ssh user@host -L <local port>:<remote host>:<remote port>
运行 SSH 并尝试通过本地端口连接时,会发生“direct-tcpip”请求(通常称为端口转发) .
我正在尝试在自定义 SSH 服务器上实现 direct-tcpip, check_channel_direct_tcpip_request
在ServerInterface
class 中提供了 check_channel_direct_tcpip_request,以检查是否应允许“direct-tcpip”请求,可以按如下方式实现:
class Server(paramiko.ServerInterface):
# ...
def check_channel_direct_tcpip_request(self, chanid, origin, destination):
return paramiko.OPEN_SUCCEEDED
但是,当我使用上述 SSH 命令并通过本地端口连接时,没有任何反应,可能是因为我需要自己实现连接处理。
阅读文档,似乎通道仅在OPEN_SUCCEDED
返回后才打开。
在为请求返回OPEN_SUCCEEDED
后如何处理直接 tcpip 请求?
您确实需要设置自己的连接处理程序。 这是解释我采取的步骤的冗长答案 - 如果您的服务器代码已经工作,您将不需要其中的一些。 整个运行的服务器示例在这里: https://controlc.com/25439153
我使用了来自这里https://github.com/paramiko/paramiko/blob/master/demos/demo_server.py的 Paramiko 示例服务器代码作为基础,并在其上植入了一些套接字代码。 这没有任何错误处理、线程相关的细节或任何其他“适当”的东西,但它允许您使用端口转发器。
这也有很多你不需要的东西,因为我不想开始整理一个虚拟的示例代码。 对此表示歉意。
首先,我们需要转发器工具。 这将创建一个线程来运行“隧道”转发器。 这也回答了您从哪里获得频道的问题。 您从传输中accept()
它,但您需要在转发器线程中执行此操作。 正如您在 OP 中所述,它在check_channel_direct_tcpip_request()
function 中还没有,但它最终将可供线程使用。
def tunnel(sock, chan, chunk_size=1024):
while True:
r, w, x = select.select([sock, chan], [], [])
if sock in r:
data = sock.recv(chunk_size)
if len(data) == 0:
break
chan.send(data)
if chan in r:
data = chan.recv(chunk_size)
if len(data) == 0:
break
sock.send(data)
chan.close()
sock.close()
class ForwardClient(threading.Thread):
daemon = True
# chanid = 0
def __init__(self, address, transport, chanid):
threading.Thread.__init__(self)
self.socket = socket.create_connection(address)
self.transport = transport
self.chanid = chanid
def run(self):
while True:
chan = self.transport.accept(10)
if chan == None:
continue
print("Got new channel (id: %i).", chan.get_id())
if chan.get_id() == self.chanid:
break
peer = self.socket.getpeername()
try:
tunnel(self.socket, chan)
except:
pass
回到示例服务器代码。 您的服务器 class 需要将传输作为参数,这与示例代码不同:
class Server(paramiko.ServerInterface):
# 'data' is the output of base64.b64encode(key)
# (using the "user_rsa_key" files)
data = (
b"AAAAB3NzaC1yc2EAAAABIwAAAIEAyO4it3fHlmGZWJaGrfeHOVY7RWO3P9M7hp"
b"fAu7jJ2d7eothvfeuoRFtJwhUmZDluRdFyhFY/hFAh76PJKGAusIqIQKlkJxMC"
b"KDqIexkgHAfID/6mqvmnSJf0b5W8v5h2pI/stOSwTQ+pxVhwJ9ctYDhRSlF0iT"
b"UWT10hcuO4Ks8="
)
good_pub_key = paramiko.RSAKey(data=decodebytes(data))
def __init__(self, transport):
self.transport = transport
self.event = threading.Event()
然后您将覆盖相关方法并在那里创建转发器:
def check_channel_direct_tcpip_request(self, chanid, origin, destination):
print(chanid, origin, destination)
f = ForwardClient(destination, self.transport, chanid)
f.start()
return paramiko.OPEN_SUCCEEDED
您需要将传输参数添加到服务器 class 的创建中:
t.add_server_key(host_key)
server = Server(t)
此示例服务器要求您在名为 test_rsa.key 的目录中拥有一个 RSA 私钥。 在那里创建任何 RSA 密钥,您不需要它,但我没有费心从代码中删除它的使用。
然后您可以运行您的服务器(在端口 2200 上运行)并发出
ssh -p 2200 -L 2300:www.google.com:80 robey@localhost
(密码是 foo)
现在当你尝试
telnet localhost 2300
并在那里输入一些东西,你会得到谷歌的回复。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.