pty & paramiko

변경 계획: ssh 자체 프로그램을 이용하던 것을 paramiko(python ssh 라이브러리)를 사용하도록 바꾸기

바꾸는 이유: 파이썬 모듈 자체에서 제공하는 기능들을 이용하기 위함임, ssh 그대로 쓰면 다른 기능이 필요할 때 고려할 사항이 많음
공식문서: https://docs.paramiko.org/en/stable/api/client.html


구현 순서

  1. paramiko 사용 exec_command() 사용해보기
  2. invoke_shell()로 send 해서 결과물만 채널에 recv
  3. get_pty()랑 invoke_shell() 사용해서 interactive 한 shell 만들기
    4, getkey() 이용-처음 엔터 눌러야 login banner 뜨는 거 수정

    https://wikidocs.net/16063

  4. VORA ZONE처럼 output 처리하는 스레드 생성 진행중
  5. VORA ZONE에서는 channel이 아닌 fd를 기준으로 read write하므로, 채널 기반 send&recv를 fd와 연동시키기



기존 VORA ZONE

ㄱ. 생성: bash(python) -> 부모 프로세스 -> pty.fork() -> 자식 프로세스 생성
ㄴ. 터미널 결과 값 출력: 자식 프로세스에서 출력 -> 부모 프로세스에서 스레드로 보낸 후 os.read



ㄱ. pty.fork()

  • 자식의 제어 터미널을 의사 터미널에 연결함
  • 이 함수의 반환 값은 (pid, fd)
  • 이 fd를 통해서 입출력 관리가 가능해진다 !!

consumer.py

  • 자식은 pid 0, os.execve로 ssh의 특성을 갖도록 바꿔줌
  • 부모는 자식의 pid, 자식의 제어 터미널(자식 i/o)에 연결된 fd 반환




paramiko

핵심 함수

  • invoke_shell( )

    대화식 쉘 세션 요청
    서버에서 허용하는 경우 채널은 쉘의 stdin, stdout 및 stderr에 직접 연결됩니다.
    이 경우 쉘은 pty를 통해 작동하고 채널은 pty의 stdin 및 stdout에 연결됩니다.
    쉘이 종료되면 채널이 닫히고 재사용할 수 없습니다. 다른 쉘을 열려면 새 채널을 열어야 합니다.

  • get_pty( term='vt100' , width=80 , height=24 , width_pixels=0 , height_pixels=0 )

    서버에서 의사 터미널을 요청
    일반적으로 클라이언트 채널을 생성한 직후에 호출된 셸에 대한 몇 가지 기본 터미널 의미를 제공하도록 서버에 요청하는 데 사용
    invoke_shell. 로 단일 명령을 실행하려는 경우 이 메서드를 호출할 필요가 없습니다(또는 바람직하지 않음)


example ( => interactive shell)

구현순서 상 3번임 !! 단순 send&recv 이용함

import paramiko as paramiko
from paramiko import AutoAddPolicy
import time

sshClient = paramiko.SSHClient()
sshClient.load_system_host_keys() #시스템(읽기 전용) 파일에서 호스트 키를 로드
sshClient.set_missing_host_key_policy(AutoAddPolicy()) #알려진 호스트 키 없이 서버에 연결할 때 사용할 정책을 설정 -> 호스트 이름과 키를 로컬 HostKeys개체 에 자동으로 추가 하고 저장
sshClient.connect('0.0.0.0', username='((입력))', password='((입력))')

channel = sshClient.get_transport().open_session() #서버에 새 채널 요청
channel.get_pty() # 이 줄 없으면 Welcome to Ubuntu는 뜨고 그 뒤로 쉘이 무반응
channel.invoke_shell()  #이 줄 없으면 아예 첨부터 아무것도 안 뜸


while True:
    
    
    command = input()
    if command == 'exit':
        print("TEST END")
        break

    channel.send(command + "\n")

    while True:
        if channel.recv_ready():
            output = channel.recv(1024)
            print(output.decode('utf-8'))
        else:
            time.sleep(0.1)
            if not(channel.recv_ready()):
                break

sshClient.close()


좋은 웹페이지 즐겨찾기