1#!/bin/sh
2#
3# Copyright (C) 2015 Red Hat, Inc.
4# Copyright (C) 2016 Lance LeFlore
5#
6# This file is part of ocserv.
7#
8# This file is free software; you can redistribute it and/or modify it
9# under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# This file is distributed in the hope that it will be useful, but
14# WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16# General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this file; if not, write to the Free Software Foundation,
20# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21
22# Input is from environment:
23#
24# OCSERV_RESTRICT_TO_ROUTES: If set to '1' the user should be restricted
25#                    to accessing the OCSERV_ROUTES and prevented from accessing
26#                    OCSERV_NO_ROUTES.
27#
28# OCSERV_ROUTES:     A space separated list of IPv4 and IPv6 routes to
29#                    which the user has access. If empty or not set the
30#                    user has default route.
31#
32# OCSERV_ROUTES4:    A version of OCSERV_ROUTES with IPv4 addresses only.
33# OCSERV_ROUTES6:    A version of OCSERV_ROUTES with IPv6 addresses only.
34#
35# OCSERV_NO_ROUTES:  A space separated list of IPv4 and IPv6 routes to
36#                    which the user has NO access.
37#
38# OCSERV_NO_ROUTES4: A version of OCSERV_NO_ROUTES with IPv4 addresses only.
39# OCSERV_NO_ROUTES6: A version of OCSERV_NO_ROUTES with IPv6 addresses only.
40#
41# OCSERV_DNS:        A space-separated list of DNS servers the user has access to.
42# OCSERV_DNS4:       A version of OCSERV_DNS with IPv4 addresses only.
43# OCSERV_DNS6:       A version of OCSERV_DNS with IPv6 addresses only.
44#
45# OCSERV_DENY_PORTS: A space-separated list of port types and ports that the user
46#                    should be denied access to. An example of the format is:
47#                    "tcp 443 udp 312 sctp 999 icmp all esp all icmpv6 all"
48#
49# OCSERV_ALLOW_PORTS: A space-separated list of port types and ports that the user
50#                     should be granted access to. If set the user must be denied access
51#                     to any other ports. An example of the format is:
52#                     "tcp 443 udp 312 sctp 999 icmp all esp all icmpv6 all"
53
54PATH=/sbin:/usr/sbin:$PATH
55
56COMMENT="ocserv-fw"
57FORWARD_CHAIN="FORWARD"
58SEC_FORWARD_CHAIN="FORWARD-${COMMENT}-${DEVICE}"
59
60if test "$1" = "--removeall";then
61	eval "$(iptables -S | grep "comment ${COMMENT}" | sed -e 's/-A/-D/g' -e 's/^-/iptables -/g')"
62	eval "$(ip6tables -S | grep "comment ${COMMENT}" | sed -e 's/-A/-D/g' -e 's/^-/ip6tables -/g')"
63
64	#delete chains
65	eval "$(iptables -S | grep "INPUT-${COMMENT}" | sed -e 's/-N/-X/g' -e 's/^-/iptables -/g')"
66	eval "$(ip6tables -S | grep "INPUT-${COMMENT}" | sed -e 's/-N/-X/g' -e 's/^-/ip6tables -/g')"
67	exit 0
68fi
69
70execute_next_script() {
71	if test -n "${OCSERV_NEXT_SCRIPT}";then
72		TMP_SCRIPT="${OCSERV_NEXT_SCRIPT}"
73		unset OCSERV_NEXT_SCRIPT
74		/bin/sh "${TMP_SCRIPT}"
75	fi
76}
77
78clean_all_rules() {
79	eval "$(iptables -S | grep "comment ${COMMENT}" | grep -e "-[io] ${DEVICE}" | sed -e 's/-A/-D/g' -e 's/^-/iptables -/g')" 2>/dev/null
80	eval "$(ip6tables -S | grep "comment ${COMMENT}" | grep -e "-[io] ${DEVICE}" | sed -e 's/-A/-D/g' -e 's/^-/ip6tables -/g')" 2>/dev/null
81	iptables -X ${SEC_FORWARD_CHAIN} 2>/dev/null
82	ip6tables -X ${SEC_FORWARD_CHAIN} 2>/dev/null
83}
84
85if test "${REASON}" = "connect";then
86	#clear any leftover rules for this device
87	clean_all_rules
88	# assume FORWARD policy is REJECT - allow return traffic
89	# may also need to turn kernel knob to allow forwarding
90	iptables -I ${FORWARD_CHAIN} \
91		-o ${DEVICE} \
92		-m conntrack --ctstate RELATED,ESTABLISHED \
93		-j ACCEPT -m comment --comment "${COMMENT}"
94	else
95	if test "${REASON}" = "disconnect";then
96		clean_all_rules
97		set -e
98		execute_next_script
99		exit 0
100	else
101		logger -t ocserv-fw "unknown reason ${REASON}"
102		exit 1
103	fi
104fi
105
106set -e
107
108allow_dns() {
109	"$1" -A ${FORWARD_CHAIN} -i ${DEVICE} -p udp -d "$2" --dport 53 -j ACCEPT --match comment --comment "${COMMENT}"
110
111	"$1" -A ${FORWARD_CHAIN} -i ${DEVICE} -p tcp -d "$2" --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT --match comment --comment "${COMMENT}"
112}
113
114allow_dns4() {
115	allow_dns iptables "$1"
116}
117
118allow_dns6() {
119	allow_dns ip6tables "$1"
120}
121
122allow_route() {
123	"$1" -A ${SEC_FORWARD_CHAIN} -i ${DEVICE} -d "$2" -j ACCEPT --match comment --comment "${COMMENT}"
124}
125
126allow_route4() {
127	allow_route iptables "$1"
128}
129
130allow_route6() {
131	allow_route ip6tables "$1"
132}
133
134disallow_route() {
135	"$1" -A ${SEC_FORWARD_CHAIN} -i ${DEVICE} -d "$2" -j REJECT --match comment --comment "${COMMENT}"
136}
137
138disallow_route4() {
139	disallow_route iptables "$1"
140}
141
142disallow_route6() {
143	disallow_route ip6tables "$1"
144}
145
146disallow_all() {
147	iptables -A ${FORWARD_CHAIN} -i ${DEVICE} -j REJECT --match comment --comment "${COMMENT}"
148	ip6tables -A ${FORWARD_CHAIN} -i ${DEVICE} -j REJECT --match comment --comment "${COMMENT}"
149}
150
151allow_all() {
152	iptables -A ${FORWARD_CHAIN} -i ${DEVICE} -j ACCEPT --match comment --comment "${COMMENT}"
153	ip6tables -A ${FORWARD_CHAIN} -i ${DEVICE} -j ACCEPT --match comment --comment "${COMMENT}"
154}
155
156allow_port() {
157	proto=$1
158	port=$2
159
160	case "$proto" in
161		icmp)
162			iptables -A FORWARD -i ${DEVICE} -p $proto -j ${SEC_FORWARD_CHAIN} --match comment --comment "${COMMENT}"
163			;;
164		icmpv6)
165			ip6tables -A FORWARD -i ${DEVICE} -p $proto -j ${SEC_FORWARD_CHAIN} --match comment --comment "${COMMENT}"
166			;;
167		*)
168			iptables -A FORWARD -i ${DEVICE} -p $proto --dport $port -j ${SEC_FORWARD_CHAIN} --match comment --comment "${COMMENT}"
169			ip6tables -A FORWARD -i ${DEVICE} -p $proto --dport $port -j ${SEC_FORWARD_CHAIN} --match comment --comment "${COMMENT}"
170			;;
171	esac
172}
173
174deny_port() {
175	proto=$1
176	port=$2
177
178	case "$proto" in
179		icmp)
180			iptables -A ${FORWARD_CHAIN} -i ${DEVICE} -p $proto -j REJECT --match comment --comment "${COMMENT}"
181			;;
182		icmpv6)
183			ip6tables -A ${FORWARD_CHAIN} -i ${DEVICE} -p $proto -j REJECT --match comment --comment "${COMMENT}"
184			;;
185		*)
186			iptables -A ${FORWARD_CHAIN} -i ${DEVICE} -p $proto --dport $port -j REJECT --match comment --comment "${COMMENT}"
187			ip6tables -A ${FORWARD_CHAIN} -i ${DEVICE} -p $proto --dport $port -j REJECT --match comment --comment "${COMMENT}"
188			;;
189	esac
190}
191
192disallow_all_ports() {
193	iptables -A FORWARD -i ${DEVICE} -j REJECT --match comment --comment "${COMMENT}"
194	ip6tables -A FORWARD -i ${DEVICE} -j REJECT --match comment --comment "${COMMENT}"
195}
196
197# Allow DNS lookups
198for i in $OCSERV_DNS4;do
199	allow_dns4 $i
200done
201
202# block or allow routes
203for i in $OCSERV_DNS6;do
204	allow_dns6 $i
205done
206
207# create the chain
208FORWARD_CHAIN="${SEC_FORWARD_CHAIN}"
209iptables -N "${FORWARD_CHAIN}"
210ip6tables -N "${FORWARD_CHAIN}"
211
212# block ports - if needed
213if test -n "${OCSERV_DENY_PORTS}";then
214	set ${OCSERV_DENY_PORTS}
215	while test $# -gt 1; do
216		proto=$1
217		port=$2
218
219		deny_port $proto $port
220		if test $# -gt 1;then
221			shift 2
222		else
223			break
224		fi
225	done
226else
227	if test -n "${OCSERV_ALLOW_PORTS}";then
228		set ${OCSERV_ALLOW_PORTS}
229		while test $# -gt 1; do
230			proto=$1
231			port=$2
232
233			allow_port $proto $port
234			if test $# -gt 1;then
235				shift 2
236			else
237				break
238			fi
239		done
240		disallow_all_ports
241	fi
242fi
243
244if test "${OCSERV_RESTRICT_TO_ROUTES}" = "1";then
245	for i in $OCSERV_NO_ROUTES4;do
246		disallow_route4 $i
247	done
248
249	for i in $OCSERV_NO_ROUTES6;do
250		disallow_route6 $i
251	done
252
253	if test -n "$OCSERV_ROUTES";then
254
255		for i in $OCSERV_ROUTES4;do
256			allow_route4 $i
257		done
258
259		for i in $OCSERV_ROUTES6;do
260			allow_route6 $i
261		done
262
263		# no default route, don't allow anything except the configured routes
264		disallow_all
265	else
266		allow_all
267	fi
268else
269	# we still need to allow traffic through if OCSERV_RESTRICT_TO_ROUTES is not true
270	iptables -A ${SEC_FORWARD_CHAIN} -i ${DEVICE} -j ACCEPT -m comment --comment "${COMMENT}"
271fi
272
273# send traffic to the route chain
274iptables  -A FORWARD -i ${DEVICE} -j ${SEC_FORWARD_CHAIN} --match comment --comment "${COMMENT}"
275ip6tables -A FORWARD -i ${DEVICE} -j ${SEC_FORWARD_CHAIN} --match comment --comment "${COMMENT}"
276
277execute_next_script
278
279exit 0
280