ganzl

(瓜)

导航

paramiko模块-2

如何用paramiko模块模拟登入服务器,并记录操作日志,起到审计的作用?

  各个client ---(连接跳转机)--->(跳转机)------>各自的目标服务器。

目前我们公司的跳转机,只有跳转的功能(外网--->内网),没有其他功能。

可以用如下的demo进行日志记录等操作:

脚本登入服务器:

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import paramiko
import os
import sys
import select
import socket

tran = paramiko.Transport(('10.1.1.10', 22,))
tran.start_client()

'''
#使用密钥认证
default_path = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
key = paramiko.RSAKey.from_private_key_file(default_path)
tran.auth_publickey('lbsweb', key)

'''
tran.auth_password('ganzl', '123456') #通过密码认证


chan = tran.open_session()# 打开一个通道
chan.get_pty()# 获取一个终端
chan.invoke_shell()# 激活器

'''
chan创建的通道,用于接收服务器返回信息
利用sys.stdin,肆意妄为执行操作,用户在终端输入内容,并将内容发送至远程服务器
远程服务器执行命令,并将结果返回,用户终端显示内容.
'''
while True:
    readable, writeable, error = select.select([chan, sys.stdin, ],[],[],1)  # sys.stdin 处理用户输入
    #只要发生变化,chan或者stdin或者都变化
    if chan in readable: #远端有变化后捕获到
        try:
            x = chan.recv(1024)  #Transport的对象调用的start_client方法,就是sorcket,看这个start_client方法。
            if len(x) == 0:
                print '\r\n*** EOF\r\n',
                break
            sys.stdout.write(x)#把内容输入到终端上显示
            sys.stdout.flush()
        except socket.timeout:
            pass
    if sys.stdin in readable:                        #当终端有输入捕获到之后
        inp = sys.stdin.readline()                   #把用户的那一行输入
        chan.sendall(inp)                            #发送命令至远端

chan.close()
tran.close()
View Code

脚本登入服务器并写日志:

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import paramiko
import os
import sys
import select
import socket

tran = paramiko.Transport(('10.1.1.10', 22,))
tran.start_client()
'''
#使用密钥认证
default_path = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
key = paramiko.RSAKey.from_private_key_file(default_path)
tran.auth_publickey('lbsweb', key)
'''
tran.auth_password('ganzl', '123456') #通过密码认证

chan = tran.open_session()# 打开一个通道
chan.get_pty()# 获取一个终端
chan.invoke_shell()# 激活器
file_log = open('log','a')
'''
chan创建的通道,用于接收服务器返回信息
利用sys.stdin,肆意妄为执行操作,用户在终端输入内容,并将内容发送至远程服务器
远程服务器执行命令,并将结果返回,用户终端显示内容.
'''
while True:
    readable, writeable, error = select.select([chan, sys.stdin, ],[],[],1)  # sys.stdin 处理用户输入
    #只要发生变化,chan或者stdin或者都变化
    if chan in readable: #远端有变化后捕获到
        try:
            x = chan.recv(1024)  #Transport的对象调用的start_client方法,就是sorcket,看这个start_client方法。
            if len(x) == 0:
                print '\r\n*** EOF\r\n',
                break
            sys.stdout.write(x)#把内容输入到终端上显示
            sys.stdout.flush()
        except socket.timeout:
            pass
    if sys.stdin in readable:                        #当终端有输入捕获到之后
        inp = sys.stdin.readline()                   #把用户的那一行输入
        file_log.write(inp)
        chan.sendall(inp)                            #发送命令至远端

file_log.close()
chan.close()
tran.close()
View Code

脚本登入服务器,并且能操作[tab]等特殊键:(我的环境下日志写入有问题 python --version:Python 2.6.6)

这个修改终端模式,会不会对写日志有影响,再学习实验!!!待完善。

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import paramiko
import os
import sys
import select
import socket
import termios
import tty

