网络不通的版本

main
阳光少年 1 year ago
parent 84790df859
commit a7188b94ff

67
Cargo.lock generated

@ -57,6 +57,12 @@ version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -184,6 +190,15 @@ dependencies = [
"libc",
]
[[package]]
name = "ppv-lite86"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.86"
@ -202,12 +217,43 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "rocker"
version = "0.1.0"
dependencies = [
"clap",
"nix",
"rand",
"serde",
"toml",
"uuid",
@ -401,3 +447,24 @@ checksum = "b480ae9340fc261e6be3e95a1ba86d54ae3f9171132a73ce8d4bbaf68339507c"
dependencies = [
"memchr",
]
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

@ -4,13 +4,13 @@ version = "0.1.0"
edition = "2021"
[dependencies]
rand = "0.8.5"
uuid = {version = "1.3", features = ["v4"]}
toml = "0.8.8"
clap = {version = "4.5.0", features = ["derive"]}
nix = {version = "0.29", features = ["sched", "process", "hostname", "mount", "fs", "env", "user", "term", "signal"]}
serde = { version = "1.0", features = ["derive"] }
[[bin]]
name = "network"
path = "src/network.rs"

@ -1,24 +1,37 @@
WORKSPACE := /root/rocker
WORKSPACE := /home/rocker
USER_NAME := rocker
PASSWORD = asd123
build:
cargo build --release
# 创建WORKSPACE 对应的文件夹
install: build
mkdir -p $(WORKSPACE)
install:
@# 创建一个普通用户
-@echo "Creating user $(USER_NAME)"
-@sudo useradd -m -s /bin/bash $(USER_NAME)
@# 设置密码
-@echo "Setting password for $(USER_NAME)"
-@echo "$(USER_NAME):$(PASSWORD)" | sudo chpasswd
@# 授权sudo
-@echo "Authorizing $(USER_NAME) to use sudo"
-@sudo sh -c "echo '$(USER_NAME) ALL=(ALL) ALL' >> /etc/sudoers"
mkdir -p $(WORKSPACE)/images
mkdir -p $(WORKSPACE)/volumes
mkdir -p $(WORKSPACE)/containers
chmod -R 777 $(WORKSPACE)
cp images/* $(WORKSPACE)/images/
chown -R rocker:rocker $(WORKSPACE)
cp images/* /root/rocker/images/
cp target/release/rocker /usr/bin/rocker
# 创建一个普通用户
-useradd -g rocker rocker
-groupadd rocker
-sysctl net.ipv4.conf.all.forwarding=1
-iptables -t filter -P FORWARD ACCEPT
clean:
-rocker --rm all
-rm -rf $(WORKSPACE)
-rm -rf $(WORKSPACE)/*
-rm -rf /usr/bin/rocker
-@echo "Cleaning up"
-@sudo userdel -r $(USER_NAME)
-@sudo sed -i "/^$(USER_NAME)/d" /etc/sudoers

@ -7,7 +7,7 @@ use path::{Path, PathBuf};
use nix::sched::{clone, CloneCb, CloneFlags, setns};
use nix::sys::{signal::{kill, Signal}, wait::{waitpid, WaitPidFlag}};
use nix::unistd::{dup2, pivot_root, setgid, setgroups, sethostname, setuid, Gid, Pid, Uid, User};
use nix::unistd::{pause, dup2, pivot_root, setgid, setgroups, sethostname, setuid, Gid, Pid, Uid, User};
use nix::mount::{mount, MntFlags, MsFlags, umount2};
use uuid;
use toml;
@ -17,7 +17,7 @@ use clap::Parser;
use error::{Result, RockerError};
mod error;
static WORKSPACE: &str = "/root/rocker";
static WORKSPACE: &str = "/home/rocker";
static USER_NAME: &str = "rocker";
static INFO_FILE: &str = "info.toml";
static LOCK_FILE: &str = ".lock";
@ -98,6 +98,13 @@ fn extend_image(image_name: &String) -> Result<PathBuf> {
if out.status.success() {
println!("解压缩完毕: {image_name:?}");
// 把解压缩后的文件全部给 rocker:rocker
let out = process::Command::new("chown")
.arg("-R")
.arg("rocker:rocker")
.arg(volume_path_str)
.output()?;
println!("{out:?}");
Ok(volume_path)
} else {
// 删除 volume_path
@ -304,46 +311,47 @@ fn init_exec_ns(pid: i32) -> Result<()>{
Ok(())
}
fn start(is_wait: bool, cb: CloneCb, clong_flags: CloneFlags) -> Result<i32>{
let main_exe = std::env::current_exe()?;
unsafe {
match clone(cb, STACK.as_mut_slice(), clong_flags, None) {
Ok(child_pid) => {
println!("clone ok: {child_pid:?}");
// check_container_is_running
let mut cnt = 0;
while let Ok(running) = check_container_is_running(&child_pid, &main_exe) {
cnt += 1;
std::thread::sleep(std::time::Duration::from_millis(10));
if running {
break;
}
if cnt > 1000 {
println!("{child_pid} 启动 超时");
break;
}
match unsafe {clone(cb, STACK.as_mut_slice(), clong_flags, None)} {
Ok(child_pid) => {
println!("clone ok: {child_pid:?}");
// exec之前的步骤
// 检查是否执行exec了
let mut cnt = 0;
let main_exe = std::env::current_exe()?;
while let Ok(running) = check_container_is_running(&child_pid, &main_exe) {
cnt += 1;
std::thread::sleep(std::time::Duration::from_millis(10));
if running {
break;
}
// wait
if is_wait {
match waitpid(child_pid, Some(WaitPidFlag::WUNTRACED)) {
Ok(status) => {
println!("{child_pid:?} exit: {status:?}");
}
Err(e) => {
println!("{child_pid} wait err: {e}");
}
}
if cnt > 1000 {
println!("{child_pid} 启动 超时");
break;
}
Ok(child_pid.as_raw())
}
Err(e) => {
Err(RockerError::OtherError(format!("clone err: {e}")))
// wait
if is_wait {
match waitpid(child_pid, Some(WaitPidFlag::WUNTRACED)) {
Ok(status) => {
println!("{child_pid:?} exit: {status:?}");
}
Err(e) => {
println!("{child_pid} wait err: {e}");
}
}
}
Ok(child_pid.as_raw())
}
Err(e) => {
Err(RockerError::OtherError(format!("clone err: {e}")))
}
}
}
fn run_container(_container_id: &String, cmd: &String, args: &RockerArgs, volume_path: &PathBuf, is_exec: bool) -> Result<i32> {
@ -365,6 +373,7 @@ fn run_container(_container_id: &String, cmd: &String, args: &RockerArgs, volume
init_container_env(None).unwrap();
init_container_user(rocker_uid, rocker_gid).unwrap();
// pause();
let cmd_vec = cmd.split(" ").collect::<Vec<&str>>();
let err = process::Command::new(cmd_vec[0])
.args(&cmd_vec[1..])
@ -397,6 +406,7 @@ fn run_container(_container_id: &String, cmd: &String, args: &RockerArgs, volume
init_container_log(args.log).unwrap();
init_container_user(rocker_uid, rocker_gid).unwrap();
// pause();
let cmd_vec = cmd.split(" ").collect::<Vec<&str>>();
let err = process::Command::new(cmd_vec[0])
.args(&cmd_vec[1..])

@ -1,33 +1,306 @@
use std::{fs::OpenOptions, io::Read, os::unix::net};
use rand::Rng;
fn get_gateway_addr(addr: &str) -> String {
let prefix = &addr[..addr.len() - 1];
format!("{}0", prefix)
}
fn create_bridge_dev(bridge_name: &str) {
// brctl addbr br0
let args = ["addbr", bridge_name];
println!("create_bridge_dev: {args:?}");
let out = std::process::Command::new("brctl")
.args(args)
.output()
.unwrap();
if !out.status.success() {
panic!("{:?}", out);
}
}
fn set_bridge_ip(bridge_name: &str, addr: &str){
// 设置容器内从ip: ip addr add 192.168.124.1/24 dev bridge_name
let args = ["addr", "add", &format!("{addr}/24"), "dev", bridge_name];
println!("set_bridge_ip: {args:?}");
let out = std::process::Command::new("ip")
.args(args)
.output()
.unwrap();
if !out.status.success() {
panic!("{:?}", out);
}
}
fn main(){
fn set_slave_ip(slave_veth_name: &str, addr: &str, pid: &str) {
// nsenter -t 10050 -n -- ip addr add <ip_address>/<subnet_mask> dev veth1
let args = ["-t", pid, "-n", "--", "ip", "addr", "add", &format!("{addr}/24"), "dev", slave_veth_name];
println!("set_slave_ip: {args:?}");
let out = std::process::Command::new("nsenter")
.args(args)
.output()
.unwrap();
if !out.status.success() {
panic!("{:?}", out);
}
}
fn set_net_up(bridge_name: &str, master_veth_name: &str, pid: &str, slave_veth_name: &str) {
// sudo ip link set bridge_name up
let args = ["link", "set", bridge_name, "up"];
println!("set_up: {args:?}");
let out = std::process::Command::new("ip")
.args(args)
.output()
.unwrap();
if !out.status.success() {
panic!("{:?}", out);
}
// sudo ip link set master_veth_name up
let args = ["link", "set", master_veth_name, "up"];
println!("set_up: {args:?}");
let out = std::process::Command::new("ip")
.args(args)
.output()
.unwrap();
if !out.status.success() {
println!("{:?}", out);
}
// nsenter -t 1970 -n -- ip link set dev slave_veth_name up
let args = ["-t", pid, "-n", "--", "ip", "link", "set", "dev", slave_veth_name, "up"];
println!("set_up: {args:?}");
let out = std::process::Command::new("nsenter")
.args(args)
.output()
.unwrap();
if !out.status.success() {
println!("{:?}", out);
}
}
fn set_up(dev_name: &str) {
// sudo ip link set bridge_name up
let args = ["link", "set", dev_name, "up"];
println!("set_up: {args:?}");
let out = std::process::Command::new("ip")
.args(args)
.output()
.unwrap();
if !out.status.success() {
println!("{:?}", out);
}
}
fn set_route(bridge_name: &str, addr: &str) {
// ip route add 192.168.100.0/24 via 192.168.100.1 dev bridge_name
// sudo ip netns exec ns1 ip route add default via 172.18.0.1 dev veth0
// 把addr最后的1位替换为0
let gateway_addr = get_gateway_addr(addr);
// 删掉系统自动添加的 ip route del 172.18.0.0/24 dev br0
let args = ["route", "del", &format!("{gateway_addr}/24"), "dev", bridge_name];
println!("set_route: {args:?}");
let out = std::process::Command::new("ip")
.args(args)
.output()
.unwrap();
if !out.status.success() {
println!("{:?}", out);
}
let args = ["route", "add", &format!("{gateway_addr}/24"), "via", addr, "dev", bridge_name];
println!("set_route: {args:?}");
let out = std::process::Command::new("ip")
.args(args)
.output()
.unwrap();
if !out.status.success() {
println!("{:?}", out);
}
}
fn set_net(bridge_name: &str, addr: &str){
// sudo iptables -t nat -A POSTROUTING -s 172.18.0.0/24 ! -o bridge_name -j MASQUERADE
let gateway_addr = get_gateway_addr(addr);
let args = ["-t", "nat", "-A", "POSTROUTING", "-s", &format!("{gateway_addr}/24"), "!", "-o", bridge_name, "-j", "MASQUERADE"];
println!("set_net: {args:?}");
let out = std::process::Command::new("iptables")
.args(args)
.output()
.unwrap();
if !out.status.success() {
println!("{:?}", out);
}
}
fn del_bridge(bridge_name: &str) {
// sudo brctl delbr br0
let args = ["delbr", bridge_name];
println!("del_bridge: {args:?}");
let out = std::process::Command::new("brctl")
.args(args)
.output()
.unwrap();
if !out.status.success() {
println!("{:?}", out);
}
}
fn create_veth_pair(master_veth_name: &str, slave_veth_name: &str) {
// sudo ip link add veth0 type veth peer name veth1
let args = ["link", "add", master_veth_name, "type", "veth", "peer", "name", slave_veth_name];
println!("create_veth_pair: {args:?}");
let out = std::process::Command::new("ip")
.args(args)
.output()
.unwrap();
if !out.status.success() {
panic!("{:?}", out);
}
}
#[derive(Debug)]
struct NetWrok {
gateway_addr: String, // 192.168.124.0
bridge_addr: String, // 192.168.124.1
slave_addr: String,
bridge_name: String, // uuid[:8]_1 // ip 就是 192.168.124.1
master_veth_name: String, // uuid[:8]_2 // 不分配ip 直接插到桥
slave_veth_name: String, // uuid[:8]_3 // ip 就是 192.168.124.3, 插在容器中
}
fn get_all_network() -> Vec<NetWrok> {
// 打开 /home/rocker/network 所有已经配置的信息, 如果没有则创建
let mut f = OpenOptions::new()
.write(true)
.create(true)
.read(true)
.open("/home/rocker/network")
.unwrap();
let mut text = String::new();
f.read_to_string(&mut text).unwrap();
vec![]
}
fn master_join_bridge(bridge_name: &str, master_veth_name: &str) {
// 将主端链接到桥
//sudo brctl addif bridge_name master_veth_name
let args = ["addif", bridge_name, master_veth_name];
println!("master_join_bridge: {args:?}");
let out = std::process::Command::new("brctl")
.args(args)
.output()
.unwrap();
if !out.status.success() {
panic!("{:?}", out);
}
}
fn slave_join_bridge(slave_veth_name: &str, pid: &str) {
// 将从端 链接到容器
// sudo ip link set slave_veth_name netns 1234
let args = ["link", "set", slave_veth_name, "netns", pid];
println!("slave_join_bridge: {args:?}");
#[test]
fn test_network() {
let bridge_name = "test_rocker";
// ip link add xxxx
// ip link add name br0 type bridge
let out = std::process::Command::new("ip")
.arg("link")
.arg("add")
.arg("name")
.arg(bridge_name)
.arg("type")
.arg("bridge")
.args(args)
.output()
.unwrap();
out.status.success();
println!("{:?}", out);
if !out.status.success() {
panic!("{:?}", out);
}
}
fn create_network(uuid_name: &str, pid: i32) {
// 创建一个随机地址段的 没分配过的ip
let all_network = get_all_network();
let mut rg = rand::thread_rng();
let network = loop {
// 生成一个随机桥ip
let base_addr = format!("{}.{}.{}", rg.gen_range(200..240), rg.gen_range(200..240), rg.gen_range(200..240));
let gateway_addr = format!("{base_addr}.0");
let bridge_addr = format!("{base_addr}.1");
let slave_addr = format!("{base_addr}.3");
if all_network.iter().any(|n|n.bridge_addr == bridge_addr) == false {
let bridge_name = format!("{uuid_name}_1");
let master_veth_name = format!("{uuid_name}_2");
let slave_veth_name = format!("{uuid_name}_3");
let net_work = NetWrok {
gateway_addr,
bridge_addr,
slave_addr,
bridge_name,
master_veth_name,
slave_veth_name,
};
break net_work;
}
};
let line = format!("{},{},{},{},{},{}", network.gateway_addr, network.bridge_addr, network.slave_addr, network.bridge_name, network.master_veth_name, network.slave_veth_name);
println!("{line:?}");
// 系统中创建桥
create_bridge_dev(&network.bridge_name);
// 给桥分配ip
set_bridge_ip(&network.bridge_name, &network.bridge_addr);
// 创建veth pair
create_veth_pair(&network.master_veth_name, &network.slave_veth_name);
// 宿主机 主pair 连接桥
master_join_bridge(&network.bridge_name, &network.master_veth_name);
// 把从 pair 添加到容器内
slave_join_bridge(&network.slave_veth_name, pid.to_string().as_str());
// 给容器内 pair 分配ip
set_slave_ip(&network.slave_veth_name, &network.slave_addr, pid.to_string().as_str());
// 激活 上线
set_net_up(&network.bridge_name, &network.master_veth_name, pid.to_string().as_str(), &&network.slave_veth_name);
// 配置路由
println!("123");
// let mut f = OpenOptions::new()
// .write(true)
// .create(true)
// .read(true)
// .open("/home/rocker/network")
// .unwrap();
}
fn main(){
// get_all_network();
let container_id = uuid::Uuid::new_v4().to_string()[0..3].to_string();
create_network(&container_id, 28930);
return;
let addr = "192.168.124.1";
let bridge_name = &format!("rocker_{}", addr[8..].replace(".", "_"));
println!("{bridge_name}");
println!("{addr}");
create_bridge_dev(&bridge_name);
set_bridge_ip(&bridge_name, &addr);
set_up(&bridge_name);
// 我们在 set_bridge中补充了网段信息 /24 所以在 set_up的时候, 会自动配置路由表配置路由表 192.168.0.0/24 转发到这 bridge_name 的网络接口上
// set_route(bridge_name, addr);
set_net(bridge_name, addr);
let veth_name = "yanguang";
// connect(bridge_name, veth_name);
}

Loading…
Cancel
Save