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'))