-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuild-net
executable file
·166 lines (148 loc) · 4.52 KB
/
build-net
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
#!/bin/sh -efu
# vim:et:sw=4
#
# Copyright (c) 2019-2025 Nikita (sh1r4s3) Ermakov <[email protected]>
# SPDX-License-Identifier: MIT
#
fatal() {
printf "fatal error: %s\n" "${1-}"
exit 1
}
# Help message
help()
{
cat <<EOF
${0##*/} -- create network namespace for runns.
Usage: ${0##*/} [options]
Options:
-h | --help print this help message
-n | --name namespace name (default is "vpnX", where X is a number)
-s | --section specify section to load from /etc/runns.conf
-i | --int interface name (default is "eth0")
-o | --out interface name for veth in default network namespace
(default is "vpnX", where X is a number)
-r | --resolve path to resolv.conf file for this network namespace
EOF
exit 0
}
read_section()
{
[ -f "${CONFIG-}" ] || { echo "No config file was specified"; exit 1; }
[ "$#" -eq "1" ] || { echo "Not enough number of arguments"; exit 1; }
awk -F '=' -v section="[${SECTION-}]" -v field="$1" '
BEGIN{ IGNORECASE = 1}
flag && /^\[/{ exit }
$0==section { flag=1; next }
flag && $1==field{ print $2; exit }
' $CONFIG
}
# Parse command line arguments
TMPARGS="$(getopt -n "$0" -o n:,i:,o:,s:,r:,h -l name:,int:,out:,section:,resolve:,help -- "$@")" || help
eval set -- "$TMPARGS"
NS=
INT=
OUT=
CONFIG=/etc/runns.conf
SECTION=
RESOLVE=
TYPE_DEF=
while :
do
case "$1" in
--)
shift; break ;;
-n|--name)
shift; NS="$1" ;;
-i|--int)
shift; INT="$1" ;;
-o|--out)
shift; OUT="$1" ;;
-s|--section)
shift; SECTION="$1" ;;
-r|--resolve)
shift; RESOLVE="$1" ;;
*)
help ;;
esac
shift
done
# Load configuration file if it was specified
if [ -n "$SECTION" ]; then
# Read network namespace if it is not set
[ -n "$NS" ] || NS="$(read_section NetworkNamespace)"
# Read interfaces name if it is not set
[ -n "$INT" ] || INT="$(read_section InterfaceIn)"
[ -n "$OUT" ] || OUT="$(read_section InterfaceOut)"
# Read resolve.conf
[ -n "$RESOLVE" ] || RESOLVE="$(read_section Resolve)"
# Read the type
TYPE="$(read_section Type)"
fi
[ -n "$NS" ] || fatal "Please set network namespace name"
MAXNS="$(find /var/run/netns/ -maxdepth 1 -type f -name "runns_*" | wc -l)"
NS="runns_$NS"
# Check that we have correct type
[ -n "${TYPE:-}" ] || TYPE=$TYPE_DEF
case "$TYPE" in
openvpn)
VPN="$(read_section VPN)"
[ -n "$VPN" ] || fatal "Type is $TYPE but VPN is not found"
;;
bin)
BIN="$(read_section BIN)"
[ -n "$BIN" ] || fatal "Type is $TYPE but BIN is not found"
;;
esac
# Set IPv4 third octet
IP4C="${MAXNS:-0}"
# Set default name of interfaces in the case if they did not set yet
[ -n "$INT" ] || INT="eth0"
[ -n "$OUT" ] || OUT="${NS}d"
# Output setup information
cat <<EOF
Using following options:
- Network namespace: $NS
- Network interface: $OUT
- IPv4 address for ${NS}d: 172.24.${IP4C}.1/24
- resolv.conf: ${RESOLVE:-using default}
EOF
# Check that network interface is exists
ip link show "$INT" > /dev/null 2>&1 || (echo "Interface $INT does not exists!"; exit 1)
# Add network namespace and interfaces
ip netns add "$NS"
ip link add "$OUT" type veth peer name "${NS}r"
ip link set "${NS}r" netns "$NS"
echo "Network namespace created"
# Set IP address and up interface in the default network namespace
ip addr add "172.24.${IP4C}.1/24" dev "$OUT"
ip link set "$OUT" up
echo "Interface $OUT is up"
# Setup interface in another network namespace
ip netns exec "$NS" ip link set "${NS}r" name eth0
ip netns exec "$NS" ip addr add "172.24.${IP4C}.2/24" dev eth0
ip netns exec "$NS" ip link set eth0 up
ip netns exec "$NS" ip route add default via "172.24.${IP4C}.1"
echo "Interface ${NS}r in ${NS} is up and ready"
# Enable IPv4 forward
echo "1" > /proc/sys/net/ipv4/ip_forward
# Add NAT rule
iptables -t nat -A POSTROUTING -s 172.24.${IP4C}.0/24 -o "$INT" -j MASQUERADE
echo "NAT rule is ready"
# Setup resolv.conf for this network namespace
if [ -n "${RESOLVE-}" ]
then
[ -d "/etc/netns/$NS" ] || mkdir -p "/etc/netns/$NS"
[ ! -f "$RESOLVE" ] || cp "$RESOLVE" "/etc/netns/$NS"
fi
# ACCEPT FORWARD
iptables -A FORWARD -i $INT -o $OUT -j ACCEPT
iptables -A FORWARD -o $INT -i $OUT -j ACCEPT
# Launch commands in the new network namespace
case "$TYPE" in
openvpn)
ip netns exec "$NS" openvpn --daemon "openvpn-$NS" --config "$arg"
;;
bin)
[ -x "$BIN" ] || fatal "$BIN is not executable"
ip netns exec "$NS" "$BIN"
esac