]> git.ipfire.org Git - people/ms/network.git/blame - functions.iptables
firewall: Create a basic layout of the firewall chains.
[people/ms/network.git] / functions.iptables
CommitLineData
98146c00
MT
1#!/bin/bash
2###############################################################################
3# #
4# IPFire.org - A linux based firewall #
5# Copyright (C) 2012 IPFire Network Development Team #
6# #
7# This program is free software: you can redistribute it and/or modify #
8# it under the terms of the GNU General Public License as published by #
9# the Free Software Foundation, either version 3 of the License, or #
10# (at your option) any later version. #
11# #
12# This program is distributed in the hope that it will be useful, #
13# but WITHOUT ANY WARRANTY; without even the implied warranty of #
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15# GNU General Public License for more details. #
16# #
17# You should have received a copy of the GNU General Public License #
18# along with this program. If not, see <http://www.gnu.org/licenses/>. #
19# #
20###############################################################################
21
22function iptables() {
23 local arg
24 local args
afb7d704
MT
25 local table="filter"
26 local src dst
27
28 # Default is both protocols.
29 local proto="6 4"
98146c00
MT
30
31 # Check if the directory where we put our rules in is set and
32 # exists.
33 assert isset IPTABLES_TMPDIR
34 assert [ -d "${IPTABLES_TMPDIR}" ]
35
98146c00
MT
36 # Parsing arguments
37 while [ $# -gt 0 ]; do
38 case "${1}" in
afb7d704
MT
39 # Select IPv4 protocol.
40 -4)
41 proto="4"
42 shift
43 ;;
44 # Select IPv6 protocol.
45 -6)
46 proto="6"
47 shift
48 ;;
98146c00
MT
49 -t)
50 table=${2}
51 shift 2
52 ;;
53 -A)
54 args="${args} -A ${2^^}"
55 shift 2
56 ;;
57 *)
58 args="${args} ${1}"
afb7d704
MT
59
60 # Save some values for further processing.
61 case "${1}" in
62 -s)
63 src="${2}"
64 ;;
65 -d)
66 dst="${2}"
67 ;;
68 esac
98146c00
MT
69 shift
70 ;;
71 esac
72 done
73
afb7d704
MT
74 # Check that the nat table is not used for IPv6.
75 if isoneof 6 ${proto}; then
76 assert [ "${table}" != "nat" ]
77 fi
78
79 # Detect the version of the IP protocol.
80 local src_proto
81 isset src && src_proto=$(ip_detect_protocol ${src})
82
83 local dst_proto
84 isset dst && dst_proto=$(ip_detect_protocol ${dst})
85
86 # Check that the source and destinations are not
87 # using different versions of the IP protocol.
88 if isset src_proto && isset dst_proto; then
89 assert [ "${src_proto}" = "${dst_proto}" ]
90 fi
91
92 local rulesfile
93 local p
94 for p in ${proto}; do
95 case "${p}" in
96 6)
97 listmatch ipv4 ${src_proto} ${dst_proto} \
98 && continue
99 ;;
100 4)
101 listmatch ipv6 ${src_proto} ${dst_proto} \
102 && continue
103 ;;
104 esac
105
106 rulesfile=$(iptables_rulesfile ipv${p} ${table})
107 print "${args:1:${#args}}" >> ${rulesfile}
108 done
109}
110
111# Calls the binary iptables command.
112function _iptables() {
113 local iptables_cmd=$(which iptables)
114 assert isset iptables_cmd
115
116 ${iptables_cmd} $@
117}
118
119function iptables_status() {
120 _iptables -L -n -v
121}
122
123# Returns which tables exist for the given protocol.
124function iptables_tables() {
125 local proto=${1}
ab2eb246 126 assert isset proto
afb7d704
MT
127
128 case "${proto}" in
129 ipv6)
ab2eb246 130 print "filter mangle"
afb7d704
MT
131 ;;
132 ipv4)
ab2eb246 133 print "filter mangle nat"
afb7d704
MT
134 ;;
135 *)
136 return ${EXIT_ERROR}
137 ;;
138 esac
139
afb7d704
MT
140 return ${EXIT_OK}
141}
142
143function iptables_rulesfile() {
144 local proto=${1}
145 proto=${proto/ipv/}
146
147 local chain=${2}
148 [ -z "${chain}" ] && chain="ruleset"
149
150 print "${IPTABLES_TMPDIR}/${chain}${proto}"
98146c00
MT
151}
152
153function iptables_init() {
154 local policy=${1}
afb7d704 155 assert isset policy
98146c00 156
afb7d704 157 # Create filter table and initialize chains.
98146c00 158 iptables "* filter"
afb7d704
MT
159 iptables_chain_create -t filter INPUT --policy=${policy}
160 iptables_chain_create -t filter OUTPUT --policy=${policy}
161 iptables_chain_create -t filter FORWARD --policy=${policy}
98146c00 162
afb7d704 163 # Create mangle table initialize chains.
98146c00 164 iptables -t mangle "* mangle"
afb7d704
MT
165 iptables_chain_create -t mangle PREROUTING --policy=ACCEPT
166 iptables_chain_create -t mangle INPUT --policy=ACCEPT
167 iptables_chain_create -t mangle OUTPUT --policy=ACCEPT
168 iptables_chain_create -t mangle FORWARD --policy=ACCEPT
169 iptables_chain_create -t mangle POSTROUTING --policy=ACCEPT
98146c00 170
afb7d704
MT
171 # Add NAT table for IPv4.
172 iptables -4 -t nat "* nat"
173 iptables_chain_create -4 -t nat PREROUTING --policy=ACCEPT
174 iptables_chain_create -4 -t nat OUTPUT --policy=ACCEPT
175 iptables_chain_create -4 -t nat POSTROUTING --policy=ACCEPT
98146c00
MT
176}
177
afb7d704
MT
178# Load the created ruleset into the kernel.
179function iptables_load() {
180 # If first argument is present and true, we
181 # run in test mode.
182 local test="${1}"
98146c00 183
afb7d704 184 local rulesfile
98146c00 185
afb7d704
MT
186 # Concat the table rulesets into one big file.
187 local proto
188 for proto in 6 4; do
189 rulesfile=$(iptables_rulesfile ipv${proto})
16ac9775 190 assert isset rulesfile
afb7d704
MT
191
192 local table
193 local tablefile
194 for table in $(iptables_tables ipv${proto}); do
195 tablefile=$(iptables_rulesfile ipv${proto} ${table})
16ac9775
MT
196
197 fread ${tablefile}
198
199 # Add the COMMIT statement for every table.
200 if [ -s "${tablefile}" ]; then
201 print "COMMIT"
202 fi
afb7d704 203 done > ${rulesfile}
16ac9775
MT
204
205 assert [ -s "${rulesfile}" ]
afb7d704
MT
206 done
207
208 local error="false"
209 local ret
210
211 # First check if everything is correctly formatted.
212 for proto in 6 4; do
213 rulesfile=$(iptables_rulesfile ipv${proto})
214
215 _iptables_load ipv${proto} ${rulesfile} true
216 if [ $? -ne ${EXIT_OK} ]; then
217 log CRITICAL "Ruleset load check failed for IPv${proto}"
218 error="true"
219 fi
220 done
221
222 # Check if there has been an error in the load check.
223 if enabled error; then
224 iptables_dump CRITICAL
225
226 log CRITICAL "New firewall rules could not be loaded."
227 return ${EXIT_ERROR}
228 fi
229
230 # Dump the data, we are going to load.
231 iptables_dump
232
233 # If we are running in test mode, we are done here.
234 enabled test && return ${EXIT_OK}
235
236 # If we got until here, everything is fine to load the ruleset.
237 for proto in 6 4; do
238 rulesfile=$(iptables_rulesfile ipv${proto})
239
240 _iptables_load ipv${proto} ${rulesfile}
241 done
242 return ${EXIT_OK}
243}
244
afb7d704
MT
245function _iptables_load() {
246 local proto=${1}
247 local file=${2}
248 local testmode=${3}
98146c00 249
afb7d704
MT
250 local command
251 case "${proto}" in
252 ipv6)
253 command="ip6tables-restore"
254 ;;
255 ipv4)
256 command="iptables-restore"
257 ;;
258 esac
259 assert isset command
260
261 if enabled testmode; then
262 command="${command} --test"
263 fi
264
265 local time_started=$(date -u "+%s")
266
267 cmd ${command} < ${file}
268 local ret=$?
269
270 case "${ret}" in
271 ${EXIT_OK})
272 local time_finished=$(date -u "+%s")
273 time_finished=$(( ${time_finished} - ${time_started} ))
274 log INFO \
275 "Successfully loaded new firewall ruleset for IPv${proto/ipv/} in ${time_finished}s!"
276 ;;
277 *)
278 if ! enabled testmode; then
279 log CRITICAL "Error loading firewall ruleset for IPv${proto/ipv/}!"
280 fi
281 ;;
282 esac
283
284 return ${ret}
285}
286
287function iptables_dump() {
288 local log_facility=${1-DEBUG}
289
290 # Here is nothing to do, if we are not running in
291 # debug mode.
292 enabled DEBUG || return ${EXIT_OK}
98146c00 293
afb7d704
MT
294 local rulesfile
295 local counter
98146c00 296 local line
98146c00 297
afb7d704
MT
298 local proto
299 for proto in 6 4; do
300 rulesfile=$(iptables_rulesfile ipv${proto})
301 [ -e "${rulesfile}" ] || continue
302
303 log ${log_facility} "Firewall ruleset for IPv${proto}:"
304
305 counter=1
ed26fecf
MT
306 while read -r line; do
307 printf -v line "%4d | %s" "${counter}" "${line}"
afb7d704
MT
308 log ${log_facility} "${line}"
309
310 counter=$(( $counter + 1 ))
311 done < ${rulesfile}
312 done
98146c00
MT
313}
314
315function iptables_chain_create() {
afb7d704
MT
316 local chain
317 local table="filter"
318 local policy="-"
319 local proto
98146c00 320 local args
afb7d704
MT
321 while [ $# -gt 0 ]; do
322 case "${1}" in
323 -6|-4)
324 proto=${1}
325 ;;
326 -t)
327 table=${2}
328 shift
329 ;;
330 --policy=*)
331 policy=$(cli_get_val ${1})
332 ;;
333 *)
334 chain=${1}
335 ;;
336 esac
337 shift
338 done
339
340 assert isset chain
341 assert isset table
342 assert isoneof policy ACCEPT DROP "-"
98146c00 343
afb7d704 344 iptables ${proto} -t ${table} ":${chain} ${policy} [0:0]"
98146c00
MT
345}
346
347function iptables_LOG() {
348 local prefix=${1}
afb7d704 349 local ret
98146c00 350
afb7d704
MT
351 case "${FIREWALL_LOG_METHOD}" in
352 nflog)
353 ret="NFLOG --nflog-threshold ${FIREWALL_NFLOG_THRESHOLD}"
354 isset prefix && ret="${ret} --nflog-prefix \"$prefix\""
355 ;;
356 syslog)
357 ret="LOG"
358 isset prefix && ret="${ret} --log-prefix \"$prefix\""
359 ;;
360 esac
361
362 print "${ret}"
98146c00
MT
363}
364
365function iptables_protocol() {
366 local PROTO
367 PROTO=$1
368 for proto in tcp udp esp ah; do
369 if [ "$PROTO" = "$proto" ]; then
370 echo "-p $PROTO"
371 break
372 fi
373 done
374}
375
376IPTABLES_PORT=0
377IPTABLES_MULTIPORT=1
378IPTABLES_PORTRANGE=2
379
380function _iptables_port_range() {
381 grep -q ":" <<< $@
382}
383
384function _iptables_port_multiport() {
385 grep -q "," <<< $@
386}
387
388function _iptables_port() {
389 if _iptables_port_range "$@"; then
390 echo $IPTABLES_PORTRANGE
391 elif _iptables_port_multiport "$@"; then
392 echo $IPTABLES_MULTIPORT
393 else
394 echo $IPTABLES_PORT
395 fi
396}
397
398function iptables_source_port() {
399 [ -z "$@" ] && return
400 local type
401 type=$(_iptables_port $@)
402 if [ "$type" = "$IPTABLES_MULTIPORT" ]; then
403 echo "-m multiport --source-ports $@"
404 else
405 echo "--sport $@"
406 fi
407}
408
409function iptables_destination_port() {
410 [ -z "$@" ] && return
411 local type
412 type=$(_iptables_port $@)
413 if [ "$type" = "$IPTABLES_MULTIPORT" ]; then
414 echo "-m multiport --destination-ports $@"
415 else
416 echo "--dport $@"
417 fi
418}