-
Notifications
You must be signed in to change notification settings - Fork 5
/
eos-firewall-localonly
executable file
·171 lines (142 loc) · 4.78 KB
/
eos-firewall-localonly
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
#!/bin/bash -e
# eos-firewall-localonly - simple firewall to restrict host to local networks
#
# Copyright (C) 2017 Endless Mobile, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# this script sets up "localonly" iptables/ip6tables chains which are connected
# to the OUTPUT chain, so that the host can reach typical local network and
# local multicast address ranges, a couple of internet services (DNS and NTP)
# but are otherwise left offline. a NetworkManager dispatcher hook adds
# any other local network routes and looks up the IP addresses for the Endless
# metrics servers too.
LOCALONLY_CHAIN="localonly"
METRICS_CHAIN="${LOCALONLY_CHAIN}-metrics"
# deep madness lies in blocking any localhost traffic
allowed_interfaces="lo"
# allowed v4 ranges:
# - the three usual ranges for private IPs (these should always be handled
# by eos-firewall-localonly-nm, this is just belt & braces)
# - the "link-local autoconf" address range
# - link-local multicast for mDNS etc
# - local broadcast (all 1s) for DHCP etc
allowed_v4_networks="10.0.0.0/8 172.16.0.0/12 169.254.0.0/16 192.168.0.0/16 224.0.0.0/24 255.255.255.255"
# allowed v6 ranges (IPv6 is so much more elegant!):
# - unique local addresses
# - link-local addresses
# - link-local multicast ranges
allowed_v6_networks="fc00::/7 fe80::/10 ff02::/16"
# these are the services where we want to talk *outside* the local networks
# so eg DHCP is not here: it should be permitted by the allowed networks
allowed_internet_services="ntp domain"
# add the localonly chain to OUTPUT
enable() {
for cmd in iptables ip6tables; do
${cmd} -F OUTPUT
${cmd} -A OUTPUT -j "${LOCALONLY_CHAIN}"
${cmd} -P OUTPUT DROP
done
}
# remove the localonly chain from OUTPUT
disable() {
for cmd in iptables ip6tables; do
${cmd} -P OUTPUT ACCEPT
${cmd} -F OUTPUT
done
}
# initialise the localonly chain
setup() {
for cmd in iptables ip6tables; do
${cmd} -N ${LOCALONLY_CHAIN}
for i in ${allowed_interfaces}; do
${cmd} -A ${LOCALONLY_CHAIN} -o ${i} -j ACCEPT
done
for p in tcp udp; do
for s in ${allowed_internet_services}; do
${cmd} -A ${LOCALONLY_CHAIN} -p ${p} --dport ${s} -j ACCEPT
done
done
done
for n in ${allowed_v4_networks}; do
iptables -A ${LOCALONLY_CHAIN} -d ${n} -j ACCEPT
done
for n in ${allowed_v6_networks}; do
ip6tables -A ${LOCALONLY_CHAIN} -d ${n} -j ACCEPT
done
# log anything we're about to DROP, but reset TCP connections for faster app feedback
for cmd in iptables ip6tables; do
${cmd} -A ${LOCALONLY_CHAIN} -m limit --limit 1/min -j LOG --log-prefix "eos-firewall-localonly: "
${cmd} -A ${LOCALONLY_CHAIN} -p tcp -j REJECT --reject-with tcp-reset
${cmd} -A ${LOCALONLY_CHAIN} -j RETURN
done
}
remove_localonly_chain() {
local chain="${1}"
for cmd in iptables ip6tables; do
if ${cmd} -n -L "${chain}" >/dev/null 2>&1; then
# ignore failure in case chain is not present
${cmd} -D "${LOCALONLY_CHAIN}" -j "${chain}" >/dev/null 2>&1 || true
${cmd} -F "${chain}"
${cmd} -X "${chain}"
fi
done
}
# clear and remove any localonly chains
reset() {
# disable first because otherwise we can't erase our chains
disable
for iface in $(find /sys/class/net -maxdepth 1 -type l -printf "%f\n"); do
remove_localonly_chain "${LOCALONLY_CHAIN}-${iface}"
done
remove_localonly_chain "${METRICS_CHAIN}"
# this will try and remove the localonly chain from itself, but the failure
# is ignored so this saves code
remove_localonly_chain "${LOCALONLY_CHAIN}"
}
usage() {
cat <<EOF
Usage:
$0 ACTION
Set up a simple firewall which permits the system to only access IPv4 and
IPv6 resources on the local network.
Actions:
start Set up the firewall
stop Remove the firewall
test Set up the firewall without making it active, so that the localonly
iptables chain exists and the NetworkManager dispatcher is active
EOF
}
case "$1" in
"start")
reset
setup
enable
echo "$0 started"
;;
"stop")
reset
echo "$0 stopped"
;;
"test")
reset
setup
echo "$0 started in test mode"
;;
*)
usage
exit 1
;;
esac
exit 0