提前准备:
TAP (Network TAP):工作在数据链路层(第2层)。
TUN (Network TUNnel):工作在网络层(第3层)。传输加密的 IP 数据包,从而实现点到点的加密通信。虚拟的物理网络接口,用户态可以直接写数据。 数据包可以被操作系统协议栈进一步处理,就像该数据包是通过一个物理网络接口接收到的一样。
TAP设备:
数据链路层设备:模拟以太网设备,处理以太网帧。
无需网络协议栈处理:数据帧直接传递,不需要进入内核的网络协议栈。
内核传输这些帧:
这些数据帧可以直接被其它网络工具处理或发送到实际物理接口。
内核中的 bridge 设备将这些帧传递到物理接口,或者转发给其他虚拟设备。
TUN设备:
网络层设备:模拟网络层设备,处理IP包。
需要网络协议栈处理:IP包需要进入内核网络协议栈进行处理。
内核处理这些包:
内核接收这些IP包进行网络层处理(如路由决策、转发、NAT等)。
内核将处理后的IP包发送到实际物理接口,或交给其他网络程序进行处理。
如何使用tap呢?
// TAP 配置
let mut config = Configuration::default();
config
.address((192, 168, 100, 1))
.netmask((255, 255, 255, 0))
.tap(true) // 指定使用 TAP 模式
.up();
// 创建并配置 TAP 设备
let mut dev = Device::new(&config).unwrap();
println!("TAP device created");
杂问杂答:A和B想要通过vpn进行通信。
- 网络协议:可以有很多种方式,这里使用的udp.
- udp里面传的是什么数据呢? wiregurad协议的数据, 一种vpn 协议。简单版本先不用考虑这个, 用一个加密的数据即可。
- 整个过程有没有内核参与呢? 有!!!
- 如果是tun的方式:用户态的!
- 用户态加解密数据,写入到tun(虚拟的网卡)
- 数据是怎么走到虚拟网卡的? 需要配置路由协议。
- 分配给tun的IP是虚拟的,随便设计IP的地址吧,但是要有,有了才能走路由规则。
服务依赖:
rand = "0.8.5"
tun = "0.6.1"
x25519-dalek = { version = "2.0.1", features = ["static_secrets"] }
blake2 = "0.11.0-pre.4"
服务端:
use tokio::{
net::UdpSocket,
io::{self, AsyncReadExt, AsyncWriteExt},
};
use tun::platform::Device;
use tun::Configuration;
use x25519_dalek::StaticSecret;
use x25519_dalek::PublicKey;
use blake2::Blake2s;
use blake2::digest::{Update, VariableOutput};
use rand::rngs::OsRng;
use std::process::Command;
pub async fn run_server() {
// TUN 配置
let mut config = Configuration::default();
config.address((10, 0, 0, 1)).netmask((255, 255, 255, 0)).up();
let mut dev = Device::new(&config).unwrap();
println!("Server TUN device created");
// 配置路由
configure_routing();
// 加密密钥
let server_privkey = StaticSecret::new(&mut OsRng);
let server_pubkey = PublicKey::from(&server_privkey);
let client_pubkey = PublicKey::from([0u8; 32]); // 从配置文件或命令行读取或替换为实际的客户端公钥
// UDP 套接字
let socket = UdpSocket::bind("0.0.0.0:51820").await.unwrap();
println!("Server listening on port 51820");
let mut buf = [0u8; 1500];
loop {
let (size, addr) = socket.recv_from(&mut buf).await.unwrap();
let decrypted = decrypt_data(&server_privkey, &client_pubkey, &buf[..size]);
dev.write(&decrypted).unwrap();
let size = dev.read(&mut buf).unwrap();
let encrypted = encrypt_data(&server_privkey, &client_pubkey, &buf[..size]);
socket.send_to(&encrypted, addr).await.unwrap();
}
}
fn configure_routing() {
// 删除现有的默认路由(如果有的话)
let _ = Command::new("sudo").arg("ip").arg("route").arg("del").arg("default").output();
// 添加新的默认路由通过 TUN 设备
let _ = Command::new("sudo").arg("ip").arg("route").arg("add").arg("default").arg("dev").arg("utun0").output();
// 确保 TUN 设备的网络范围内的流量也通过 TUN 设备
let _ = Command::new("sudo").arg("ip").arg("route").arg("add").arg("10.0.0.0/24").arg("dev").arg("utun0").output();
}
fn encrypt_data(server_privkey: &StaticSecret, client_pubkey: &PublicKey, data: &[u8]) -> Vec<u8> {
let shared_secret = server_privkey.diffie_hellman(client_pubkey);
let key = blake2_key_derive(&shared_secret);
// 使用对称加密(例如 ChaCha20)的逻辑进行加密
data.to_vec() // 暂时返回原数据
}
fn decrypt_data(server_privkey: &StaticSecret, client_pubkey: &PublicKey, data: &[u8]) -> Vec<u8> {
let shared_secret = server_privkey.diffie_hellman(client_pubkey);
let key = blake2_key_derive(&shared_secret);
// 使用对称加密(例如 ChaCha20)的逻辑进行解密
data.to_vec() // 暂时返回原数据
}
fn blake2_key_derive(shared_secret: &x25519_dalek::SharedSecret) -> Vec<u8> {
let mut hasher = Blake2s::new_keyed(shared_secret.as_bytes(), 32);
hasher.update(b"WireGuard");
let mut key = vec![0u8; 32];
hasher.finalize_variable(|res| key.copy_from_slice(res));
key
}
客户端:
use tokio::{
net::UdpSocket,
io::{self, AsyncReadExt, AsyncWriteExt},
};
use tun::platform::Device;
use tun::Configuration;
use x25519_dalek::StaticSecret;
use x25519_dalek::PublicKey;
use blake2::Blake2s;
use blake2::digest::{Update, VariableOutput};
use rand::rngs::OsRng;
use std::process::Command;
pub async fn run_client() {
// TUN 配置
let mut config = Configuration::default();
config.address((10, 0, 0, 2)).netmask((255, 255, 255, 0)).up();
let mut dev = Device::new(&config).unwrap();
println!("Client TUN device created");
// 配置路由
configure_routing();
// 加密密钥
let client_privkey = StaticSecret::new(&mut OsRng);
let client_pubkey = PublicKey::from(&client_privkey);
let server_pubkey = PublicKey::from([0u8; 32]); // 从配置文件或命令行读取或替换为实际的服务器公钥
// UDP 套接字
let socket = UdpSocket::bind("0.0.0.0:51820").await.unwrap();
socket.connect("<公司公网IP>:51820").await.unwrap();
println!("Connected to server");
let mut buf = [0u8; 1500];
loop {
let size = dev.read(&mut buf).unwrap();
let encrypted = encrypt_data(&client_privkey, &server_pubkey, &buf[..size]);
socket.send(&encrypted).await.unwrap();
let received_size = socket.recv(&mut buf).await.unwrap();
let decrypted = decrypt_data(&client_privkey, &server_pubkey, &buf[..received_size]);
dev.write(&decrypted).unwrap();
}
}
fn configure_routing() {
// 删除现有的默认路由(如果有的话)
let _ = Command::new("sudo").arg("ip").arg("route").arg("del").arg("default").output();
// 添加新的默认路由通过 TUN 设备
let _ = Command::new("sudo").arg("ip").arg("route").arg("add").arg("default").arg("dev").arg("utun0").output();
// 确保 TUN 设备的网络范围内的流量也通过 TUN 设备
let _ = Command::new("sudo").arg("ip").arg("route").arg("add").arg("10.0.0.0/24").arg("dev").arg("utun0").output();
}
fn encrypt_data(client_privkey: &StaticSecret, server_pubkey: &PublicKey, data: &[u8]) -> Vec<u8> {
let shared_secret = client_privkey.diffie_hellman(server_pubkey);
let key = blake2_key_derive(&shared_secret);
// 使用对称加密(例如 ChaCha20)的逻辑进行加密
data.to_vec() // 暂时返回原数据
}
fn decrypt_data(client_privkey: &StaticSecret, server_pubkey: &PublicKey, data: &[u8]) -> Vec<u8> {
let shared_secret = client_privkey.diffie_hellman(server_pubkey);
let key = blake2_key_derive(&shared_secret);
// 使用对称加密(例如 ChaCha20)的逻辑进行解密
data.to_vec() // 暂时返回原数据
}
fn blake2_key_derive(shared_secret: &x25519_dalek::SharedSecret) -> Vec<u8> {
let mut hasher = Blake2s::new_keyed(shared_secret.as_bytes(), 32);
hasher.update(b"WireGuard");
let mut key = vec![0u8; 32];
hasher.finalize_variable(|res| key.copy_from_slice(res));
key
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。