paramiko 自建代理服务ssh到内网服务器

paramiko 自建代理服务ssh到内网服务器
  • 原理

    • 在一台拥有公网IP的服务器建立代理服务,用户名为username,密码为password,端口为12237,那么就可以在本地通过这台服务器ssh到与之内网相同的服务器

    在这里插入图片描述

  • 自建代理服务

    • 在有公网IP的服务器上部署以下代码
#!/usr/bin/python3
# -*- coding:utf-8 -*-
# @Author         : Charlie Zhang
# @Email          : charlie.zhang@wiwide.com
# @Time           : 2020/11/9 15:53
# @Version        : 1.0
# @File           : proxy.py
# @Software       : PyCharm

import select
import socket
import struct
from socketserver import ThreadingMixIn, TCPServer, StreamRequestHandler
from loguru import logger as logging

USERNAME = "username" 
PASSWORD = "password" 
PROXY_PORT = 12237

SOCKS_VERSION = 5


class ThreadingTCPServer(ThreadingMixIn, TCPServer):
    pass


class SocksProxy(StreamRequestHandler):
    username = USERNAME
    password = PASSWORD

    def handle(self):
        logging.info('Accepting connection from %s:%s' % self.client_address)

        # greeting header
        # read and unpack 2 bytes from a client
        header = self.connection.recv(2)
        version, nmethods = struct.unpack("!BB", header)

        # socks 5
        assert version == SOCKS_VERSION
        assert nmethods > 0

        # get available methods
        methods = self.get_available_methods(nmethods)

        # accept only USERNAME/PASSWORD auth
        if 2 not in set(methods):
            # close connection
            self.server.close_request(self.request)
            return

        # send welcome message
        self.connection.sendall(struct.pack("!BB", SOCKS_VERSION, 2))

        if not self.verify_credentials():
            return

        # request
        version, cmd, _, address_type = struct.unpack("!BBBB", self.connection.recv(4))
        assert version == SOCKS_VERSION

        if address_type == 1:  # IPv4
            address = socket.inet_ntoa(self.connection.recv(4))
        elif address_type == 3:  # Domain name
            domain_length = self.connection.recv(1)[0]
            address = self.connection.recv(domain_length)
            address = socket.gethostbyname(address)
        port = struct.unpack('!H', self.connection.recv(2))[0]

        # reply
        try:
            if cmd == 1:  # CONNECT
                remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                remote.connect((address, port))
                bind_address = remote.getsockname()
                logging.info('Connected to %s %s' % (address, port))
            else:
                self.server.close_request(self.request)

            addr = struct.unpack("!I", socket.inet_aton(bind_address[0]))[0]
            port = bind_address[1]
            reply = struct.pack("!BBBBIH", SOCKS_VERSION, 0, 0, 1,
                                addr, port)

        except Exception as err:
            logging.error(err)
            # return connection refused error
            reply = self.generate_failed_reply(address_type, 5)

        self.connection.sendall(reply)

        # establish data exchange
        if reply[1] == 0 and cmd == 1:
            self.exchange_loop(self.connection, remote)

        self.server.close_request(self.request)

    def get_available_methods(self, n):
        methods = []
        for i in range(n):
            methods.append(ord(self.connection.recv(1)))
        return methods

    def verify_credentials(self):
        version = ord(self.connection.recv(1))
        assert version == 1

        username_len = ord(self.connection.recv(1))
        username = self.connection.recv(username_len).decode('utf-8')

        password_len = ord(self.connection.recv(1))
        password = self.connection.recv(password_len).decode('utf-8')

        if username == self.username and password == self.password:
            # success, status = 0
            response = struct.pack("!BB", version, 0)
            self.connection.sendall(response)
            return True

        # failure, status != 0
        response = struct.pack("!BB", version, 0xFF)
        self.connection.sendall(response)
        self.server.close_request(self.request)
        return False

    def generate_failed_reply(self, address_type, error_number):
        return struct.pack("!BBBBIH", SOCKS_VERSION, error_number, 0, address_type, 0, 0)

    def exchange_loop(self, client, remote):

        while True:

            # wait until client or remote is available for read
            r, w, e = select.select([client, remote], [], [])

            if client in r:
                data = client.recv(4096)
                if remote.send(data) <= 0:
                    break

            if remote in r:
                data = remote.recv(4096)
                if client.send(data) <= 0:
                    break


def run_proxyserver():
    with ThreadingTCPServer(('0.0.0.0', PROXY_PORT), SocksProxy) as server:
        server.serve_forever()


if __name__ == '__main__':
    run_proxyserver()

  • paramiko

    #!/usr/bin/python3
    # -*- coding:utf-8 -*-
    # @Author         : Charlie Zhang
    # @Email          : charlie.zhang@wiwide.com
    # @Time           : 2021/1/25 17:22
    # @Version        : 1.0
    # @File           : test.py
    # @Software       : PyCharm
    import paramiko
    import socks
    from paramiko import AuthenticationException
    
    PROXY_HOST = '49.125.4.75'
    PROXY_PORT = 12237
    PROXY_USERNAME = 'username'
    PROXY_PASSWORD = 'password'
    
    
    def connect_ssh(self):
        """
        连接ssh
        """
        username = 'root'  # 局域网服务器用户名
        password = 'xxxxxx'  # 局域网服务器用户密码
    
        sock = socks.socksocket()
        sock.set_proxy(
            proxy_type=socks.SOCKS5,
            addr=PROXY_HOST,
            port=self.socks_port,
            rdns=False, username=self.socks_username, password=self.socks_password
        )
        sock.connect((self.vpn_client_ip, 22))
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        try:
            client.connect(self.vpn_client_ip, username=username, password=password, timeout=10, sock=sock)
        except AuthenticationException:
            print('ssh error')
        print(client.exec_command('ls'))
    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值