]> git.ipfire.org Git - people/stevee/network.git/blame - src/functions/functions.iptables
Remove the function keyword which is a bashism
[people/stevee/network.git] / src / functions / functions.iptables
CommitLineData
98146c00
MT
1#!/bin/bash
2###############################################################################
3# #
4# IPFire.org - A linux based firewall #
fe52c5e0 5# Copyright (C) 2012-2013 IPFire Network Development Team #
98146c00
MT
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
fe52c5e0
MT
22IPTABLES_TABLES="filter mangle nat"
23
1c6a4e30 24iptables() {
fe52c5e0
MT
25 local protocol="${1}"
26 assert isset protocol
27 shift
28
29 # Rules go to the filter table by default
afb7d704 30 local table="filter"
afb7d704 31
fe52c5e0
MT
32 # Argument list
33 local args
98146c00 34
fe52c5e0
MT
35 # Cached arguments
36 local src dst
98146c00 37
98146c00
MT
38 # Parsing arguments
39 while [ $# -gt 0 ]; do
40 case "${1}" in
fe52c5e0 41 # Filter to which table this rule should go.
98146c00 42 -t)
fe52c5e0 43 table="${2}"
98146c00 44 shift 2
fe52c5e0
MT
45
46 assert isoneof table ${IPTABLES_TABLES}
98146c00 47 ;;
9e65113f
MT
48
49 # Automatically convert ICMP to ICMPv6 for IPv6
50 --protocol|-p)
51 local proto="${2}"
52
53 if [ "${protocol}" = "ipv6" -a "${proto}" = "icmp" ]; then
54 proto="icmpv6"
55 fi
56
57 list_append args "${1} ${proto}"
58 shift 2
59 ;;
98146c00 60 *)
fe52c5e0 61 list_append args "${1}"
afb7d704
MT
62
63 # Save some values for further processing.
64 case "${1}" in
65 -s)
66 src="${2}"
67 ;;
68 -d)
69 dst="${2}"
70 ;;
71 esac
98146c00
MT
72 shift
73 ;;
74 esac
75 done
76
fe52c5e0 77 assert isset action
afb7d704 78
fe52c5e0 79 # Check if given IP addresses or networks match the protocol version.
afb7d704 80 local src_proto
fe52c5e0
MT
81 if isset src; then
82 src_proto="$(ip_detect_protocol ${src})"
83
84 assert [ "${protocol}" = "${src_proto}" ]
85 fi
afb7d704
MT
86
87 local dst_proto
fe52c5e0
MT
88 if isset dst; then
89 dst_proto="$(ip_detect_protocol ${dst})"
afb7d704 90
fe52c5e0 91 assert [ "${protocol}" = "${dst_proto}" ]
afb7d704
MT
92 fi
93
fe52c5e0
MT
94 # Check if the directory where we put our rules in is set and
95 # exists.
96 assert isset IPTABLES_TMPDIR
97 local rulesfile="${IPTABLES_TMPDIR}/${protocol}-${table}"
98
99 print "${args}" >> "${rulesfile}"
100 assert_check_retval $?
101}
102
1c6a4e30 103iptables_chain_create() {
fe52c5e0
MT
104 local protocol="${1}"
105 assert isset protocol
106 shift
107
108 local chain
109 local table="filter"
110 local policy="-"
111
112 while [ $# -gt 0 ]; do
113 case "${1}" in
114 -t)
115 table="${2}"
116 shift
117 ;;
118 --policy=*)
119 policy="$(cli_get_val ${1})"
afb7d704 120 ;;
fe52c5e0
MT
121 -*)
122 log WARNING "Unrecognized argument: ${1}"
123 ;;
124 *)
125 chain=${1}
afb7d704
MT
126 ;;
127 esac
fe52c5e0
MT
128 shift
129 done
afb7d704 130
fe52c5e0
MT
131 assert isset chain
132 assert isset table
133 assert isoneof policy ACCEPT DROP "-"
2239db91 134
fe52c5e0 135 iptables "${protocol}" -t "${table}" ":${chain} ${policy} [0:0]"
afb7d704
MT
136}
137
138# Calls the binary iptables command.
1c6a4e30 139_iptables() {
fe52c5e0
MT
140 local protocol="${1}"
141 assert isset protocol
142 shift
afb7d704 143
fe52c5e0
MT
144 local cmd
145 case "${protocol}" in
afb7d704 146 ipv6)
fe52c5e0 147 cmd="ip6tables"
afb7d704
MT
148 ;;
149 ipv4)
fe52c5e0 150 cmd="iptables"
afb7d704
MT
151 ;;
152 esac
fe52c5e0
MT
153 assert isset cmd
154 cmd="$(which ${cmd})"
155
156 cmd "${cmd}" "$@"
157 return $?
158}
159
1c6a4e30 160iptables_status() {
fe52c5e0
MT
161 local protocol="${1}"
162 assert isset protocol
163
164 local table
165 for table in ${IPTABLES_TABLES}; do
166 print "${protocol} - ${table}:"
167 _iptables "${protocol}" -t "${table}" -L -n -v
168 print
169 done
afb7d704 170
afb7d704
MT
171 return ${EXIT_OK}
172}
173
1c6a4e30 174iptables_rulesfile() {
afb7d704
MT
175 local proto=${1}
176 proto=${proto/ipv/}
177
178 local chain=${2}
179 [ -z "${chain}" ] && chain="ruleset"
180
181 print "${IPTABLES_TMPDIR}/${chain}${proto}"
98146c00
MT
182}
183
1c6a4e30 184iptables_init() {
fe52c5e0
MT
185 local protocol="${1}"
186 assert isset protocol
187
188 local policy="${2}"
afb7d704 189 assert isset policy
98146c00 190
afb7d704 191 # Create filter table and initialize chains.
fe52c5e0
MT
192 iptables "${protocol}" "* filter"
193 iptables_chain_create "${protocol}" -t filter INPUT --policy="${policy}"
194 iptables_chain_create "${protocol}" -t filter OUTPUT --policy="${policy}"
195 iptables_chain_create "${protocol}" -t filter FORWARD --policy="${policy}"
196
197 # Create mangle table and initialize chains.
198 iptables "${protocol}" -t mangle "* mangle"
199 iptables_chain_create "${protocol}" -t mangle PREROUTING --policy="ACCEPT"
200 iptables_chain_create "${protocol}" -t mangle INPUT --policy="ACCEPT"
201 iptables_chain_create "${protocol}" -t mangle OUTPUT --policy="ACCEPT"
202 iptables_chain_create "${protocol}" -t mangle FORWARD --policy="ACCEPT"
203 iptables_chain_create "${protocol}" -t mangle POSTROUTING --policy="ACCEPT"
204
205 # Create NAT table and initialize chains.
206 iptables "${protocol}" -t nat "* nat"
207 iptables_chain_create "${protocol}" -t nat PREROUTING --policy="ACCEPT"
208 iptables_chain_create "${protocol}" -t nat OUTPUT --policy="ACCEPT"
209 iptables_chain_create "${protocol}" -t nat POSTROUTING --policy="ACCEPT"
98146c00
MT
210}
211
afb7d704 212# Load the created ruleset into the kernel.
1c6a4e30 213iptables_commit () {
fe52c5e0
MT
214 local protocol="${1}"
215 assert isset protocol
216 shift
98146c00 217
fe52c5e0 218 local testmode="false"
98146c00 219
fe52c5e0
MT
220 while [ $# -gt 0 ]; do
221 case "${1}" in
222 --test)
223 testmode="true"
224 ;;
225 *)
226 log WARNING "Unrecognized argument: ${1}"
227 ;;
228 esac
229 shift
230 done
16ac9775 231
fe52c5e0
MT
232 # Concat all rules into one big file.
233 local rulesfile="${IPTABLES_TMPDIR}/ruleset"
234 _iptables_commit_cat_rulesfile "${protocol}" "${rulesfile}"
235
236 # Run the following loop twice:
237 # 1st: Check if the ruleset can be loaded
238 # 2nd: If not in test mode, actually load the ruleset into the kernel
239 local load_cmd="--test"
240 local ret=0
241
242 local i
243 for i in 0 1; do
244 _iptables_commit_load_rulesfile "${protocol}" "${rulesfile}" "${load_cmd}"
245 ret=$?
246
247 case "${i},${ret}" in
248 0,${EXIT_OK})
249 iptables_dump "${protocol}" "${rulesfile}" --log-facility="DEBUG"
250 log DEBUG "Ruleset load check succeeded (${protocol})"
251 ;;
16ac9775 252
fe52c5e0
MT
253 # Loading rules has failed (test)
254 0,*)
255 iptables_dump "${protocol}" "${rulesfile}" --log-facility="CRITICAL"
256 log CRITICAL "Ruleset load check failed (${protocol} - ${ret})"
257 return ${ret}
258 ;;
16ac9775 259
fe52c5e0
MT
260 1,${EXIT_OK})
261 log DEBUG "Ruleset successfully loaded (${protocol})"
262 return ${EXIT_OK}
263 ;;
afb7d704 264
fe52c5e0
MT
265 1,*)
266 log CRITICAL "Ruleset loading failed (${protocol})"
267 return ${ret}
268 ;;
269 esac
afb7d704 270
fe52c5e0
MT
271 # Skip the second loop iteration, if we are running in test mode.
272 enabled testmode && break
afb7d704 273
fe52c5e0 274 load_cmd=""
afb7d704
MT
275 done
276
fe52c5e0
MT
277 return ${EXIT_OK}
278}
afb7d704 279
1c6a4e30 280_iptables_commit_cat_rulesfile() {
fe52c5e0
MT
281 local protocol="${1}"
282 assert isset protocol
afb7d704 283
fe52c5e0
MT
284 local rulesfile="${2}"
285 assert isset rulesfile
afb7d704 286
fe52c5e0
MT
287 local table
288 local file
289 for table in ${IPTABLES_TABLES}; do
290 file="${IPTABLES_TMPDIR}/${protocol}-${table}"
afb7d704 291
fe52c5e0 292 fread "${file}"
afb7d704 293
fe52c5e0
MT
294 # Add the COMMIT statement for every table.
295 print "COMMIT"
296 done > "${rulesfile}"
297
298 assert [ -s "${rulesfile}" ]
afb7d704
MT
299}
300
1c6a4e30 301_iptables_commit_load_rulesfile() {
fe52c5e0
MT
302 local protocol="${1}"
303 assert isset protocol
304
305 local rulesfile="${2}"
306 assert isset rulesfile
307 shift 2
308
309 local testmode="false"
310 while [ $# -gt 0 ]; do
311 case "${1}" in
312 --test)
313 testmode="true"
314 ;;
315 esac
316 shift
317 done
98146c00 318
fe52c5e0
MT
319 local iptables_cmd
320 case "${protocol}" in
afb7d704 321 ipv6)
fe52c5e0 322 iptables_cmd="ip6tables-restore"
afb7d704
MT
323 ;;
324 ipv4)
fe52c5e0 325 iptables_cmd="iptables-restore"
afb7d704
MT
326 ;;
327 esac
fe52c5e0 328 assert isset iptables_cmd
afb7d704
MT
329
330 if enabled testmode; then
fe52c5e0 331 list_append iptables_cmd "--test"
afb7d704
MT
332 fi
333
fe52c5e0
MT
334 # Save when importing the rules has started.
335 local time_started="$(timestamp)"
afb7d704 336
fe52c5e0 337 cmd "${iptables_cmd}" < "${rulesfile}"
afb7d704
MT
338 local ret=$?
339
340 case "${ret}" in
341 ${EXIT_OK})
fe52c5e0
MT
342 local time_finished="$(timestamp)"
343 time_finished="$(( ${time_finished} - ${time_started} ))"
344
345 enabled testmode && return ${EXIT_OK}
346
347 log INFO "Successfully loaded new firewall ruleset for ${protocol} in ${time_finished}s!"
afb7d704
MT
348 ;;
349 *)
350 if ! enabled testmode; then
fe52c5e0 351 log CRITICAL "Error loading firewall ruleset for ${protocol}!"
afb7d704
MT
352 fi
353 ;;
354 esac
355
356 return ${ret}
357}
358
1c6a4e30 359iptables_dump() {
fe52c5e0
MT
360 local protocol="${1}"
361 assert isset protocol
afb7d704 362
fe52c5e0
MT
363 local rulesfile="${2}"
364 assert isset rulesfile
365 shift 2
98146c00 366
fe52c5e0 367 local log_facility="INFO"
98146c00 368
afb7d704
MT
369 while [ $# -gt 0 ]; do
370 case "${1}" in
fe52c5e0
MT
371 --log-facility=*)
372 log_facility="$(cli_get_val ${1})"
afb7d704
MT
373 ;;
374 *)
fe52c5e0 375 log WARNING "Unrecognized argument: ${1}"
afb7d704
MT
376 ;;
377 esac
378 shift
379 done
380
fe52c5e0
MT
381 # Say what we are going to do:
382 log "${log_facility}" "Firewall ruleset for ${protocol}:"
383
384 local counter="0"
385 local line
386 while read -r line; do
387 counter="$(( ${counter} + 1 ))"
98146c00 388
fe52c5e0
MT
389 printf -v line "%4d | %s" "${counter}" "${line}"
390 log "${log_facility}" "${line}"
391 done < "${rulesfile}"
98146c00
MT
392}
393
1c6a4e30 394iptables_LOG() {
4320067c 395 local prefix="${1}"
afb7d704 396 local ret
98146c00 397
4320067c
MT
398 # Automatically append a colon and whitespace.
399 case "${prefix}" in
400 # Everything is fine.
401 "*: ") ;;
402
403 # Ends with colon, add whitespace only.
404 "*:")
405 prefix="${prefix} "
406 ;;
407
408 # Append both.
409 *)
410 prefix="${prefix}: "
411 ;;
412 esac
413
afb7d704
MT
414 case "${FIREWALL_LOG_METHOD}" in
415 nflog)
416 ret="NFLOG --nflog-threshold ${FIREWALL_NFLOG_THRESHOLD}"
417 isset prefix && ret="${ret} --nflog-prefix \"$prefix\""
418 ;;
419 syslog)
420 ret="LOG"
421 isset prefix && ret="${ret} --log-prefix \"$prefix\""
422 ;;
423 esac
424
425 print "${ret}"
98146c00
MT
426}
427
1c6a4e30 428iptables_protocol() {
98146c00
MT
429 local PROTO
430 PROTO=$1
431 for proto in tcp udp esp ah; do
432 if [ "$PROTO" = "$proto" ]; then
433 echo "-p $PROTO"
434 break
435 fi
436 done
437}
438
439IPTABLES_PORT=0
440IPTABLES_MULTIPORT=1
441IPTABLES_PORTRANGE=2
442
1c6a4e30 443_iptables_port_range() {
98146c00
MT
444 grep -q ":" <<< $@
445}
446
1c6a4e30 447_iptables_port_multiport() {
98146c00
MT
448 grep -q "," <<< $@
449}
450
1c6a4e30 451_iptables_port() {
98146c00
MT
452 if _iptables_port_range "$@"; then
453 echo $IPTABLES_PORTRANGE
454 elif _iptables_port_multiport "$@"; then
455 echo $IPTABLES_MULTIPORT
456 else
457 echo $IPTABLES_PORT
458 fi
459}
460
1c6a4e30 461iptables_source_port() {
98146c00
MT
462 [ -z "$@" ] && return
463 local type
464 type=$(_iptables_port $@)
465 if [ "$type" = "$IPTABLES_MULTIPORT" ]; then
466 echo "-m multiport --source-ports $@"
467 else
468 echo "--sport $@"
469 fi
470}
471
1c6a4e30 472iptables_destination_port() {
98146c00
MT
473 [ -z "$@" ] && return
474 local type
475 type=$(_iptables_port $@)
476 if [ "$type" = "$IPTABLES_MULTIPORT" ]; then
477 echo "-m multiport --destination-ports $@"
478 else
479 echo "--dport $@"
480 fi
481}