我想在Rust中編寫一個小程序來基本完成ssh -L 5000:localhost:8080
的工作:在我的機器上建立localhost:5000
與遠程機器上的localhost:8080
之間的隧道,這樣如果HTTP服務器正在運行在遙控器上的端口8080,我可以通過localhost:5000
我的地方訪問它,繞過遠程防火牆可能會阻止到8080通過SSH生鏽的TCP隧道
外部訪問我意識到ssh
已經正是這樣做的,可靠,這是一個學習項目,加上我可能會添加一些功能,如果我得到它的工作:)這是一個準系統(沒有線程,沒有錯誤處理)的版本到目前爲止(應該在Rust 1.8上編譯):
extern crate ssh2; // see http://alexcrichton.com/ssh2-rs/
use std::io::Read;
use std::io::Write;
use std::str;
use std::net;
fn main() {
// establish SSH session with remote host
println!("Connecting to host...");
// substitute appropriate value for IPv4
let tcp = net::TcpStream::connect("<IPv4>:22").unwrap();
let mut session = ssh2::Session::new().unwrap();
session.handshake(&tcp).unwrap();
// substitute appropriate values for username and password
// session.userauth_password("<username>", "<password>").unwrap();
assert!(session.authenticated());
println!("SSH session authenticated.");
// start listening for TCP connections
let listener = net::TcpListener::bind("localhost:5000").unwrap();
println!("Started listening, ready to accept");
for stream in listener.incoming() {
println!("===============================================================================");
// read the incoming request
let mut stream = stream.unwrap();
let mut request = vec![0; 8192];
let read_bytes = stream.read(&mut request).unwrap();
println!("REQUEST ({} BYTES):\n{}", read_bytes, str::from_utf8(&request).unwrap());
// send the incoming request over ssh on to the remote localhost and port
// where an HTTP server is listening
let mut channel = session.channel_direct_tcpip("localhost", 8080, None).unwrap();
channel.write(&request).unwrap();
// read the remote server's response (all of it, for simplicity's sake)
// and forward it to the local TCP connection's stream
let mut response = Vec::new();
let read_bytes = channel.read_to_end(&mut response).unwrap();
stream.write(&response).unwrap();
println!("SENT {} BYTES AS RESPONSE", read_bytes);
};
}
事實證明,這種工作,但不完全。例如。如果遠程服務器上運行的應用程序是Cloud9 IDE Core/SDK,主要的HTML頁面被加載和一些資源爲好,但請求其他資源(.js
,.css
)系統地回來空(是否請求由主網頁或直接),即在撥打channel.read_to_end()
時沒有任何內容。其他(更簡單?)Web應用程序或靜態網站似乎工作正常。最重要的是,當使用ssh -L 5000:localhost:8080
時,即使Cloud9 Core也能正常工作。
我預計其他更復雜的應用程序也會受到影響。我看到那裏的錯誤可能潛伏在我的代碼不同的潛在領域:
- 鏽病的流讀/寫的API:也許調用
channel.read_to_end()
作品不同於我認爲,只是偶然做正確的事對於一些類型的請求? - HTTP:在將請求轉發到遠程服務器之前,可能需要修改HTTP標頭?或者我可以通過撥打
channel.read_to_end()
來放棄響應流? - 鏽本身 - 這是在學習一門系統編程語言
我已經嘗試了一些上述的打我的第一個比較認真的嘗試,但我會感謝任何建議的路徑探索,較好隨着一個解釋,爲什麼這可能是問題:)
謝謝,你是對的,更好地保持焦點:) – dlukes
我無法讓代碼在本地運行,但'vec![0; 8192]'是可疑的。這創建了一個有很多零的向量。如果你從套接字中讀取一個字節,那麼在緩衝區中將會有8191個零。當你寫回來時,你正在編寫所有這些零,這是遠程端必須處理的。你只應該發送你閱讀的數據。 – Shepmaster
此外,您可能需要讀取輸入,直到HTTP標頭完成('\ r \ n \ r \ n',IIRC),然後向上遊發送。 – Shepmaster