2 ###############################################################################
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2012 IPFire Network Development Team #
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. #
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. #
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/>. #
20 ###############################################################################
22 # High-level function which will create a ruleset for the current firewall
23 # configuration and load it into the kernel.
24 function firewall_start
() {
32 while [ $# -gt 0 ]; do
38 error
"Unrecognized argument: ${1}"
46 log INFO
"Test mode enabled."
47 log INFO
"The firewall ruleset will not be loaded."
52 # Initialize an empty iptables ruleset.
53 iptables_init
"${protocol}" "DROP"
56 firewall_tcp_state_flags
"${protocol}"
57 firewall_custom_chains
"${protocol}"
58 firewall_connection_tracking
"${protocol}"
59 firewall_tcp_clamp_mss
"${protocol}"
61 # Add policies for every zone.
62 firewall_localhost_create_chains
"${protocol}"
65 for zone
in $
(zones_get_all
); do
66 # Create all needed chains for the zone.
67 firewall_zone_create_chains
"${protocol}" "${zone}"
69 # After the chains that are always available have been
70 # created, we will add a custom policy to every single
73 policy_zone_add
"${protocol}" "${zone}"
76 # Load the new ruleset.
78 if enabled testmode
; then
79 list_append args
"--test"
81 iptables_commit
"${protocol}" ${args}
86 function firewall_stop
() {
92 # Initialize an empty firewall ruleset
93 # with default policy ACCEPT.
94 iptables_init
"${protocol}" ACCEPT
97 ipables_load
"${protocol}"
102 function firewall_show
() {
103 local protocol
="${1}"
104 assert isset protocol
106 # Shows the ruleset that is currently loaded.
107 iptables_status
"${protocol}"
112 function firewall_panic
() {
113 local protocol
="${1}"
114 assert isset protocol
117 local admin_hosts
="$@"
119 firewall_lock_acquire
"${protocol}"
121 # Drop all communications.
122 iptables_init
"${protocol}" DROP
124 # If an admin host is provided, some administrative
125 # things will be allowed from there.
127 for admin_host
in ${admin_hosts}; do
128 iptables
"${protocol}" -A INPUT
-s "${admin_host}" -j ACCEPT
129 iptables
"${protocol}" -A OUTPUT
-d "${admin_host}" -j ACCEPT
133 iptables_commit
"${protocol}"
135 firewall_lock_release
138 function firewall_lock_acquire
() {
139 lock_acquire
${RUN_DIR}/.firewall_lock
141 # Make sure the lock is released after the firewall
142 # script has crashed or exited early.
143 trap firewall_lock_release EXIT TERM KILL
145 # Create a directory where we can put our
146 # temporary data in the most secure way as possible.
147 IPTABLES_TMPDIR
=$
(mktemp
-d)
150 function firewall_lock_release
() {
151 if isset IPTABLES_TMPDIR
; then
152 # Remove all temporary data.
153 rm -rf ${IPTABLES_TMPDIR}
155 # Reset the tempdir variable.
160 trap true EXIT TERM KILL
162 lock_release
${RUN_DIR}/.firewall_lock
165 function firewall_custom_chains
() {
166 local protocol
="${1}"
167 assert isset protocol
169 log INFO
"Creating CUSTOM* chains..."
171 # These chains are intened to be filled with
172 # rules by the user. They are processed at the very
173 # beginning so it is possible to overwrite everything.
175 iptables_chain_create
"${protocol}" CUSTOMINPUT
176 iptables
"${protocol}" -A INPUT
-j CUSTOMINPUT
178 iptables_chain_create
"${protocol}" CUSTOMFORWARD
179 iptables
"${protocol}" -A FORWARD
-j CUSTOMFORWARD
181 iptables_chain_create
"${protocol}" CUSTOMOUTPUT
182 iptables
"${protocol}" -A OUTPUT
-j CUSTOMOUTPUT
184 iptables_chain_create
"${protocol}" -t nat CUSTOMPREROUTING
185 iptables
"${protocol}" -t nat
-A PREROUTING
-j CUSTOMPREROUTING
187 iptables_chain_create
"${protocol}" -t nat CUSTOMPOSTROUTING
188 iptables
"${protocol}" -t nat
-A POSTROUTING
-j CUSTOMPOSTROUTING
190 iptables_chain_create
"${protocol}" -t nat CUSTOMOUTPUT
191 iptables
"${protocol}" -t nat
-A OUTPUT
-j CUSTOMOUTPUT
194 function firewall_tcp_state_flags
() {
195 local protocol
="${1}"
196 assert isset protocol
198 log INFO
"Creating TCP State Flags chain..."
200 iptables_chain_create
"${protocol}" BADTCP_LOG
201 iptables
"${protocol}" -A BADTCP_LOG
-p tcp
-j "$(iptables_LOG "Illegal TCP state
: ")"
202 iptables
"${protocol}" -A BADTCP_LOG
-j DROP
204 iptables_chain_create
"${protocol}" BADTCP
205 iptables
"${protocol}" -A BADTCP
-p tcp
--tcp-flags ALL NONE
-j BADTCP_LOG
206 iptables
"${protocol}" -A BADTCP
-p tcp
--tcp-flags SYN
,FIN SYN
,FIN
-j BADTCP_LOG
207 iptables
"${protocol}" -A BADTCP
-p tcp
--tcp-flags SYN
,RST SYN
,RST
-j BADTCP_LOG
208 iptables
"${protocol}" -A BADTCP
-p tcp
--tcp-flags FIN
,RST FIN
,RST
-j BADTCP_LOG
209 iptables
"${protocol}" -A BADTCP
-p tcp
--tcp-flags ACK
,FIN FIN
-j BADTCP_LOG
210 iptables
"${protocol}" -A BADTCP
-p tcp
--tcp-flags ACK
,PSH PSH
-j BADTCP_LOG
211 iptables
"${protocol}" -A BADTCP
-p tcp
--tcp-flags ACK
,URG URG
-j BADTCP_LOG
213 iptables
"${protocol}" -A INPUT
-p tcp
-j BADTCP
214 iptables
"${protocol}" -A OUTPUT
-p tcp
-j BADTCP
215 iptables
"${protocol}" -A FORWARD
-p tcp
-j BADTCP
218 function firewall_tcp_clamp_mss
() {
219 # Do nothing if this has been disabled.
220 enabled FIREWALL_CLAMP_PATH_MTU ||
return ${EXIT_OK}
222 local protocol
="${1}"
223 assert isset protocol
225 log DEBUG
"Adding rules to clamp MSS to path MTU..."
227 iptables
"${protocol}" -t mangle
-A FORWARD \
228 -p tcp
--tcp-flags SYN
,RST SYN
-j TCPMSS
--clamp-mss-to-pmtu
231 function firewall_connection_tracking
() {
232 local protocol
="${1}"
233 assert isset protocol
235 log INFO
"Creating Connection Tracking chain..."
237 iptables_chain_create
"${protocol}" CONNTRACK
238 iptables
"${protocol}" -A CONNTRACK
-m conntrack
--ctstate ESTABLISHED
,RELATED
-j ACCEPT
239 iptables
"${protocol}" -A CONNTRACK
-m conntrack
--ctstate INVALID
-j "$(iptables_LOG "INVALID packet
: ")"
240 iptables
"${protocol}" -A CONNTRACK
-m conntrack
--ctstate INVALID
-j DROP
242 iptables
"${protocol}" -A INPUT
-j CONNTRACK
243 iptables
"${protocol}" -A OUTPUT
-j CONNTRACK
244 iptables
"${protocol}" -A FORWARD
-j CONNTRACK
247 function firewall_localhost_create_chains
() {
248 local protocol
="${1}"
249 assert isset protocol
251 log DEBUG
"Creating firewall chains for localhost..."
253 # Accept everything on lo
254 iptables
"${protocol}" -A INPUT
-i lo
-j ACCEPT
255 iptables
"${protocol}" -A OUTPUT
-o lo
-j ACCEPT
258 function firewall_zone_create_chains
() {
259 local protocol
="${1}"
260 assert isset protocol
265 log DEBUG
"Creating firewall chains for zone '${zone}'."
267 local chain_prefix
="ZONE_${zone^^}"
269 # Create filter chains.
270 iptables_chain_create
"${protocol}" "${chain_prefix}_INPUT"
271 iptables
"${protocol}" -A INPUT -i ${zone} -j "${chain_prefix}_INPUT"
273 iptables_chain_create
"${protocol}" "${chain_prefix}_OUTPUT"
274 iptables
"${protocol}" -A OUTPUT -o ${zone} -j "${chain_prefix}_OUTPUT"
277 iptables_chain_create
"${protocol}" "${chain_prefix}_CUSTOM"
279 # Intrusion Prevention System.
280 iptables_chain_create
"${protocol}" "${chain_prefix}_IPS"
282 # Create a chain for each other zone.
283 # This leaves us with n^2 chains. Duh.
285 local other_zone other_chain_prefix
286 for other_zone
in $
(zones_get_all
); do
287 other_chain_prefix
="${chain_prefix}_${other_zone^^}"
288 iptables_chain_create
"${protocol}" "${other_chain_prefix}"
290 # Connect the chain with the FORWARD chain.
291 iptables
"${protocol}" -A FORWARD -i "${zone}" -o "${other_zone}" \
292 -j "${other_chain_prefix}"
294 # Handle custom rules.
295 iptables
"${protocol}" -A "${other_chain_prefix}" -j "${chain_prefix}_CUSTOM"
298 iptables
"${protocol}" -A "${other_chain_prefix}" -j "${chain_prefix}_IPS"
301 iptables_chain_create
"${protocol}" "${other_chain_prefix}_RULES"
302 iptables
"${protocol}" -A "${other_chain_prefix}" -j "${other_chain_prefix}_RULES"
305 iptables_chain_create
"${protocol}" "${other_chain_prefix}_POLICY"
306 iptables
"${protocol}" -A "${other_chain_prefix}" -j "${other_chain_prefix}_POLICY"
309 ## Create mangle chain.
310 #iptables_chain_create "${protocol}" -t mangle "${chain_prefix}"
311 #iptables "${protocol}" -t mangle -A PREROUTING -i "${zone}" -j "${chain_prefix}"
312 #iptables "${protocol}" -t mangle -A POSTROUTING -o "${zone}" -j "${chain_prefix}"
314 ## Quality of Service
315 #iptables_chain_create "${protocol}" -t mangle "${chain_prefix}_QOS_INC"
316 #iptables "${protocol}" -t mangle -A "${chain_prefix}" -i "${zone}" -j "${chain_prefix}_QOS_INC"
317 #iptables_chain_create "${protocol}" -t mangle "${chain_prefix}_QOS_OUT"
318 #iptables "${protocol}" -t mangle -A "${chain_prefix}" -o "${zone}" -j "${chain_prefix}_QOS_OUT"
321 iptables_chain_create
"${protocol}" -t nat
"${chain_prefix}"
322 iptables
"${protocol}" -t nat -A PREROUTING -i "${zone}" -j "${chain_prefix}"
323 iptables
"${protocol}" -t nat -A POSTROUTING -o "${zone}" -j "${chain_prefix}"
325 # Network Address Translation
326 iptables_chain_create
"${protocol}" -t nat
"${chain_prefix}_DNAT"
327 iptables
"${protocol}" -t nat -A PREROUTING -i "${zone}" -j "${chain_prefix}_DNAT"
328 iptables_chain_create
"${protocol}" -t nat
"${chain_prefix}_SNAT"
329 iptables
"${protocol}" -t nat -A POSTROUTING -o "${zone}" -j "${chain_prefix}_SNAT"
332 iptables_chain_create
"${protocol}" -t nat
"${chain_prefix}_UPNP"
333 iptables
"${protocol}" -t nat -A "${chain_prefix}" -j "${chain_prefix}_UPNP"
338 function firewall_parse_rules
() {
343 # End if no rule file exists.
344 [ -r "${file}" ] ||
return ${EXIT_OK}
348 local ${FIREWALL_RULES_CONFIG_PARAMS}
350 while read -r line
; do
352 [ -n "${line}" ] ||
continue
354 # Skip commented lines.
355 [ "${line:0:1}" = "#" ] && continue
358 _firewall_parse_rule_line
${line}
359 if [ $?
-ne ${EXIT_OK} ]; then
360 log WARNING
"Skipping invalid line: ${line}"
366 # Source IP address/net.
368 list_append cmd
"-s ${src}"
371 # Destination IP address/net.
373 list_append cmd
"-d ${dst}"
378 list_append cmd
"-p ${proto}"
380 if list_match
${proto} ${FIREWALL_PROTOCOLS_SUPPORTING_PORTS}; then
382 list_append cmd
"--sport ${sport}"
386 list_append cmd
"--dport ${dport}"
391 # Always append the action.
392 list_append cmd
"-j ${action}"
399 function _firewall_parse_rule_line
() {
403 for arg
in ${FIREWALL_RULES_CONFIG_PARAMS}; do
408 while read -r arg
; do
409 key
=$
(cli_get_key
${arg})
411 if ! listmatch
"${key}" ${FIREWALL_RULES_CONFIG_PARAMS}; then
412 log WARNING
"Unrecognized argument: ${arg}"
416 val
=$
(cli_get_val
${arg})
417 assign
"${key}" "${val}"
418 done <<< "$(args $@)"
420 # action must always be set.
421 if ! isset action
; then
422 log WARNING
"'action' is not set: $@"
426 for arg
in src dst
; do
427 isset
${arg} ||
continue
429 # Check for valid IP addresses.
430 if ! ip_is_valid
${!arg}; then
431 log WARNING
"Invalid IP address for '${arg}=${!arg}': $@"
440 if ! list_match
"${proto}" ${FIREWALL_SUPPORTED_PROTOCOLS}; then
441 log WARNING
"Unsupported protocol type 'proto=${proto}': $@"
446 for arg
in sport dport
; do
447 isset
${arg} ||
continue
449 # Check if port is valid.
450 if ! isinteger
${arg}; then
451 log WARNING
"Invalid port '${arg}=${!arg}': $@"