我试图在Rust中编写一个小程序来基本完成ssh -L 5000:localhost:8080
的工作:在我的机器上的localhost:5000
和远程机器上的localhost:8080
之间建立隧道,因此,如果HTTP服务器在远程端口8080上运行,我可以通过localhost:5000
在本地访问它,绕过远程防火墙,这可能会阻止对8080的外部访问。
我意识到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
,{{1 }})系统地返回空(无论是主页还是直接请求),即在.css
的调用中没有读取任何内容。其他(更简单?)网络应用程序或静态网站似乎工作正常。至关重要的是,使用channel.read_to_end()
时,即使是Cloud9 Core也能正常工作。
我预计其他更复杂的应用也会受到影响。我在代码中看到了潜在的潜在区域:
ssh -L 5000:localhost:8080
的调用可能与我想的不同,只是偶然为某些请求做了正确的事情?channel.read_to_end()
?我已经尝试过使用上述某些内容,但我会感谢任何探索路径的建议,最好还要解释为什么可能会出现问题:)
答案 0 :(得分:1)
tl; dr :使用Go及其网络库执行此特定任务
原来我对HTTP的工作方式的基本理解可能是错误的(我最初认为我可以通过ssh连接来回挖掘数据,但我无法实现这一点 - 如果有人知道的话为了做到这一点,我仍然很好奇!)。请参阅评论中的一些建议,但基本上归结为HTTP连接如何启动,保持活动和关闭的复杂性。我尝试使用hyper包来抽象掉这些细节,但事实证明ssh2包(就像底层的libssh2)不是线程安全的,这使得在超级处理程序中使用ssh Session成为不可能。
此时,我认为初学者没有简单,高级方式来实现Rust中的这种方式(我是我必须首先做一些低级别的管道,因为我不能可靠地和惯用地做到这一点,我认为它根本不值得做。所以我最终分配了用Go编写的这个SSHTunnel存储库,其中对此特定任务的库支持很容易获得,我可以找到我在OP中描述的Cloud9设置的解决方案here。