1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
extern crate tokio; extern crate futures; extern crate thrussh; extern crate regex; #[macro_use] extern crate log; #[macro_use] extern crate error_chain; extern crate dirs; use std::io::Read; use std::path::Path; error_chain!{ foreign_links { IO(std::io::Error); } errors { HostNotFound { } NoHome { } } } mod proxy; pub use proxy::*; #[derive(Debug, Default)] pub struct Config { pub user: Option<String>, pub host_name: Option<String>, pub port: Option<u16>, pub identity_file: Option<String>, pub proxy_command: Option<String>, } impl Config { pub fn update_proxy_command(&mut self) { if let Some(ref h) = self.host_name { if let Some(ref mut prox) = self.proxy_command { *prox = prox.replace("%h", h); } } if let Some(ref p) = self.port { if let Some(ref mut prox) = self.proxy_command { *prox = prox.replace("%p", &format!("{}", p)); } } } } pub fn parse_home(host: &str) -> Result<Config> { let mut home = if let Some(home) = dirs::home_dir() { home } else { return Err(ErrorKind::NoHome.into()) }; home.push(".ssh"); home.push("config"); parse_path(&home, host) } pub fn parse_path<P:AsRef<Path>>(path: P, host: &str) -> Result<Config> { let mut s = String::new(); let mut b = std::fs::File::open(path)?; b.read_to_string(&mut s)?; parse(&s, host) } pub fn parse(file: &str, host: &str) -> Result<Config> { let mut config: Option<Config> = None; for line in file.lines() { let line = line.trim(); if let Some(n) = line.find(' ') { let (key, value) = line.split_at(n); let lower = key.to_lowercase(); if let Some(ref mut config) = config { match lower.as_str() { "host" => break, "user" => config.user = Some(value.trim_left().to_string()), "hostname" => config.host_name = Some(value.trim_left().to_string()), "port" => config.port = value.trim_left().parse().ok(), "identityfile" => config.identity_file = Some(value.trim_left().to_string()), "proxycommand" => config.proxy_command = Some(value.trim_left().to_string()), key => { debug!("{:?}", key); } } } else { match lower.as_str() { "host" => { if value.trim_left() == host { config = Some(Config::default()) } } _ => {} } } } } if let Some(config) = config { Ok(config) } else { Err(ErrorKind::HostNotFound.into()) } }