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
() {
28 while [ $# -gt 0 ]; do
38 log INFO
"Test mode enabled."
39 log INFO
"The firewall ruleset will not be loaded."
44 # Initialize an empty iptables ruleset.
48 firewall_tcp_state_flags
49 firewall_custom_chains
50 firewall_connection_tracking
51 firewall_tcp_clamp_mss
53 # Add policies for every zone.
54 firewall_localhost_create_chains
57 for zone
in $
(zones_get_all
); do
58 # Create all needed chains for the zone.
59 firewall_zone_create_chains
${zone}
61 # After the chains that are always available have been
62 # created, we will add a custom policy to every single
65 policy_zone_add
${zone}
68 # Load the new ruleset.
74 function firewall_stop
() {
77 # Initialize an empty firewall ruleset
78 # with default policy ACCEPT.
87 function firewall_show
() {
88 # Shows the ruleset that is currently loaded.
94 function firewall_panic
() {
95 local admin_hosts
="$@"
99 # Drop all communications.
102 # If an admin host is provided, some administrative
103 # things will be allowed from there.
105 for admin_host
in ${admin_hosts}; do
106 iptables
-A INPUT
-s ${admin_host} -j ACCEPT
107 iptables
-A OUTPUT
-d ${admin_host} -j ACCEPT
113 firewall_lock_release
116 function firewall_lock_acquire
() {
117 lock_acquire
${RUN_DIR}/.firewall_lock
119 # Make sure the lock is released after the firewall
120 # script has crashed or exited early.
121 trap firewall_lock_release EXIT TERM KILL
123 # Create a directory where we can put our
124 # temporary data in the most secure way as possible.
125 IPTABLES_TMPDIR
=$
(mktemp
-d)
128 function firewall_lock_release
() {
129 if isset IPTABLES_TMPDIR
; then
130 # Remove all temporary data.
131 rm -rf ${IPTABLES_TMPDIR}
133 # Reset the tempdir variable.
138 trap true EXIT TERM KILL
140 lock_release
${RUN_DIR}/.firewall_lock
143 function firewall_custom_chains
() {
144 log INFO
"Creating CUSTOM* chains..."
146 # These chains are intened to be filled with
147 # rules by the user. They are processed at the very
148 # beginning so it is possible to overwrite everything.
150 iptables_chain_create CUSTOMINPUT
151 iptables
-A INPUT
-j CUSTOMINPUT
153 iptables_chain_create CUSTOMFORWARD
154 iptables
-A FORWARD
-j CUSTOMFORWARD
156 iptables_chain_create CUSTOMOUTPUT
157 iptables
-A OUTPUT
-j CUSTOMOUTPUT
159 iptables_chain_create
-4 -t nat CUSTOMPREROUTING
160 iptables
-4 -t nat
-A PREROUTING
-j CUSTOMPREROUTING
162 iptables_chain_create
-4 -t nat CUSTOMPOSTROUTING
163 iptables
-4 -t nat
-A POSTROUTING
-j CUSTOMPOSTROUTING
165 iptables_chain_create
-4 -t nat CUSTOMOUTPUT
166 iptables
-4 -t nat
-A OUTPUT
-j CUSTOMOUTPUT
169 function firewall_tcp_state_flags
() {
170 log INFO
"Creating TCP State Flags chain..."
171 iptables_chain_create BADTCP_LOG
172 iptables
-A BADTCP_LOG
-p tcp
-j $
(iptables_LOG
"Illegal TCP state: ")
173 iptables
-A BADTCP_LOG
-j DROP
175 iptables_chain_create BADTCP
176 iptables
-A BADTCP
-p tcp
--tcp-flags ALL NONE
-j BADTCP_LOG
177 iptables
-A BADTCP
-p tcp
--tcp-flags SYN
,FIN SYN
,FIN
-j BADTCP_LOG
178 iptables
-A BADTCP
-p tcp
--tcp-flags SYN
,RST SYN
,RST
-j BADTCP_LOG
179 iptables
-A BADTCP
-p tcp
--tcp-flags FIN
,RST FIN
,RST
-j BADTCP_LOG
180 iptables
-A BADTCP
-p tcp
--tcp-flags ACK
,FIN FIN
-j BADTCP_LOG
181 iptables
-A BADTCP
-p tcp
--tcp-flags ACK
,PSH PSH
-j BADTCP_LOG
182 iptables
-A BADTCP
-p tcp
--tcp-flags ACK
,URG URG
-j BADTCP_LOG
184 iptables
-A INPUT
-p tcp
-j BADTCP
185 iptables
-A OUTPUT
-p tcp
-j BADTCP
186 iptables
-A FORWARD
-p tcp
-j BADTCP
189 function firewall_tcp_clamp_mss
() {
190 # Do nothing if this has been disabled.
191 enabled FIREWALL_CLAMP_PATH_MTU ||
return ${EXIT_OK}
193 log DEBUG
"Adding rules to clamp MSS to path MTU..."
194 iptables
-t mangle
-A FORWARD \
195 -p tcp
--tcp-flags SYN
,RST SYN
-j TCPMSS
--clamp-mss-to-pmtu
198 function firewall_connection_tracking
() {
199 log INFO
"Creating Connection Tracking chain..."
200 iptables_chain_create CONNTRACK
201 iptables
-A CONNTRACK
-m state
--state ESTABLISHED
,RELATED
-j ACCEPT
202 iptables
-A CONNTRACK
-m state
--state INVALID
-j $
(iptables_LOG
"INVALID packet: ")
203 iptables
-A CONNTRACK
-m state
--state INVALID
-j DROP
205 iptables
-A INPUT
-j CONNTRACK
206 iptables
-A OUTPUT
-j CONNTRACK
207 iptables
-A FORWARD
-j CONNTRACK
210 function firewall_localhost_create_chains
() {
211 log DEBUG
"Creating firewall chains for localhost..."
213 # Accept everything on lo
214 iptables
-A INPUT
-i lo
-m state
--state NEW
-j ACCEPT
215 iptables
-A OUTPUT
-o lo
-m state
--state NEW
-j ACCEPT
218 function firewall_zone_create_chains
() {
222 log DEBUG
"Creating firewall chains for zone '${zone}'."
224 local chain_prefix
="ZONE_${zone^^}"
226 # Create filter chains.
227 iptables_chain_create
"${chain_prefix}_INPUT"
228 iptables
-A INPUT
-i ${zone} -j "${chain_prefix}_INPUT"
230 iptables_chain_create
"${chain_prefix}_OUTPUT"
231 iptables
-A OUTPUT
-o ${zone} -j "${chain_prefix}_OUTPUT"
234 iptables_chain_create
"${chain_prefix}_CUSTOM"
236 # Intrusion Prevention System.
237 iptables_chain_create
"${chain_prefix}_IPS"
239 # Create a chain for each other zone.
240 # This leaves us with n^2 chains. Duh.
242 local other_zone other_chain_prefix
243 for other_zone
in $
(zones_get_all
); do
244 other_chain_prefix
="${chain_prefix}_${other_zone^^}"
245 iptables_chain_create
${other_chain_prefix}
247 # Connect the chain with the FORWARD chain.
248 iptables
-A FORWARD
-i ${zone} -o ${other_zone} \
249 -j "${other_chain_prefix}"
251 # Handle custom rules.
252 iptables
-A ${other_chain_prefix} -j "${chain_prefix}_CUSTOM"
255 iptables
-A ${other_chain_prefix} -j "${chain_prefix}_IPS"
258 iptables_chain_create
"${other_chain_prefix}_RULES"
259 iptables
-A ${other_chain_prefix} -j "${other_chain_prefix}_RULES"
262 iptables_chain_create
"${other_chain_prefix}_POLICY"
263 iptables
-A ${other_chain_prefix} -j "${other_chain_prefix}_POLICY"
266 ## Create mangle chain.
267 #iptables_chain_create -t mangle ${chain_prefix}
268 #iptables -t mangle -A PREROUTING -i ${zone} -j ${chain_prefix}
269 #iptables -t mangle -A POSTROUTING -o ${zone} -j ${chain_prefix}
271 ## Quality of Service
272 #iptables_chain_create -t mangle "${chain_prefix}_QOS_INC"
273 #iptables -t mangle -A ${chain_prefix} -i ${zone} -j "${chain_prefix}_QOS_INC"
274 #iptables_chain_create -t mangle "${chain_prefix}_QOS_OUT"
275 #iptables -t mangle -A ${chain_prefix} -o ${zone} -j "${chain_prefix}_QOS_OUT"
278 iptables_chain_create
-4 -t nat
${chain_prefix}
279 iptables
-4 -t nat
-A PREROUTING
-i ${zone} -j ${chain_prefix}
280 iptables
-4 -t nat
-A POSTROUTING
-o ${zone} -j ${chain_prefix}
282 # Network Address Translation
283 iptables_chain_create
-4 -t nat
"${chain_prefix}_DNAT"
284 iptables
-4 -t nat
-A PREROUTING
-i ${zone} -j "${chain_prefix}_DNAT"
285 iptables_chain_create
-4 -t nat
"${chain_prefix}_SNAT"
286 iptables
-4 -t nat
-A POSTROUTING
-o ${zone} -j "${chain_prefix}_SNAT"
289 iptables_chain_create
-4 -t nat
"${chain_prefix}_UPNP"
290 iptables
-4 -t nat
-A ${chain_prefix} -j "${chain_prefix}_UPNP"
295 function firewall_parse_rules
() {
300 # End if no rule file exists.
301 [ -r "${file}" ] ||
return ${EXIT_OK}
305 local ${FIREWALL_RULES_CONFIG_PARAMS}
307 while read -r line
; do
309 [ -n "${line}" ] ||
continue
311 # Skip commented lines.
312 [ "${line:0:1}" = "#" ] && continue
315 _firewall_parse_rule_line
${line}
316 if [ $?
-ne ${EXIT_OK} ]; then
317 log WARNING
"Skipping invalid line: ${line}"
323 # Source IP address/net.
325 list_append cmd
"-s ${src}"
328 # Destination IP address/net.
330 list_append cmd
"-d ${dst}"
335 list_append cmd
"-p ${proto}"
337 if list_match
${proto} ${FIREWALL_PROTOCOLS_SUPPORTING_PORTS}; then
339 list_append cmd
"--sport ${sport}"
343 list_append cmd
"--dport ${dport}"
348 # Always append the action.
349 list_append cmd
"-j ${action}"
356 function _firewall_parse_rule_line
() {
360 for arg
in ${FIREWALL_RULES_CONFIG_PARAMS}; do
365 while read -r arg
; do
366 key
=$
(cli_get_key
${arg})
368 if ! listmatch
"${key}" ${FIREWALL_RULES_CONFIG_PARAMS}; then
369 log WARNING
"Unrecognized argument: ${arg}"
373 val
=$
(cli_get_val
${arg})
374 assign
"${key}" "${val}"
375 done <<< "$(args $@)"
377 # action must always be set.
378 if ! isset action
; then
379 log WARNING
"'action' is not set: $@"
383 for arg
in src dst
; do
384 isset
${arg} ||
continue
386 # Check for valid IP addresses.
387 if ! ip_is_valid
${!arg}; then
388 log WARNING
"Invalid IP address for '${arg}=${!arg}': $@"
397 if ! list_match
"${proto}" ${FIREWALL_SUPPORTED_PROTOCOLS}; then
398 log WARNING
"Unsupported protocol type 'proto=${proto}': $@"
403 for arg
in sport dport
; do
404 isset
${arg} ||
continue
406 # Check if port is valid.
407 if ! isinteger
${arg}; then
408 log WARNING
"Invalid port '${arg}=${!arg}': $@"