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_filter_rh0_headers
"${protocol}"
57 firewall_tcp_state_flags
"${protocol}"
58 firewall_custom_chains
"${protocol}"
59 firewall_connection_tracking
"${protocol}"
60 firewall_tcp_clamp_mss
"${protocol}"
62 # Add policies for every zone.
63 firewall_localhost_create_chains
"${protocol}"
66 for zone
in $
(zones_get_all
); do
67 # Create all needed chains for the zone.
68 firewall_zone_create_chains
"${protocol}" "${zone}"
70 # After the chains that are always available have been
71 # created, we will add a custom policy to every single
74 policy_zone_add
"${protocol}" "${zone}"
77 # Load the new ruleset.
79 if enabled testmode
; then
80 list_append args
"--test"
82 iptables_commit
"${protocol}" ${args}
87 function firewall_stop
() {
93 # Initialize an empty firewall ruleset
94 # with default policy ACCEPT.
95 iptables_init
"${protocol}" ACCEPT
98 ipables_load
"${protocol}"
100 firewall_lock_release
103 function firewall_show
() {
104 local protocol
="${1}"
105 assert isset protocol
107 # Shows the ruleset that is currently loaded.
108 iptables_status
"${protocol}"
113 function firewall_panic
() {
114 local protocol
="${1}"
115 assert isset protocol
118 local admin_hosts
="$@"
120 firewall_lock_acquire
"${protocol}"
122 # Drop all communications.
123 iptables_init
"${protocol}" DROP
125 # If an admin host is provided, some administrative
126 # things will be allowed from there.
128 for admin_host
in ${admin_hosts}; do
129 iptables
"${protocol}" -A INPUT
-s "${admin_host}" -j ACCEPT
130 iptables
"${protocol}" -A OUTPUT
-d "${admin_host}" -j ACCEPT
134 iptables_commit
"${protocol}"
136 firewall_lock_release
139 function firewall_lock_acquire
() {
140 lock_acquire
${RUN_DIR}/.firewall_lock
142 # Make sure the lock is released after the firewall
143 # script has crashed or exited early.
144 trap firewall_lock_release EXIT TERM KILL
146 # Create a directory where we can put our
147 # temporary data in the most secure way as possible.
148 IPTABLES_TMPDIR
=$
(mktemp
-d)
151 function firewall_lock_release
() {
152 if isset IPTABLES_TMPDIR
; then
153 # Remove all temporary data.
154 rm -rf ${IPTABLES_TMPDIR}
156 # Reset the tempdir variable.
161 trap true EXIT TERM KILL
163 lock_release
${RUN_DIR}/.firewall_lock
166 function firewall_custom_chains
() {
167 local protocol
="${1}"
168 assert isset protocol
170 log INFO
"Creating CUSTOM* chains..."
172 # These chains are intened to be filled with
173 # rules by the user. They are processed at the very
174 # beginning so it is possible to overwrite everything.
176 iptables_chain_create
"${protocol}" CUSTOMINPUT
177 iptables
"${protocol}" -A INPUT
-j CUSTOMINPUT
179 iptables_chain_create
"${protocol}" CUSTOMFORWARD
180 iptables
"${protocol}" -A FORWARD
-j CUSTOMFORWARD
182 iptables_chain_create
"${protocol}" CUSTOMOUTPUT
183 iptables
"${protocol}" -A OUTPUT
-j CUSTOMOUTPUT
185 iptables_chain_create
"${protocol}" -t nat CUSTOMPREROUTING
186 iptables
"${protocol}" -t nat
-A PREROUTING
-j CUSTOMPREROUTING
188 iptables_chain_create
"${protocol}" -t nat CUSTOMPOSTROUTING
189 iptables
"${protocol}" -t nat
-A POSTROUTING
-j CUSTOMPOSTROUTING
191 iptables_chain_create
"${protocol}" -t nat CUSTOMOUTPUT
192 iptables
"${protocol}" -t nat
-A OUTPUT
-j CUSTOMOUTPUT
195 function firewall_tcp_state_flags
() {
196 local protocol
="${1}"
197 assert isset protocol
199 log INFO
"Creating TCP State Flags chain..."
201 iptables_chain_create
"${protocol}" BADTCP_LOG
202 iptables
"${protocol}" -A BADTCP_LOG
-p tcp
-j "$(iptables_LOG "Illegal TCP state
: ")"
203 iptables
"${protocol}" -A BADTCP_LOG
-j DROP
205 iptables_chain_create
"${protocol}" BADTCP
206 iptables
"${protocol}" -A BADTCP
-p tcp
--tcp-flags ALL NONE
-j BADTCP_LOG
207 iptables
"${protocol}" -A BADTCP
-p tcp
--tcp-flags SYN
,FIN SYN
,FIN
-j BADTCP_LOG
208 iptables
"${protocol}" -A BADTCP
-p tcp
--tcp-flags SYN
,RST SYN
,RST
-j BADTCP_LOG
209 iptables
"${protocol}" -A BADTCP
-p tcp
--tcp-flags FIN
,RST FIN
,RST
-j BADTCP_LOG
210 iptables
"${protocol}" -A BADTCP
-p tcp
--tcp-flags ACK
,FIN FIN
-j BADTCP_LOG
211 iptables
"${protocol}" -A BADTCP
-p tcp
--tcp-flags ACK
,PSH PSH
-j BADTCP_LOG
212 iptables
"${protocol}" -A BADTCP
-p tcp
--tcp-flags ACK
,URG URG
-j BADTCP_LOG
214 iptables
"${protocol}" -A INPUT
-p tcp
-j BADTCP
215 iptables
"${protocol}" -A OUTPUT
-p tcp
-j BADTCP
216 iptables
"${protocol}" -A FORWARD
-p tcp
-j BADTCP
219 function firewall_tcp_clamp_mss
() {
220 # Do nothing if this has been disabled.
221 enabled FIREWALL_CLAMP_PATH_MTU ||
return ${EXIT_OK}
223 local protocol
="${1}"
224 assert isset protocol
226 log DEBUG
"Adding rules to clamp MSS to path MTU..."
228 iptables
"${protocol}" -t mangle
-A FORWARD \
229 -p tcp
--tcp-flags SYN
,RST SYN
-j TCPMSS
--clamp-mss-to-pmtu
232 function firewall_connection_tracking
() {
233 local protocol
="${1}"
234 assert isset protocol
236 log INFO
"Creating Connection Tracking chain..."
238 iptables_chain_create
"${protocol}" CONNTRACK
239 iptables
"${protocol}" -A CONNTRACK
-m conntrack
--ctstate ESTABLISHED
,RELATED
-j ACCEPT
240 iptables
"${protocol}" -A CONNTRACK
-m conntrack
--ctstate INVALID
-j "$(iptables_LOG "INVALID packet
: ")"
241 iptables
"${protocol}" -A CONNTRACK
-m conntrack
--ctstate INVALID
-j DROP
243 iptables
"${protocol}" -A INPUT
-j CONNTRACK
244 iptables
"${protocol}" -A OUTPUT
-j CONNTRACK
245 iptables
"${protocol}" -A FORWARD
-j CONNTRACK
248 function firewall_localhost_create_chains
() {
249 local protocol
="${1}"
250 assert isset protocol
252 log DEBUG
"Creating firewall chains for localhost..."
254 # Accept everything on lo
255 iptables
"${protocol}" -A INPUT
-i lo
-j ACCEPT
256 iptables
"${protocol}" -A OUTPUT
-o lo
-j ACCEPT
259 function firewall_filter_rh0_headers
() {
260 local protocol
="${1}"
261 assert isset protocol
264 [ "${protocol}" = "ipv6" ] ||
return ${EXIT_OK}
266 # Filter all packets that have RH0 headers
267 # http://www.ietf.org/rfc/rfc5095.txt
268 iptables_chain_create
"${protocol}" FILTER_RH0
269 iptables
"${protocol}" -A FILTER_RH0
-m rt
--rt-type 0 -j DROP
271 iptables
"${protocol}" -A INPUT
-j FILTER_RH0
272 iptables
"${protocol}" -A FORWARD
-j FILTER_RH0
273 iptables
"${protocol}" -A OUTPUT
-j FILTER_RH0
276 function firewall_zone_create_chains
() {
277 local protocol
="${1}"
278 assert isset protocol
283 log DEBUG
"Creating firewall chains for zone '${zone}'."
285 local chain_prefix
="ZONE_${zone^^}"
287 # Create filter chains.
288 iptables_chain_create
"${protocol}" "${chain_prefix}_INPUT"
289 iptables
"${protocol}" -A INPUT -i ${zone} -j "${chain_prefix}_INPUT"
291 iptables_chain_create
"${protocol}" "${chain_prefix}_OUTPUT"
292 iptables
"${protocol}" -A OUTPUT -o ${zone} -j "${chain_prefix}_OUTPUT"
295 iptables_chain_create
"${protocol}" "${chain_prefix}_CUSTOM"
297 # Intrusion Prevention System.
298 iptables_chain_create
"${protocol}" "${chain_prefix}_IPS"
300 # Create a chain for each other zone.
301 # This leaves us with n^2 chains. Duh.
303 local other_zone other_chain_prefix
304 for other_zone
in $
(zones_get_all
); do
305 other_chain_prefix
="${chain_prefix}_${other_zone^^}"
306 iptables_chain_create
"${protocol}" "${other_chain_prefix}"
308 # Connect the chain with the FORWARD chain.
309 iptables
"${protocol}" -A FORWARD -i "${zone}" -o "${other_zone}" \
310 -j "${other_chain_prefix}"
312 # Handle custom rules.
313 iptables
"${protocol}" -A "${other_chain_prefix}" -j "${chain_prefix}_CUSTOM"
316 iptables
"${protocol}" -A "${other_chain_prefix}" -j "${chain_prefix}_IPS"
319 iptables_chain_create
"${protocol}" "${other_chain_prefix}_RULES"
320 iptables
"${protocol}" -A "${other_chain_prefix}" -j "${other_chain_prefix}_RULES"
323 iptables_chain_create
"${protocol}" "${other_chain_prefix}_POLICY"
324 iptables
"${protocol}" -A "${other_chain_prefix}" -j "${other_chain_prefix}_POLICY"
327 ## Create mangle chain.
328 #iptables_chain_create "${protocol}" -t mangle "${chain_prefix}"
329 #iptables "${protocol}" -t mangle -A PREROUTING -i "${zone}" -j "${chain_prefix}"
330 #iptables "${protocol}" -t mangle -A POSTROUTING -o "${zone}" -j "${chain_prefix}"
332 ## Quality of Service
333 #iptables_chain_create "${protocol}" -t mangle "${chain_prefix}_QOS_INC"
334 #iptables "${protocol}" -t mangle -A "${chain_prefix}" -i "${zone}" -j "${chain_prefix}_QOS_INC"
335 #iptables_chain_create "${protocol}" -t mangle "${chain_prefix}_QOS_OUT"
336 #iptables "${protocol}" -t mangle -A "${chain_prefix}" -o "${zone}" -j "${chain_prefix}_QOS_OUT"
339 iptables_chain_create
"${protocol}" -t nat
"${chain_prefix}"
340 iptables
"${protocol}" -t nat -A PREROUTING -i "${zone}" -j "${chain_prefix}"
341 iptables
"${protocol}" -t nat -A POSTROUTING -o "${zone}" -j "${chain_prefix}"
343 # Network Address Translation
344 iptables_chain_create
"${protocol}" -t nat
"${chain_prefix}_DNAT"
345 iptables
"${protocol}" -t nat -A PREROUTING -i "${zone}" -j "${chain_prefix}_DNAT"
346 iptables_chain_create
"${protocol}" -t nat
"${chain_prefix}_SNAT"
347 iptables
"${protocol}" -t nat -A POSTROUTING -o "${zone}" -j "${chain_prefix}_SNAT"
350 iptables_chain_create
"${protocol}" -t nat
"${chain_prefix}_UPNP"
351 iptables
"${protocol}" -t nat -A "${chain_prefix}" -j "${chain_prefix}_UPNP"
356 function firewall_parse_rules
() {
361 # End if no rule file exists.
362 [ -r "${file}" ] ||
return ${EXIT_OK}
366 local ${FIREWALL_RULES_CONFIG_PARAMS}
368 while read -r line
; do
370 [ -n "${line}" ] ||
continue
372 # Skip commented lines.
373 [ "${line:0:1}" = "#" ] && continue
376 _firewall_parse_rule_line
${line}
377 if [ $?
-ne ${EXIT_OK} ]; then
378 log WARNING
"Skipping invalid line: ${line}"
384 # Source IP address/net.
386 list_append cmd
"-s ${src}"
389 # Destination IP address/net.
391 list_append cmd
"-d ${dst}"
396 list_append cmd
"-p ${proto}"
398 if list_match
${proto} ${FIREWALL_PROTOCOLS_SUPPORTING_PORTS}; then
400 list_append cmd
"--sport ${sport}"
404 list_append cmd
"--dport ${dport}"
409 # Always append the action.
410 list_append cmd
"-j ${action}"
417 function _firewall_parse_rule_line
() {
421 for arg
in ${FIREWALL_RULES_CONFIG_PARAMS}; do
426 while read -r arg
; do
427 key
=$
(cli_get_key
${arg})
429 if ! listmatch
"${key}" ${FIREWALL_RULES_CONFIG_PARAMS}; then
430 log WARNING
"Unrecognized argument: ${arg}"
434 val
=$
(cli_get_val
${arg})
435 assign
"${key}" "${val}"
436 done <<< "$(args $@)"
438 # action must always be set.
439 if ! isset action
; then
440 log WARNING
"'action' is not set: $@"
444 for arg
in src dst
; do
445 isset
${arg} ||
continue
447 # Check for valid IP addresses.
448 if ! ip_is_valid
${!arg}; then
449 log WARNING
"Invalid IP address for '${arg}=${!arg}': $@"
458 if ! list_match
"${proto}" ${FIREWALL_SUPPORTED_PROTOCOLS}; then
459 log WARNING
"Unsupported protocol type 'proto=${proto}': $@"
464 for arg
in sport dport
; do
465 isset
${arg} ||
continue
467 # Check if port is valid.
468 if ! isinteger
${arg}; then
469 log WARNING
"Invalid port '${arg}=${!arg}': $@"