]> git.ipfire.org Git - people/ms/network.git/blob - functions.iptables
Actually install the new man pages.
[people/ms/network.git] / functions.iptables
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
22 function iptables() {
23 local arg
24 local args
25 local table="filter"
26 local src dst
27
28 # Default is both protocols.
29 local proto="6 4"
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
36 # Parsing arguments
37 while [ $# -gt 0 ]; do
38 case "${1}" in
39 # Select IPv4 protocol.
40 -4)
41 proto="4"
42 shift
43 ;;
44 # Select IPv6 protocol.
45 -6)
46 proto="6"
47 shift
48 ;;
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}"
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
69 shift
70 ;;
71 esac
72 done
73
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 assert isset rulesfile
108
109 print "${args:1:${#args}}" >> ${rulesfile}
110 done
111 }
112
113 # Calls the binary iptables command.
114 function _iptables() {
115 local iptables_cmd=$(which iptables)
116 assert isset iptables_cmd
117
118 cmd ${iptables_cmd} $@
119 }
120
121 function iptables_status() {
122 _iptables -L -n -v
123 }
124
125 # Returns which tables exist for the given protocol.
126 function iptables_tables() {
127 local proto=${1}
128 assert isset proto
129
130 case "${proto}" in
131 ipv6)
132 print "filter mangle"
133 ;;
134 ipv4)
135 print "filter mangle nat"
136 ;;
137 *)
138 return ${EXIT_ERROR}
139 ;;
140 esac
141
142 return ${EXIT_OK}
143 }
144
145 function 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}"
153 }
154
155 function iptables_init() {
156 local policy=${1}
157 assert isset policy
158
159 # Create filter table and initialize chains.
160 iptables "* filter"
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}
164
165 # Create mangle table initialize chains.
166 iptables -t mangle "* mangle"
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
172
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
178 }
179
180 # Load the created ruleset into the kernel.
181 function iptables_load() {
182 # If first argument is present and true, we
183 # run in test mode.
184 local test="${1}"
185
186 local rulesfile
187
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})
192 assert isset rulesfile
193
194 local table
195 local tablefile
196 for table in $(iptables_tables ipv${proto}); do
197 tablefile=$(iptables_rulesfile ipv${proto} ${table})
198
199 fread ${tablefile}
200
201 # Add the COMMIT statement for every table.
202 if [ -s "${tablefile}" ]; then
203 print "COMMIT"
204 fi
205 done > ${rulesfile}
206
207 assert [ -s "${rulesfile}" ]
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})
216 assert isset rulesfile
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
248 function _iptables_load() {
249 local proto=${1}
250 local file=${2}
251 local testmode=${3}
252
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
290 function 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}
296
297 local rulesfile
298 local counter
299 local line
300
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
309 while read -r line; do
310 printf -v line "%4d | %s" "${counter}" "${line}"
311 log ${log_facility} "${line}"
312
313 counter=$(( $counter + 1 ))
314 done < ${rulesfile}
315 done
316 }
317
318 function iptables_chain_create() {
319 local chain
320 local table="filter"
321 local policy="-"
322 local proto
323 local args
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 "-"
346
347 iptables ${proto} -t ${table} ":${chain} ${policy} [0:0]"
348 }
349
350 function iptables_LOG() {
351 local prefix=${1}
352 local ret
353
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}"
366 }
367
368 function 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
379 IPTABLES_PORT=0
380 IPTABLES_MULTIPORT=1
381 IPTABLES_PORTRANGE=2
382
383 function _iptables_port_range() {
384 grep -q ":" <<< $@
385 }
386
387 function _iptables_port_multiport() {
388 grep -q "," <<< $@
389 }
390
391 function _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
401 function 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
412 function 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 }