]> git.ipfire.org Git - people/stevee/network.git/blame - functions.iptables
aiccu: Add documentation.
[people/stevee/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})
2239db91
MT
107 assert isset rulesfile
108
afb7d704
MT
109 print "${args:1:${#args}}" >> ${rulesfile}
110 done
111}
112
113# Calls the binary iptables command.
114function _iptables() {
115 local iptables_cmd=$(which iptables)
116 assert isset iptables_cmd
117
2239db91 118 cmd ${iptables_cmd} $@
afb7d704
MT
119}
120
121function iptables_status() {
122 _iptables -L -n -v
123}
124
125# Returns which tables exist for the given protocol.
126function iptables_tables() {
127 local proto=${1}
ab2eb246 128 assert isset proto
afb7d704
MT
129
130 case "${proto}" in
131 ipv6)
ab2eb246 132 print "filter mangle"
afb7d704
MT
133 ;;
134 ipv4)
ab2eb246 135 print "filter mangle nat"
afb7d704
MT
136 ;;
137 *)
138 return ${EXIT_ERROR}
139 ;;
140 esac
141
afb7d704
MT
142 return ${EXIT_OK}
143}
144
145function iptables_rulesfile() {
146 local proto=${1}
147 proto=${proto/ipv/}
148
149 local chain=${2}
150 [ -z "${chain}" ] && chain="ruleset"
151
152 print "${IPTABLES_TMPDIR}/${chain}${proto}"
98146c00
MT
153}
154
155function iptables_init() {
156 local policy=${1}
afb7d704 157 assert isset policy
98146c00 158
afb7d704 159 # Create filter table and initialize chains.
98146c00 160 iptables "* filter"
afb7d704
MT
161 iptables_chain_create -t filter INPUT --policy=${policy}
162 iptables_chain_create -t filter OUTPUT --policy=${policy}
163 iptables_chain_create -t filter FORWARD --policy=${policy}
98146c00 164
afb7d704 165 # Create mangle table initialize chains.
98146c00 166 iptables -t mangle "* mangle"
afb7d704
MT
167 iptables_chain_create -t mangle PREROUTING --policy=ACCEPT
168 iptables_chain_create -t mangle INPUT --policy=ACCEPT
169 iptables_chain_create -t mangle OUTPUT --policy=ACCEPT
170 iptables_chain_create -t mangle FORWARD --policy=ACCEPT
171 iptables_chain_create -t mangle POSTROUTING --policy=ACCEPT
98146c00 172
afb7d704
MT
173 # Add NAT table for IPv4.
174 iptables -4 -t nat "* nat"
175 iptables_chain_create -4 -t nat PREROUTING --policy=ACCEPT
176 iptables_chain_create -4 -t nat OUTPUT --policy=ACCEPT
177 iptables_chain_create -4 -t nat POSTROUTING --policy=ACCEPT
98146c00
MT
178}
179
afb7d704
MT
180# Load the created ruleset into the kernel.
181function iptables_load() {
182 # If first argument is present and true, we
183 # run in test mode.
184 local test="${1}"
98146c00 185
afb7d704 186 local rulesfile
98146c00 187
afb7d704
MT
188 # Concat the table rulesets into one big file.
189 local proto
190 for proto in 6 4; do
191 rulesfile=$(iptables_rulesfile ipv${proto})
16ac9775 192 assert isset rulesfile
afb7d704
MT
193
194 local table
195 local tablefile
196 for table in $(iptables_tables ipv${proto}); do
197 tablefile=$(iptables_rulesfile ipv${proto} ${table})
16ac9775
MT
198
199 fread ${tablefile}
200
201 # Add the COMMIT statement for every table.
202 if [ -s "${tablefile}" ]; then
203 print "COMMIT"
204 fi
afb7d704 205 done > ${rulesfile}
16ac9775
MT
206
207 assert [ -s "${rulesfile}" ]
afb7d704
MT
208 done
209
210 local error="false"
211 local ret
212
213 # First check if everything is correctly formatted.
214 for proto in 6 4; do
215 rulesfile=$(iptables_rulesfile ipv${proto})
2239db91 216 assert isset rulesfile
afb7d704
MT
217
218 _iptables_load ipv${proto} ${rulesfile} true
219 if [ $? -ne ${EXIT_OK} ]; then
220 log CRITICAL "Ruleset load check failed for IPv${proto}"
221 error="true"
222 fi
223 done
224
225 # Check if there has been an error in the load check.
226 if enabled error; then
227 iptables_dump CRITICAL
228
229 log CRITICAL "New firewall rules could not be loaded."
230 return ${EXIT_ERROR}
231 fi
232
233 # Dump the data, we are going to load.
234 iptables_dump
235
236 # If we are running in test mode, we are done here.
237 enabled test && return ${EXIT_OK}
238
239 # If we got until here, everything is fine to load the ruleset.
240 for proto in 6 4; do
241 rulesfile=$(iptables_rulesfile ipv${proto})
242
243 _iptables_load ipv${proto} ${rulesfile}
244 done
245 return ${EXIT_OK}
246}
247
afb7d704
MT
248function _iptables_load() {
249 local proto=${1}
250 local file=${2}
251 local testmode=${3}
98146c00 252
afb7d704
MT
253 local command
254 case "${proto}" in
255 ipv6)
256 command="ip6tables-restore"
257 ;;
258 ipv4)
259 command="iptables-restore"
260 ;;
261 esac
262 assert isset command
263
264 if enabled testmode; then
265 command="${command} --test"
266 fi
267
268 local time_started=$(date -u "+%s")
269
270 cmd ${command} < ${file}
271 local ret=$?
272
273 case "${ret}" in
274 ${EXIT_OK})
275 local time_finished=$(date -u "+%s")
276 time_finished=$(( ${time_finished} - ${time_started} ))
277 log INFO \
278 "Successfully loaded new firewall ruleset for IPv${proto/ipv/} in ${time_finished}s!"
279 ;;
280 *)
281 if ! enabled testmode; then
282 log CRITICAL "Error loading firewall ruleset for IPv${proto/ipv/}!"
283 fi
284 ;;
285 esac
286
287 return ${ret}
288}
289
290function iptables_dump() {
291 local log_facility=${1-DEBUG}
292
293 # Here is nothing to do, if we are not running in
294 # debug mode.
295 enabled DEBUG || return ${EXIT_OK}
98146c00 296
afb7d704
MT
297 local rulesfile
298 local counter
98146c00 299 local line
98146c00 300
afb7d704
MT
301 local proto
302 for proto in 6 4; do
303 rulesfile=$(iptables_rulesfile ipv${proto})
304 [ -e "${rulesfile}" ] || continue
305
306 log ${log_facility} "Firewall ruleset for IPv${proto}:"
307
308 counter=1
ed26fecf
MT
309 while read -r line; do
310 printf -v line "%4d | %s" "${counter}" "${line}"
afb7d704
MT
311 log ${log_facility} "${line}"
312
313 counter=$(( $counter + 1 ))
314 done < ${rulesfile}
315 done
98146c00
MT
316}
317
318function iptables_chain_create() {
afb7d704
MT
319 local chain
320 local table="filter"
321 local policy="-"
322 local proto
98146c00 323 local args
afb7d704
MT
324 while [ $# -gt 0 ]; do
325 case "${1}" in
326 -6|-4)
327 proto=${1}
328 ;;
329 -t)
330 table=${2}
331 shift
332 ;;
333 --policy=*)
334 policy=$(cli_get_val ${1})
335 ;;
336 *)
337 chain=${1}
338 ;;
339 esac
340 shift
341 done
342
343 assert isset chain
344 assert isset table
345 assert isoneof policy ACCEPT DROP "-"
98146c00 346
afb7d704 347 iptables ${proto} -t ${table} ":${chain} ${policy} [0:0]"
98146c00
MT
348}
349
350function iptables_LOG() {
351 local prefix=${1}
afb7d704 352 local ret
98146c00 353
afb7d704
MT
354 case "${FIREWALL_LOG_METHOD}" in
355 nflog)
356 ret="NFLOG --nflog-threshold ${FIREWALL_NFLOG_THRESHOLD}"
357 isset prefix && ret="${ret} --nflog-prefix \"$prefix\""
358 ;;
359 syslog)
360 ret="LOG"
361 isset prefix && ret="${ret} --log-prefix \"$prefix\""
362 ;;
363 esac
364
365 print "${ret}"
98146c00
MT
366}
367
368function iptables_protocol() {
369 local PROTO
370 PROTO=$1
371 for proto in tcp udp esp ah; do
372 if [ "$PROTO" = "$proto" ]; then
373 echo "-p $PROTO"
374 break
375 fi
376 done
377}
378
379IPTABLES_PORT=0
380IPTABLES_MULTIPORT=1
381IPTABLES_PORTRANGE=2
382
383function _iptables_port_range() {
384 grep -q ":" <<< $@
385}
386
387function _iptables_port_multiport() {
388 grep -q "," <<< $@
389}
390
391function _iptables_port() {
392 if _iptables_port_range "$@"; then
393 echo $IPTABLES_PORTRANGE
394 elif _iptables_port_multiport "$@"; then
395 echo $IPTABLES_MULTIPORT
396 else
397 echo $IPTABLES_PORT
398 fi
399}
400
401function iptables_source_port() {
402 [ -z "$@" ] && return
403 local type
404 type=$(_iptables_port $@)
405 if [ "$type" = "$IPTABLES_MULTIPORT" ]; then
406 echo "-m multiport --source-ports $@"
407 else
408 echo "--sport $@"
409 fi
410}
411
412function iptables_destination_port() {
413 [ -z "$@" ] && return
414 local type
415 type=$(_iptables_port $@)
416 if [ "$type" = "$IPTABLES_MULTIPORT" ]; then
417 echo "-m multiport --destination-ports $@"
418 else
419 echo "--dport $@"
420 fi
421}