Skip to content
This repository was archived by the owner on Mar 16, 2024. It is now read-only.

Commit 51fa5f2

Browse files
committed
Re-add support for iptables
Add package for `useradd`
1 parent 650d55f commit 51fa5f2

File tree

5 files changed

+150
-69
lines changed

5 files changed

+150
-69
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## Version 3.1.0 - 2022-06-30
4+
### Changed
5+
- `KILL_SWITCH` now requires `iptables` or `nftables` to be enabled. It defaults to `iptables`. See documentation for more information.
6+
7+
### Added
8+
- Modified OpenVPN configuration file cleanup function.
9+
310
## Version 3.0.0 - 2022-06-14
411
### Changed
512
- Refactored scripts

Dockerfile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ RUN apk add --no-cache \
44
bash \
55
bind-tools \
66
dante-server \
7-
nftables \
7+
iptables \
88
openvpn \
9+
nftables \
10+
shadow \
911
tinyproxy
1012

1113
COPY data/ /data/
1214

13-
ENV KILL_SWITCH=on
15+
ENV KILL_SWITCH=iptables
1416
ENV USE_VPN_DNS=on
1517
ENV VPN_LOG_LEVEL=3
1618

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ services:
6767
| `VPN_AUTH_SECRET` | | Docker secret that contain the credentials for accessing the VPN. |
6868
| `VPN_LOG_LEVEL` | `3` | OpenVPN logging verbosity (`1`-`11`) |
6969
| `SUBNETS` | | A list of one or more comma-separated subnets (e.g. `192.168.0.0/24,192.168.1.0/24`) to allow outside of the VPN tunnel. |
70-
| `KILL_SWITCH` | `on` | Whether or not to enable the network kill switch. |
70+
| `KILL_SWITCH` | `iptables` | Which packet filterer to use for the kill switch. This value likely depends on your underlying host. Recommended to leave default unless you have problems. Acceptable values are `iptables` and `nftables`. To disable the kill switch, set to any other value. |
7171
| `HTTP_PROXY` | | Whether or not to enable the built-in HTTP proxy server. To enable, set to any "truthy" value (see below the table). Any other value (including unset) will cause the proxy server to not run. It listens on port 8080. |
7272
| `HTTP_PROXY_USERNAME` | | Credentials for accessing the HTTP proxy. If `HTTP_PROXY_USERNAME` is specified, you should also specify `HTTP_PROXY_PASSWORD`. |
7373
| `HTTP_PROXY_PASSWORD` | | Credentials for accessing the HTTP proxy. If `HTTP_PROXY_PASSWORD` is specified, you should also specify `HTTP_PROXY_USERNAME`. |
@@ -126,6 +126,13 @@ docker run --rm -it --network=container:openvpn-client alpine wget -qO - ifconfi
126126
```
127127

128128
### Troubleshooting
129+
#### `can't initialize iptables`
130+
If you see a message like the below in your logs, try setting `KILL_SWITCH` to `nftables`:
131+
```
132+
iptables v1.8.8 (legacy): can't initialize iptables table `filter': Table does not exist (do you need to insmod?)
133+
Perhaps iptables or your kernel needs to be upgraded.
134+
```
135+
129136
#### VPN authentication
130137
Your OpenVPN configuration file may not come with authentication baked in.
131138
To provide OpenVPN the necessary credentials, create a file (any name will work, but this example will use `credentials.txt`) next to the OpenVPN configuration file with your username on the first line and your password on the second line.

data/config/socks-proxy.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
logoutput: /var/log/sockd.log
1+
logoutput: /var/log/dante.log
22
errorlog: stderr
33

44
internal: eth0 port = 1080

data/scripts/entry.sh

Lines changed: 130 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@
33
set -e
44

55

6+
cleanup() {
7+
if [[ $openvpn_child ]]; then
8+
kill SIGTERM "$openvpn_child"
9+
fi
10+
11+
sleep 0.5
12+
rm -f "$modified_config_file"
13+
echo "info: exiting"
14+
exit 0
15+
}
16+
617
is_enabled() {
718
[[ ${1,,} =~ ^(true|t|yes|y|1|on|enable|enabled)$ ]]
819
}
@@ -64,6 +75,7 @@ echo "info: original configuration file: $original_config_file"
6475

6576
# Create a new configuration file to modify so the original is left untouched.
6677
modified_config_file=vpn/openvpn.$(tr -dc A-Za-z0-9 </dev/urandom | head -c8).conf
78+
trap cleanup SIGTERM
6779

6880
echo "info: modified configuration file: $modified_config_file"
6981
grep -Ev '(^up\s|^down\s)' "$original_config_file" > "$modified_config_file"
@@ -73,76 +85,126 @@ sed -i 's/\r$//g' "$modified_config_file"
7385

7486

7587
default_gateway=$(ip -4 route | grep 'default via' | awk '{print $3}')
76-
if is_enabled "$KILL_SWITCH" ; then
77-
echo "info: kill switch is on"
78-
79-
nftables_config_file=config/nftables.conf
80-
81-
local_subnet=$(ip -4 route | grep 'scope link' | awk '{print $1}')
82-
83-
printf '%s\n' \
84-
'#!/usr/bin/nft' '' \
85-
'flush ruleset' '' \
86-
'# base ruleset' \
87-
'add table inet killswitch' '' \
88-
'add chain inet killswitch incoming { type filter hook input priority 0; policy drop; }' \
89-
'add rule inet killswitch incoming ct state established,related accept' \
90-
'add rule inet killswitch incoming iifname lo accept' '' \
91-
'add chain inet killswitch outgoing { type filter hook output priority 0; policy drop; }' \
92-
'add rule inet killswitch outgoing ct state established,related accept' \
93-
'add rule inet killswitch outgoing oifname lo accept' '' > $nftables_config_file
94-
95-
printf '%s\n' \
96-
'# allow traffic to/from the Docker subnet' \
97-
"add rule inet killswitch incoming ip saddr $local_subnet accept" \
98-
"add rule inet killswitch outgoing ip daddr $local_subnet accept" '' >> $nftables_config_file
99-
100-
if [[ $SUBNETS ]]; then
101-
printf '# allow traffic to/from the specified subnets\n' >> $nftables_config_file
102-
for subnet in ${SUBNETS//,/ }; do
103-
ip route add "$subnet" via "$default_gateway" dev eth0
104-
printf '%s\n' \
105-
"add rule inet killswitch incoming ip saddr $subnet accept" \
106-
"add rule inet killswitch outgoing ip daddr $subnet accept" '' >> $nftables_config_file
107-
done
108-
fi
10988

110-
global_port=$(grep "^port " "$modified_config_file" | awk '{print $2}')
111-
global_protocol=$(grep "^proto " "$modified_config_file" | awk '{print $2}') # {$2 = substr($2, 1, 3)} 2
112-
remotes=$(grep "^remote " "$modified_config_file" | awk '{print $2, $3, $4}')
113-
114-
printf '# allow traffic to the VPN server(s)\n' >> $nftables_config_file
115-
ip_regex='^(([1-9]?[0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))\.){3}([1-9]?[0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))$'
116-
while IFS= read -r line; do
117-
IFS=' ' read -ra remote <<< "$line"
118-
address=${remote[0]}
119-
port=${remote[1]:-${global_port:-1194}}
120-
protocol=${remote[2]:-${global_protocol:-udp}}
121-
122-
if [[ $address =~ $ip_regex ]]; then
123-
printf '%s\n' \
124-
"add rule inet killswitch outgoing oifname eth0 ip daddr $address $protocol dport $port accept" >> $nftables_config_file
125-
else
126-
for ip in $(dig -4 +short "$address"); do
89+
case "$KILL_SWITCH" in
90+
'iptables')
91+
echo "info: kill switch is using iptables"
92+
93+
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
94+
iptables -A INPUT -i lo -j ACCEPT
95+
iptables -A OUTPUT -o lo -j ACCEPT
96+
97+
local_subnet=$(ip -4 route | grep 'scope link' | awk '{print $1}')
98+
iptables -A INPUT -s "$local_subnet" -j ACCEPT
99+
iptables -A OUTPUT -d "$local_subnet" -j ACCEPT
100+
101+
if [[ $SUBNETS ]]; then
102+
for subnet in ${SUBNETS//,/ }; do
103+
ip route add "$subnet" via "$default_gateway" dev eth0
104+
iptables -A INPUT -s "$subnet" -j ACCEPT
105+
iptables -A OUTPUT -d "$subnet" -j ACCEPT
106+
done
107+
fi
108+
109+
global_port=$(grep "^port " "$modified_config_file" | awk '{print $2}')
110+
global_protocol=$(grep "^proto " "$modified_config_file" | awk '{print $2}') # {$2 = substr($2, 1, 3)} 2
111+
remotes=$(grep "^remote " "$modified_config_file" | awk '{print $2, $3, $4}')
112+
ip_regex='^(([1-9]?[0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))\.){3}([1-9]?[0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))$'
113+
while IFS= read -r line; do
114+
IFS=' ' read -ra remote <<< "$line"
115+
address=${remote[0]}
116+
port=${remote[1]:-${global_port:-1194}}
117+
protocol=${remote[2]:-${global_protocol:-udp}}
118+
119+
if [[ $address =~ $ip_regex ]]; then
120+
iptables -A OUTPUT -o eth0 -d "$address" -p "$protocol" --dport "$port" -j ACCEPT
121+
else
122+
for ip in $(dig -4 +short "$address"); do
123+
iptables -A OUTPUT -o eth0 -d "$ip" -p "$protocol" --dport "$port" -j ACCEPT
124+
printf "%s %s\n" "$ip" "$address" >> /etc/hosts
125+
done
126+
fi
127+
done <<< "$remotes"
128+
iptables -A INPUT -i tun0 -j ACCEPT
129+
iptables -A OUTPUT -o tun0 -j ACCEPT
130+
iptables -P INPUT DROP
131+
iptables -P OUTPUT DROP
132+
iptables -P FORWARD DROP
133+
iptables-save > config/iptables.conf
134+
;;
135+
136+
'nftables')
137+
echo "info: kill switch is using nftables"
138+
nftables_config_file=config/nftables.conf
139+
140+
printf '%s\n' \
141+
'#!/usr/bin/nft' '' \
142+
'flush ruleset' '' \
143+
'# base ruleset' \
144+
'add table inet killswitch' '' \
145+
'add chain inet killswitch incoming { type filter hook input priority 0; policy drop; }' \
146+
'add rule inet killswitch incoming ct state established,related accept' \
147+
'add rule inet killswitch incoming iifname lo accept' '' \
148+
'add chain inet killswitch outgoing { type filter hook output priority 0; policy drop; }' \
149+
'add rule inet killswitch outgoing ct state established,related accept' \
150+
'add rule inet killswitch outgoing oifname lo accept' '' > $nftables_config_file
151+
152+
local_subnet=$(ip -4 route | grep 'scope link' | awk '{print $1}')
153+
printf '%s\n' \
154+
'# allow traffic to/from the Docker subnet' \
155+
"add rule inet killswitch incoming ip saddr $local_subnet accept" \
156+
"add rule inet killswitch outgoing ip daddr $local_subnet accept" '' >> $nftables_config_file
157+
158+
if [[ $SUBNETS ]]; then
159+
printf '# allow traffic to/from the specified subnets\n' >> $nftables_config_file
160+
for subnet in ${SUBNETS//,/ }; do
161+
ip route add "$subnet" via "$default_gateway" dev eth0
127162
printf '%s\n' \
128-
"add rule inet killswitch outgoing oifname eth0 ip daddr $ip $protocol dport $port accept" >> $nftables_config_file
129-
printf "%s %s\n" "$ip" "$address" >> /etc/hosts
163+
"add rule inet killswitch incoming ip saddr $subnet accept" \
164+
"add rule inet killswitch outgoing ip daddr $subnet accept" '' >> $nftables_config_file
130165
done
131166
fi
132-
done <<< "$remotes"
133167

134-
printf '%s\n' \
135-
'' '# allow traffic over the VPN interface' \
136-
"add rule inet killswitch incoming iifname tun0 accept" \
137-
"add rule inet killswitch outgoing oifname tun0 accept" >> $nftables_config_file
168+
global_port=$(grep "^port " "$modified_config_file" | awk '{print $2}')
169+
global_protocol=$(grep "^proto " "$modified_config_file" | awk '{print $2}') # {$2 = substr($2, 1, 3)} 2
170+
remotes=$(grep "^remote " "$modified_config_file" | awk '{print $2, $3, $4}')
138171

139-
nft -f $nftables_config_file
140-
else
141-
echo "info: kill switch is off"
142-
for subnet in ${SUBNETS//,/ }; do
143-
ip route add "$subnet" via "$default_gateway" dev eth0
144-
done
145-
fi
172+
printf '# allow traffic to the VPN server(s)\n' >> $nftables_config_file
173+
ip_regex='^(([1-9]?[0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))\.){3}([1-9]?[0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))$'
174+
while IFS= read -r line; do
175+
IFS=' ' read -ra remote <<< "$line"
176+
address=${remote[0]}
177+
port=${remote[1]:-${global_port:-1194}}
178+
protocol=${remote[2]:-${global_protocol:-udp}}
179+
180+
if [[ $address =~ $ip_regex ]]; then
181+
printf '%s\n' \
182+
"add rule inet killswitch outgoing oifname eth0 ip daddr $address $protocol dport $port accept" >> $nftables_config_file
183+
else
184+
for ip in $(dig -4 +short "$address"); do
185+
printf '%s\n' \
186+
"add rule inet killswitch outgoing oifname eth0 ip daddr $ip $protocol dport $port accept" >> $nftables_config_file
187+
printf "%s %s\n" "$ip" "$address" >> /etc/hosts
188+
done
189+
fi
190+
done <<< "$remotes"
191+
192+
printf '%s\n' \
193+
'' '# allow traffic over the VPN interface' \
194+
"add rule inet killswitch incoming iifname tun0 accept" \
195+
"add rule inet killswitch outgoing oifname tun0 accept" >> $nftables_config_file
196+
197+
nft -f $nftables_config_file
198+
;;
199+
200+
*)
201+
echo "info: kill switch is off"
202+
for subnet in ${SUBNETS//,/ }; do
203+
ip route add "$subnet" via "$default_gateway" dev eth0
204+
done
205+
;;
206+
207+
esac
146208

147209
if is_enabled "$HTTP_PROXY" ; then
148210
scripts/run-http-proxy.sh &
@@ -174,4 +236,7 @@ if [[ $VPN_AUTH_SECRET ]]; then
174236
openvpn_args+=("--auth-user-pass" "/run/secrets/$VPN_AUTH_SECRET")
175237
fi
176238

177-
exec openvpn "${openvpn_args[@]}"
239+
openvpn "${openvpn_args[@]}" &
240+
openvpn_child=$!
241+
242+
wait $openvpn_child

0 commit comments

Comments
 (0)