blob: efe0d4722036895d9a3aeef53d0b9aaadd3210bd (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-3.0-or-later
# Copyright (C) 2026 by Richard Qin
DC_NETWORK_MODE=${DEBIAN_NETWORK:-none}
DC_NETWORK_UNSHARE_ARGS=()
DC_NAT_BRIDGE=${DEBIAN_NAT_BRIDGE:-rutils0}
DC_NAT_NETWORK=${DEBIAN_NAT_NETWORK:-10.88.0.0/24}
DC_NAT_PREFIX=${DC_NAT_NETWORK#*/}
DC_NAT_GATEWAY=${DEBIAN_NAT_GATEWAY:-10.88.0.1}
DC_NAT_ADDRESS=${DEBIAN_NAT_ADDRESS:-10.88.0.2}
DC_NAT_DNS=${DEBIAN_NAT_DNS:-1.1.1.1}
dc_network_prepare() {
local mode=${1:-$DC_NETWORK_MODE}
case "$mode" in
none)
DC_NETWORK_UNSHARE_ARGS=(--net)
;;
host)
DC_NETWORK_UNSHARE_ARGS=()
;;
nat)
DC_NETWORK_UNSHARE_ARGS=(--net)
;;
*)
dc_die "网络模式无效:$mode(可选:none、host、nat)"
;;
esac
}
dc_network_configure_rootfs() {
[[ "$DC_NETWORK_MODE" == nat ]] || return 0
rm -f "$DC_ROOT/etc/resolv.conf"
printf 'nameserver %s\n' "$DC_NAT_DNS" > "$DC_ROOT/etc/resolv.conf"
}
dc_network_nat_setup_firewall() {
dc_require_commands grep nft sysctl
sysctl -w net.ipv4.ip_forward=1 >/dev/null
if ! nft list table ip rutils_nat >/dev/null 2>&1; then
nft add table ip rutils_nat
fi
if ! nft list chain ip rutils_nat postrouting >/dev/null 2>&1; then
nft 'add chain ip rutils_nat postrouting { type nat hook postrouting priority 100; policy accept; }'
fi
if ! nft list chain ip rutils_nat postrouting | grep -Fq "ip saddr $DC_NAT_NETWORK"; then
nft add rule ip rutils_nat postrouting ip saddr "$DC_NAT_NETWORK" oifname != "$DC_NAT_BRIDGE" masquerade
fi
}
dc_network_nat_setup() {
local netns=$1
local host_interface=$2
local guest_interface=$3
dc_require_commands grep ip
if ! ip link show "$DC_NAT_BRIDGE" >/dev/null 2>&1; then
ip link add "$DC_NAT_BRIDGE" type bridge
fi
ip link set "$DC_NAT_BRIDGE" up
if ! ip -4 addr show dev "$DC_NAT_BRIDGE" | grep -Fq "inet $DC_NAT_GATEWAY/"; then
ip addr add "$DC_NAT_GATEWAY/$DC_NAT_PREFIX" dev "$DC_NAT_BRIDGE"
fi
ip netns add "$netns"
ip link add "$host_interface" type veth peer name "$guest_interface"
ip link set "$guest_interface" netns "$netns"
ip link set "$host_interface" master "$DC_NAT_BRIDGE"
ip link set "$host_interface" up
ip netns exec "$netns" ip link set lo up
ip netns exec "$netns" ip link set "$guest_interface" name eth0
ip netns exec "$netns" ip addr add "$DC_NAT_ADDRESS/$DC_NAT_PREFIX" dev eth0
ip netns exec "$netns" ip link set eth0 up
ip netns exec "$netns" ip route add default via "$DC_NAT_GATEWAY"
dc_network_nat_setup_firewall
}
dc_network_nat_cleanup() {
local netns=$1
local host_interface=$2
ip link delete "$host_interface" 2>/dev/null || true
ip netns delete "$netns" 2>/dev/null || true
}
dc_network_nat_run() {
local child_action=$1
local netns="rutils-${DC_INSTANCE}-$$"
local host_interface="rvh$$"
local guest_interface="rvg$$"
shift
trap "dc_network_nat_cleanup '$netns' '$host_interface'" EXIT
dc_network_nat_setup "$netns" "$host_interface" "$guest_interface"
env DEBIAN_NETWORK=nat ip netns exec "$netns" \
unshare --mount --uts --ipc --pid --fork --propagation private -- \
bash "$DC_SCRIPT" "$child_action" "$DC_INSTANCE" "$@"
}
dc_network_nat_namespaces() {
ip netns list | awk '$1 ~ /^rutils-/ { print $1 }'
}
dc_network_status() {
local namespace
local link
dc_require_commands awk ip nft
echo "网桥:$DC_NAT_BRIDGE"
if ip link show "$DC_NAT_BRIDGE" >/dev/null 2>&1; then
ip -brief addr show dev "$DC_NAT_BRIDGE"
else
echo '状态:不存在'
fi
echo 'network namespace:'
while read -r namespace; do
[[ -n "$namespace" ]] || continue
echo " $namespace"
ip netns pids "$namespace" | awk '{ print " pid: " $0 }'
done < <(dc_network_nat_namespaces)
echo 'veth:'
while read -r link; do
[[ -n "$link" ]] || continue
echo " $link"
done < <(ip -o link show | awk -F': ' '$2 ~ /^rvh[0-9]+@/ { sub(/@.*/, "", $2); print $2 }')
echo 'nftables:'
if nft list table ip rutils_nat >/dev/null 2>&1; then
nft list table ip rutils_nat
else
echo ' rutils_nat 不存在'
fi
}
dc_network_clean() {
local namespace
local link
local active=0
dc_require_commands awk ip nft
while read -r namespace; do
[[ -n "$namespace" ]] || continue
if [[ -n "$(ip netns pids "$namespace")" ]]; then
echo "保留活动 namespace:$namespace"
active=1
else
ip netns delete "$namespace"
echo "已删除 namespace:$namespace"
fi
done < <(dc_network_nat_namespaces)
if ((active == 0)); then
while read -r link; do
[[ -n "$link" ]] || continue
ip link delete "$link" 2>/dev/null || true
echo "已删除 veth:$link"
done < <(ip -o link show | awk -F': ' '$2 ~ /^rvh[0-9]+@/ { sub(/@.*/, "", $2); print $2 }')
nft delete table ip rutils_nat 2>/dev/null || true
if ip link show "$DC_NAT_BRIDGE" >/dev/null 2>&1; then
ip link set "$DC_NAT_BRIDGE" down
ip link delete "$DC_NAT_BRIDGE" type bridge
fi
echo '已清理 NAT 网桥和 nftables 规则。'
else
echo '存在活动 namespace,保留 veth。'
echo '存在活动 namespace,保留 NAT 网桥和 nftables 规则。'
fi
}
|