tran = paramiko.Transport(('10.1.1.10', 22,))
tran.start_client()
'''
#使用密钥认证
default_path = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
key = paramiko.RSAKey.from_private_key_file(default_path)
tran.auth_publickey('lbsweb', key)
'''
tran.auth_password('ganzl', '123456') #通过密码认证

chan = tran.open_session()# 打开一个通道
chan.get_pty()# 获取一个终端
chan.invoke_shell()# 激活器

# 获取原tty属性
oldtty = termios.tcgetattr(sys.stdin)
try:
    # 为tty设置新属性
    # 默认当前tty设备属性:
    #   输入一行回车,执行
    #   CTRL+C 进程退出,遇到特殊字符,特殊处理。

    # 这是为原始模式,不认识所有特殊符号
    # 放置特殊字符应用在当前终端,如此设置,将所有的用户输入均发送到远程服务器
    tty.setraw(sys.stdin.fileno()) #把远端更换为LINUX原始模式
    chan.settimeout(0.0)
    file_log = open('log','a')
    while True:
        # 监视 用户输入 和 远程服务器返回数据(socket)
        # 阻塞,直到句柄可读
        r, w, e = select.select([chan, sys.stdin], [], [], 1)
        if chan in r:
            try:
                x = chan.recv(1024)
                if len(x) == 0:
                    file_log.close()
                    print '\r\n*** EOF\r\n',
                    break
                sys.stdout.write(x)
                sys.stdout.flush()
            except socket.timeout:
                pass
        if sys.stdin in r:
            x = sys.stdin.read(1)
            if len(x) == 0:
                break
            if x == '\t': #判断用户的是否为tab如果为tab将不记录
                pass
            else:
                file_log.write(x)#如果用户输入的命令保存至日志
            chan.send(x)

finally:
    # 重新设置终端属性
    termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
chan.close()
tran.close()
View Code

 

windows下的操作:(我暂时用不到,等学到web操作终端的时候再回头看。)

def windows_shell(chan):
    import threading

    sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n")

    def writeall(sock):
        while True:
            data = sock.recv(256)
            if not data:
                sys.stdout.write('\r\n*** EOF ***\r\n\r\n')
                sys.stdout.flush()
                break
            sys.stdout.write(data)
            sys.stdout.flush()

    writer = threading.Thread(target=writeall, args=(chan,))
    writer.start()

    try:
        while True:
            d = sys.stdin.read(1)
            if not d:
                break
            chan.send(d)
    except EOFError:
        # user hit ^Z or F6
        pass
View Code
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import paramiko
import sys
import threading

tran = paramiko.Transport(('10.1.1.10'', 22,))
tran.start_client()
tran.auth_password('ganzl', '123456!') #通过密码认证
chan = tran.open_session()# 打开一个通道
chan.get_pty()# 获取一个终端
chan.invoke_shell()# 激活器

sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n")

def writeall(sock):
    while True:
        data = sock.recv(256)
        '''
        SSH发送数据的也是通过socket进行发送数据的,那么我们就可以使用socket来获取远程机器发送回来的数据。
        while循环一直接收数据,sock.recv(256)是阻塞的只有数据过来的时候才会继续走。
        '''
        if not data:
            sys.stdout.write('\r\n*** EOF ***\r\n\r\n')
            sys.stdout.flush()
            break
        sys.stdout.write(data)
        sys.stdout.flush()

writer = threading.Thread(target=writeall, args=(chan,)) #创建了一个线程,去执行writeall方法,参数为chan(建立的SSH连接)
writer.start()

try:
    while True: #主线程循环
        d = sys.stdin.read(1)  #一直监听用户的输入,输入一个发送一个
        if not d:
            break
        chan.send(d)
except EOFError:
    # user hit ^Z or F6
    pass

chan.close()
tran.close()
View Code

 

paramiko操作的更多详细,请看:

http://www.cnblogs.com/wupeiqi/articles/5095821.html

http://pythonpeixun.blog.51cto.com/7195558/1213929

 

posted on 2016-01-27 16:22  ganzl  阅读(348)  评论(0编辑  收藏  举报