diff --git a/vn-link-cli/Cargo.toml b/vn-link-cli/Cargo.toml new file mode 100644 index 0000000..23a1a9a --- /dev/null +++ b/vn-link-cli/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "vn-link-cli" +version = "1.2.10" +edition = "2021" + +[dependencies] +vn-link = { path = "../vn-link", default-features = false } +common = { path = "../common", default-features = false } +tokio = { version = "1.37.0", features = ["full"] } +log = "0.4.17" + +[features] +default = ["default-feature"] +openssl = ["vn-link/openssl","common/openssl"] +openssl-vendored = ["vn-link/openssl-vendored","common/openssl-vendored"] +ring-cipher = ["vn-link/ring-cipher","common/ring-cipher"] +aes_cbc = ["vn-link/aes_cbc","common/aes_cbc"] +aes_ecb = ["vn-link/aes_ecb","common/aes_ecb"] +sm4_cbc = ["vn-link/sm4_cbc","common/sm4_cbc"] +aes_gcm = ["vn-link/aes_gcm","common/aes_gcm"] +chacha20_poly1305 = ["vn-link/chacha20_poly1305","common/chacha20_poly1305"] +server_encrypt = ["vn-link/server_encrypt","common/server_encrypt"] +port_mapping = ["vn-link/port_mapping","common/port_mapping"] +lz4 = ["vn-link/lz4_compress","common/lz4"] +zstd = ["vn-link/zstd_compress","common/zstd"] +log = ["common/log"] +command = ["common/command"] +file_config = ["common/file_config"] + +default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "log", "command", "file_config", "lz4"] diff --git a/vn-link-cli/README.md b/vn-link-cli/README.md new file mode 100644 index 0000000..665196c --- /dev/null +++ b/vn-link-cli/README.md @@ -0,0 +1,61 @@ +# 端口映射模式 + +## 一、特点 + +1. 不需要tap/tun虚拟网卡 +2. 不需要管理员/root权限 +3. 使用端口映射来访问目标服务 + +## 二、作用 + +1. 和vnt互补,能简单快速构建网络 +2. 充当被访问端,外部依赖更少 + +## 三、使用方式 + +和vnt的使用方式一样,只是多了"--vnt-mapping"这个参数 + +### vn-link作为被访问端,不需要额外配置vnt-mapping + +### vn-link访问vnt或者vn-link,需要加vnt-mapping + +例如: + +设备A 运行vnt(虚拟IP 10.26.0.A),设备B 运行vn-link(虚拟IP 10.26.0.B)。 + +如果要用B访问A上的tcp 80端口,则在设备B上需要加--vnt-mapping "tcp:port1-10.26.0.A:80" + +这个参数的作用是将B上的***本地端口port1***转发到设备A的地址10.26.0.A: +80,此时在设备B上可以访问本地port1端口从而间接访问10.26.0.A:80 + +## 四、vn-link的子网代理 + +vn-link也支持点对网参数。 还是接着上面的例子 + +假设 设备C在设备A的子网下,C的子网IP为192.168.1.C,A的子网IP为192.168.1.A,要在设备B上访问C + +则在B上加这些参数 + +- --vnt-mapping "tcp:port2-192.168.1.C:80" (将本地port2端口映射到C的80端口) +- -i 192.168.1.0/24,10.26.0.A (将目标192.168.1.0/24的数据发送到10.26.0.A,也就是A节点) + +在A上加参数 + +- -o 0.0.0.0/0 (允许所有流量转发) + +***再次说明,vn-link作为被访问端时和vnt使用方式一致,vn-link作为访问端时需要加--vnt-mapping映射端口*** + +***vn-link是基于端口映射的使用模式,不会改变本地路由*** + +## 五、参数介绍 + +--vnt-mapping支持udp/tcp,例如 --vnt-mapping "tcp:port1-remoteIp:remotePort" + +- 第一部分为协议,支持使用udp/tcp +- 第二部分是本地端口,注意不要和本地服务的端口冲突 +- 第三部分是目标机器的地址,一般是目标虚拟IP地址,如果配置了点对网参数(-i和-o)则也可以是目标子网地址 + + + + + diff --git a/vn-link-cli/src/main.rs b/vn-link-cli/src/main.rs new file mode 100644 index 0000000..78336a3 --- /dev/null +++ b/vn-link-cli/src/main.rs @@ -0,0 +1,84 @@ +use common::callback; +use vn_link::config::VnLinkConfig; +use vn_link::vnt::core::Config; + +fn main() { + let (config, vnt_link_config, cmd) = match common::cli::parse_args_config() { + Ok(rs) => { + if let Some(rs) = rs { + rs + } else { + return; + } + } + Err(e) => { + println!("{}", e); + return; + } + }; + let vnt_link_config = VnLinkConfig::new(vn_link::config::convert(vnt_link_config).unwrap()); + main0(config, vnt_link_config, cmd) +} + +#[tokio::main] +async fn main0(config: Config, vn_link_config: VnLinkConfig, _show_cmd: bool) { + #[cfg(feature = "port_mapping")] + for (is_tcp, addr, dest) in config.port_mapping_list.iter() { + if *is_tcp { + println!("TCP port mapping {}->{}", addr, dest) + } else { + println!("UDP port mapping {}->{}", addr, dest) + } + } + for x in &vn_link_config.mapping { + if x.protocol.is_tcp() { + println!("TCP vnt addr mapping 127.0.0.1:{}->{}", x.src_port, x.dest) + } else { + println!("UDP vnt addr mapping 127.0.0.1:{}->{}", x.src_port, x.dest) + } + } + + let vnt_util = match vn_link::VnLink::new(config, vn_link_config, callback::VntHandler {}).await + { + Ok(vnt) => vnt, + Err(e) => { + println!("error: {:?}", e); + std::process::exit(1); + } + }; + + #[cfg(feature = "command")] + { + let vnt_c = vnt_util.as_vnt().clone(); + std::thread::Builder::new() + .name("CommandServer".into()) + .spawn(move || { + if let Err(e) = common::command::server::CommandServer::new().start(vnt_c) { + log::warn!("cmd:{:?}", e); + } + }) + .expect("CommandServer"); + let vnt_c = vnt_util.as_vnt(); + if _show_cmd { + use tokio::io::AsyncBufReadExt; + let mut cmd = String::new(); + let mut reader = tokio::io::BufReader::new(tokio::io::stdin()); + loop { + cmd.clear(); + println!("======== input:list,info,route,all,stop ========"); + match reader.read_line(&mut cmd).await { + Ok(len) => { + if !common::command::command_str(&cmd[..len], vnt_c) { + break; + } + } + Err(e) => { + println!("input err:{}", e); + break; + } + } + } + } + } + vnt_util.wait().await +}