LoginSignup
7
9

More than 5 years have passed since last update.

Rustでssh

Last updated at Posted at 2016-01-05

前提

項目 説明
OS MacOSX Yosemite 10.11.2
Rust 1.5.0
検証日時 2016.01.05

Crate

ssh2-rsを使う
https://github.com/alexcrichton/ssh2-rs

リモートホストでlsコマンドを叩くコード例

extern crate ssh2;
use ssh2::Session;
use std::io::prelude::*;
use std::net::TcpStream;
use std::env;

static USERNAME: &'static str = "username";
static REMOTE_ADDRESS: &'static str = "127.0.0.1:22";

fn main() {
    let tcp = TcpStream::connect(REMOTE_ADDRESS).unwrap();
    let mut session = Session::new().unwrap();
    session.handshake(&tcp).unwrap();
    let privatekey_filepath = env::home_dir().unwrap().join(".ssh/id_rsa");
    session.userauth_pubkey_file(USERNAME, None, privatekey_filepath.as_path(), None).unwrap();

    assert!(session.authenticated());

    let mut chan = session.channel_session().unwrap();
    chan.exec("ls").unwrap();
    let mut s = String::new();
    chan.read_to_string(&mut s).unwrap();
    println!("{}", s);
}

scpのコード例

extern crate ssh2;
use ssh2::Session;
use std::io::prelude::*;
use std::net::TcpStream;
use std::env;
use std::path::Path;

static USERNAME: &'static str = "username";
static REMOTE_ADDRESS: &'static str = "127.0.0.1:22";
static REMOTE_FILE: &'static str = "/path/to/remote";
static NEW_REMOTE_FILE: &'static str = "/path/to/remote.new";

fn main() {
    let tcp = TcpStream::connect(REMOTE_ADDRESS).unwrap();
    let mut session = Session::new().unwrap();
    session.handshake(&tcp).unwrap();
    let privatekey_filepath = env::home_dir().unwrap().join(".ssh/id_rsa");
    session.userauth_pubkey_file(USERNAME, None, privatekey_filepath.as_path(), None).unwrap();

    let (mut remote_file, stat) = session.scp_recv(Path::new(REMOTE_FILE))
                                         .unwrap();
    println!("remote file stat: {}", stat.size());

    let mut contents = Vec::new();
    remote_file.read_to_end(&mut contents).unwrap();

    let mut new_remote_file = session.scp_send(Path::new(NEW_REMOTE_FILE),
                                               0o644,
                                               stat.size(),
                                               None)
                                     .unwrap();
    new_remote_file.write_all(&contents).unwrap();
}

注意点

TcpStreamSessionをつくって認証するところをlib.rsに切り出して共通化(モジュール作ってget_session的な関数に)しようとしたが、TCPのライフサイクルが関数内しか保持できないため、叶わぬ夢になってしまった。
良い方法をご存知の方いれば教えていただきたく。

[2016.01.06追記]

TCPのライフサイクルが関数内しか保持できないため、叶わぬ夢になってしまった。

ここは私の理解不足で、TcpStreamをもった変数(サンプル内のtcpにあたるもの)の寿命を考慮できていないことが原因でした。

7
9
8

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
9