将 SSH 服务器的隧道路由到用户

147 阅读2分钟

我们目前有一个简单的 sftp 服务器,允许客户端连接并将其 chroot 到各自的 ftp 目录中。我们希望将客户端移入 lxc 容器,但不想改变它们连接到 sftp 的方式。

huake2_00017_.png

2、解决方案

我们想在主机上创建一个简单的服务器,根据用户名决定将连接转发到哪个容器,从而实现将 SSH 服务器的隧道路由到用户。这将允许客户端继续使用他们现有的 GUI ftp 客户端连接到 sftp 服务器,而无需更改他们的连接方式。

为了实现这一点,需要修改 paramiko 服务器以支持在客户端传输中创建直接 TCP/IP 通道,以便可以将连接转发到正确的容器。

以下是实现解决方案的示例代码:

import paramiko
import socket
import traceback

class Server(paramiko.ServerInterface):
    def check_channel_request(self, kind, chanid):
        if kind == 'session':
            return paramiko.OPEN_SUCCEEDED
        elif kind == 'direct-tcpip':
            return paramiko.OPEN_SUCCEEDED
        return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED

if __name__ == '__main__':
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        sock.bind(('', 2200))
    except Exception as e:
        print('*** Bind failed: ' + str(e))
        traceback.print_exc()
        sys.exit(1)
    try:
        sock.listen(100)
        print('Listening for connection ...')
        client, addr = sock.accept()
    except Exception as e:
        print('*** Listen/accept failed: ' + str(e))
        traceback.print_exc()
        sys.exit(1)

    print('Got a connection!')
    try:
        t = paramiko.Transport(client)
        t.add_server_key(host_key)
        server = Server()
        try:
            t.start_server(server=server)
        except paramiko.SSHException:
            print('*** SSH negotiation failed.')
            sys.exit(1)

        # Waiting for authentication.. returns an unwanted channel object since
        # it isn't the right "kind" of channel
        unwanted_chan = t.accept(20)
        dest_addr = ("127.0.0.1", 1030)  # target container port
        local_addr = ("127.0.0.1", 1234)  # Arbitrary port on gateway server

        # Trying to put words in the client's mouth here.. fails
        # What should I do?
        print(" Attempting creation of direct-tcpip channel on client Transport")
        tunnel_chan = t.open_channel("direct-tcpip", dest_addr, local_addr)
        print("tunnel_chan created.")
        tunnel_client = SSHClient()
        tunnel_client.load_host_keys(host_key)
        print("attempting connection using tunnel_chan")
        tunnel_client.connect("127.0.0.1", port=1234, sock=tunnel_channel)
        stdin, stdout, stderr = tunnel_client.exec_command('hostname')
        print(stdout.readlines())
    except Exception as e:
        print('*** Caught exception: ' + str(e.__class__) + ': ' + str(e))
        traceback.print_exc()
    try:
        t.close()
    except:
        pass
    sys.exit(1)

代码中,您需要将目标容器的 IP 地址和端口替换为 dest_addrlocal_addr 变量的值。您还需要将主机密钥替换为 host_key 变量的值。

运行此代码后,您应该能够使用 SSH 客户端连接到主机,并根据您的用户名将连接转发到正确的容器。