dlu*_*kes 6 ssh tcp http tunnel rust
我正在尝试在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);
};
}
Run Code Online (Sandbox Code Playgroud)
事实证明,这种作品,但并不完全.例如,如果在远程服务器上运行的应用程序是Cloud9 IDE Core/SDK,则会加载主HTML页面和一些资源,但是对其他资源(.js,.css)的请求会系统地返回空(无论是主页还是直接请求) ),即在调用中没有读取任何内容channel.read_to_end().其他(更简单?)网络应用程序或静态网站似乎工作正常.至关重要的是,使用时ssh -L 5000:localhost:8080,即使是Cloud9 Core也能正常工作.
我预计其他更复杂的应用也会受到影响.我看到我的代码中潜在的bug可能存在的各种潜在区域:
channel.read_to_end()工作方式与我想的不同,只是偶然为某些请求做了正确的事情?channel.read_to_end()?我已经尝试过使用上面的一些内容,但我会感谢任何探索路径的建议,最好还有一个解释,为什么这可能是问题:)
dlu*_*kes -1
tl;dr:使用 Go 及其网络库来完成此特定任务
事实证明,我对 HTTP 工作原理的非常基本的理解可能有问题(我最初以为我可以通过 ssh 连接来回传输数据,但我还没有能够实现这一点——如果有人知道一种方法的话)这样做,我仍然很好奇!)。请参阅评论中的一些建议,但基本上可以归结为 HTTP 连接如何启动、保持活动状态和关闭的复杂性。我尝试使用hyper crate 来抽象这些细节,但由于线程安全限制,ssh2 Session 不能在 hyper handlers 中使用(至少在 2016 年不能)。
在这一点上,我认为初学者没有简单、高级的方法可以在 Rust 中实现这一目标(我必须先做一些低级的管道,并且由于我无法可靠且惯用地做到这一点,所以我想这根本不值得做)。因此,我最终分叉了这个用 Go 编写的SSHTunnel存储库,其中可以轻松获得对此特定任务的库支持,并且可以在此处找到 OP 中描述的 Cloud9 设置的解决方案。
| 归档时间: |
|
| 查看次数: |
1140 次 |
| 最近记录: |