forked from oofnikj/docker-openwrt
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun.sh
More file actions
executable file
·210 lines (187 loc) · 5.21 KB
/
run.sh
File metadata and controls
executable file
·210 lines (187 loc) · 5.21 KB
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#!/usr/bin/env bash
# set -x
function _usage() {
echo "Could not find config file."
echo "Usage: $0 [/path/to/openwrt.conf]"
exit 1
}
SCRIPT_DIR=$(cd $(dirname $0) && pwd )
DEFAULT_CONFIG_FILE=$SCRIPT_DIR/openwrt.conf
CONFIG_FILE=${1:-$DEFAULT_CONFIG_FILE}
source $CONFIG_FILE 2>/dev/null || { _usage; exit 1; }
function _nmcli() {
type nmcli >/dev/null 2>&1
if [[ $? -eq 0 ]]; then
echo "* setting interface '$WIFI_IFACE' to unmanaged"
nmcli dev set $WIFI_IFACE managed no
nmcli radio wifi on
fi
}
function _get_phy_from_dev() {
test $WIFI_ENABLED = 'true' || return
test -z $WIFI_PHY || return
if [[ -f /sys/class/net/$WIFI_IFACE/phy80211/name ]]; then
WIFI_PHY=$(cat /sys/class/net/$WIFI_IFACE/phy80211/name 2>/dev/null)
echo "* got '$WIFI_PHY' for device '$WIFI_IFACE'"
else
echo "$WIFI_IFACE is not a valid phy80211 device"
exit 1
fi
}
function _cleanup() {
echo -e "\n* cleaning up..."
echo "* stopping container"
docker stop $CONTAINER >/dev/null
echo "* cleaning up netns symlink"
sudo rm -rf /var/run/netns/$CONTAINER
echo "* removing host $LAN_DRIVER interface"
if [[ $LAN_DRIVER != "bridge" ]] ; then
sudo ip link del dev $LAN_IFACE
elif [[ $LAN_PARENT =~ \. ]] ; then
sudo ip link del dev $LAN_PARENT
fi
echo -ne "* finished"
}
function _gen_config() {
echo "* generating network config"
set -a
_get_phy_from_dev
source $CONFIG_FILE
for file in etc/config/*.tpl; do
envsubst <${file} >${file%.tpl}
docker cp ${file%.tpl} $CONTAINER:/${file%.tpl}
done
set +a
}
function _init_network() {
echo "* setting up docker network"
local LAN_ARGS
case $LAN_DRIVER in
bridge)
LAN_ARGS=""
;;
macvlan)
LAN_ARGS="-o parent=$LAN_PARENT"
;;
ipvlan)
LAN_ARGS="-o parent=$LAN_PARENT -o ipvlan_mode=l2"
;;
*)
echo "invalid choice for LAN network driver"
exit 1
;;
esac
docker network create --driver $LAN_DRIVER \
$LAN_ARGS \
--subnet $LAN_SUBNET \
$LAN_NAME || exit 1
docker network create --driver macvlan \
-o parent=$WAN_PARENT \
$WAN_NAME || exit 1
}
function _set_hairpin() {
test $WIFI_HAIRPIN = 'true' || return
echo -n "* set hairpin mode on interface '$1'"
for i in {1..10}; do
echo -n '.'
sudo ip netns exec $CONTAINER ip link set $WIFI_IFACE type bridge_slave hairpin on 2>/dev/null && { echo 'ok'; break; }
sleep 3
done
if [[ $i -ge 10 ]]; then
echo -e "\ncouldn't set hairpin mode, wifi clients will probably be unable to talk to each other"
fi
}
function _create_or_start_container() {
if ! docker inspect $IMAGE_TAG >/dev/null 2>&1; then
echo "no image '$IMAGE_TAG' found, did you forget to run 'make build'?"
exit 1
elif docker inspect $CONTAINER >/dev/null 2>&1; then
echo "* starting container '$CONTAINER'"
docker start $CONTAINER || exit 1
else
_init_network
echo "* creating container $CONTAINER"
docker create \
--network $LAN_NAME \
--cap-add NET_ADMIN \
--cap-add NET_RAW \
--hostname openwrt \
--dns 127.0.0.1 \
--ip $LAN_ADDR \
--sysctl net.netfilter.nf_conntrack_acct=1 \
--sysctl net.ipv6.conf.all.disable_ipv6=0 \
--sysctl net.ipv6.conf.all.forwarding=1 \
--name $CONTAINER $IMAGE_TAG >/dev/null
docker network connect $WAN_NAME $CONTAINER
_gen_config
docker start $CONTAINER
fi
}
function _reload_fw() {
echo "* reloading firewall rules"
docker exec -i $CONTAINER sh -c '
for iptables in iptables ip6tables; do
for table in filter nat mangle; do
$iptables -t $table -F
done
done
/sbin/fw3 -q restart'
}
function _prepare_wifi() {
test $WIFI_ENABLED = 'true' || return
test -z $WIFI_IFACE && _usage
_get_phy_from_dev
_nmcli
echo "* moving device $WIFI_PHY to docker network namespace"
sudo iw phy "$WIFI_PHY" set netns $pid
_set_hairpin $WIFI_IFACE
}
function _prepare_lan() {
case $LAN_DRIVER in
macvlan)
echo "* setting up host $LAN_DRIVER interface"
LAN_IFACE=macvlan0
sudo ip link add $LAN_IFACE link $LAN_PARENT type $LAN_DRIVER mode bridge
sudo ip link set $LAN_IFACE up
sudo ip route add $LAN_SUBNET dev $LAN_IFACE
;;
ipvlan)
echo "* setting up host $LAN_DRIVER interface"
LAN_IFACE=ipvlan0
sudo ip link add $LAN_IFACE link $LAN_PARENT type $LAN_DRIVER mode l2
sudo ip link set $LAN_IFACE up
sudo ip route add $LAN_SUBNET dev $LAN_IFACE
;;
bridge)
LAN_ID=$(docker network inspect $LAN_NAME -f "{{.Id}}")
LAN_IFACE=br-${LAN_ID:0:12}
# test if $LAN_PARENT is a VLAN of $WAN_PARENT, create it if it doesn't exist and add it to the bridge
local lan_array=(${LAN_PARENT//./ })
if [[ ${lan_array[0]} = $WAN_PARENT ]] && ! ip link show $LAN_PARENT >/dev/null 2>&1 ; then
sudo ip link add link ${lan_array[0]} name $LAN_PARENT type vlan id ${lan_array[1]}
fi
sudo ip link set $LAN_PARENT master $LAN_IFACE
;;
*)
echo "invalid network driver type, must be 'bridge' or 'macvlan'"
exit 1
;;
esac
echo "* getting address via DHCP"
sudo dhcpcd -q $LAN_IFACE
}
function main() {
cd "${SCRIPT_DIR}"
_create_or_start_container
pid=$(docker inspect -f '{{.State.Pid}}' $CONTAINER)
echo "* creating netns symlink '$CONTAINER'"
sudo mkdir -p /var/run/netns
sudo ln -sf /proc/$pid/ns/net /var/run/netns/$CONTAINER
_prepare_wifi
_prepare_lan
_reload_fw
echo "* ready"
}
main
trap "_cleanup" EXIT
tail --pid=$pid -f /dev/null