aboutsummaryrefslogtreecommitdiff
path: root/debian-container/lib/network.sh
blob: a5a31ddfeacec2e6177dc243902a260474fe3947 (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
#!/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" "$@"
}