marks can now be stateful/stateless and temporary/permanent as per #50

This commit is contained in:
Costa Tsaousis (ktsaou) 2015-01-25 17:59:28 +02:00
parent 55e445e033
commit 4f2b99298a

@ -99,18 +99,12 @@ declare -A MARKS_BITS=()
declare -A MARKS_MASKS=()
declare -A MARKS_MAX=()
declare -A MARKS_SHIFT=()
declare -A MARKS_SAVERESTORE=()
declare -A MARKS_STATEFUL=()
MARKS_SAVERESTORE_STATEFUL_MASK="0x00000000"
MARKS_SAVERESTORE_STATELESS_MASK="0x00000000"
MARKS_TOTAL_BITS=0
marksreset() {
#echo >&2 "${FUNCNAME} ${*}: Reseting marks..."
MARKS_BITS=()
MARKS_MASKS=()
MARKS_MAX=()
MARKS_SHIFT=()
MARKS_TOTAL_BITS=0
#declare -p MARKS_BITS MARKS_MASKS MARKS_MAX MARKS_SHIFT >&2
}
# taken from http://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer
# and http://books.google.gr/books?id=iBNKMspIlqEC&pg=PA66&redir_esc=y#v=onepage&q&f=false
# counts the number of bits set in a number
@ -135,12 +129,56 @@ ispoweroftwo() {
return 1
}
marksreset() { markdef clear; }
markdef() {
# echo >&2 "${FUNCNAME} ${*}"
if [ "$1" = "reset" -o "$1" = "clear" ]
then
MARKS_BITS=()
MARKS_MASKS=()
MARKS_MAX=()
MARKS_SHIFT=()
MARKS_SAVERESTORE=()
MARKS_STATEFUL=()
MARKS_SAVERESTORE_STATEFUL_MASK="0x00000000"
MARKS_SAVERESTORE_STATELESS_MASK="0x00000000"
MARKS_TOTAL_BITS=0
return 0
fi
local saverestore=1
local stateful=1
local name="${1}"; shift
local max="${1}"; shift
while [ ! -z "${1}" ]
do
case "${1}" in
save|restore|permanent)
local saverestore=1
;;
nosave|norestore|temp|temporary)
local saverestore=0
;;
stateless)
local stateful=0
;;
stateful)
local stateful=1
;;
*)
echo >&2 "${FUNCNAME}: Unknown keyword '${1}'."
exit 1
;;
esac
shift
done
if [ ! -z "${MARKS_MASKS[$name]}" ]
then
echo >&2 "Mark type '${name}' already exists with mask ${MARKS_MASKS[$name]}. Please use 'marksreset' to reset them before re-defining them."
@ -191,9 +229,21 @@ markdef() {
MARKS_MAX[$name]=$max
MARKS_BITS[$name]=$bits
MARKS_MASKS[$name]=$(printf "0x%08x" $mask)
MARKS_STATEFUL[$name]=$stateful
MARKS_SAVERESTORE[$name]=$saverestore
if [ $saverestore -eq 1 ]
then
if [ $stateful -eq 1 ]
then
MARKS_SAVERESTORE_STATEFUL_MASK=$(printf "0x%08x" $[MARKS_SAVERESTORE_STATEFUL_MASK | mask])
else
MARKS_SAVERESTORE_STATELESS_MASK=$(printf "0x%08x" $[MARKS_SAVERESTORE_STATELESS_MASK | mask])
fi
fi
# echo "Mark $name with $[MARKS_MAX[$name] + 1] possible values (from 0 to ${MARKS_MAX[$name]}), uses ${MARKS_BITS[$name]} bits, has mask ${MARKS_MASKS[$name]} and values should be shifted by ${MARKS_SHIFT[$name]} bits"
# declare -p MARKS_BITS MARKS_MASKS MARKS_MAX MARKS_SHIFT >&2
# declare -p MARKS_BITS MARKS_MASKS MARKS_MAX MARKS_SHIFT MARKS_STATEFUL MARKS_SAVERESTORE MARKS_SAVERESTORE_STATEFUL_MASK MARKS_SAVERESTORE_STATELESS_MASK >&2
MARKS_TOTAL_BITS=$[ MARKS_TOTAL_BITS + bits ]
}
@ -439,11 +489,60 @@ FIREHOL_TRUST_LOOPBACK=1
# FireHOL allows multiple independent MARKs.
# By default FireHOL requires 'connmark' and 'usermark'.
# The possible values supported by each may be defined here.
# The value must be a power of two.
# reset the internal marks to empty - do not remove
marksreset
# Mark types may be defined with this template:
#
# markdef NAME VALUES [stateful|stateless] [permanent|temporary]
#
# NAME = a name for this mark type
# connmark and usermark should always be defined.
#
# VALUES = max number of marks to support (0 to VALUES - 1)
# VALUES must be a power of two.
#
# stateful = all statements that assign this mark should
# only apply it on NEW packets.
#
# stateless = all statements that assign this mark type should
# only apply it only to traffic matched by the
# optional rule parameters given.
#
# temporary = do not save/restore to/from connection marks.
# This means RESPONSES to the matched packets
# will not get the mark.
#
# permanent = save/restore to/from connection marks
# This means that RESPONSES will get the mark.
#
# NOTES ABOUT markdef OPTIONS
#
# default is : stateful permanent
# in this mode, only NEW packets of connections need
# to be marked. ESTABLISHED and RELATED packets
# will automatically get the same mark too.
# So, in FireHOL mark helpers (connmark, mark, custommark)
# you will only need to match a REQUEST packet and
# automatically all the packets of the connection will
# get the mark.
#
# - stateful temporary
# In this mode, only NEW packets will be marked for each
# connection. ESTABLISHED and RELATED packets will NOT
# get the mark.
#
# - stateless permanent
# In this mode, whatever the helper statement matches
# will get the mark. This mark will also be applied to
# all the packets that are encountered after the marked
# packet and are part of the same socket.
#
# - stateless temporary
# In this mode, only whatever the helper statement matches
# will get the mark. Nothing else.
#
# clear the internal marks - do not remove this line
markdef clear
# connmarks are used by the connmark helper
markdef connmark 64
@ -451,11 +550,12 @@ markdef connmark 64
# usermark are used by the mark helper
markdef usermark 128
# Additional types may be defined like this:
# Custom mark example:
#
# markdef qosmark 8
# To use it use 'custommark' helper and match
# The first argument to both is the mark name (qosmark in this case)
#
# To use it use 'custommark' helper and optional rule parameter.
# The first argument to both should the mark name (qosmark in this case)
# ----------------------------------------------------------------------
# IPTABLES PACKETS LOGGING
@ -552,7 +652,7 @@ then
fi
# save the information for the other tools
declare -p MARKS_BITS MARKS_MASKS MARKS_MAX MARKS_SHIFT >"${FIREHOL_SPOOL_DIR}/marks.conf"
declare -p MARKS_BITS MARKS_MASKS MARKS_MAX MARKS_SHIFT MARKS_STATEFUL MARKS_SAVERESTORE MARKS_SAVERESTORE_STATEFUL_MASK MARKS_SAVERESTORE_STATELESS_MASK >"${FIREHOL_SPOOL_DIR}/marks.conf"
# ------------------------------------------------------------------------------
@ -696,8 +796,8 @@ which_cmd FLOCK_CMD flock
if [ ! -f "${FIREHOL_CONFIG_DIR}/firehol-defaults.conf" ]
then
"${EGREP_CMD}" "^# --- BEGIN OF FIREHOL DEFAULTS ---" -A 600 "${FIREHOL_FILE}" |\
"${EGREP_CMD}" "^# --- END OF FIREHOL DEFAULTS ---" -B 600 >"${FIREHOL_CONFIG_DIR}/firehol-defaults.conf" || exit 1
"${EGREP_CMD}" "^# --- BEGIN OF FIREHOL DEFAULTS ---" -A 1000 "${FIREHOL_FILE}" |\
"${EGREP_CMD}" "^# --- END OF FIREHOL DEFAULTS ---" -B 1000 >"${FIREHOL_CONFIG_DIR}/firehol-defaults.conf" || exit 1
"${CHOWN_CMD}" root:root "${FIREHOL_CONFIG_DIR}/firehol-defaults.conf" || exit 1
"${CHMOD_CMD}" 600 "${FIREHOL_CONFIG_DIR}/firehol-defaults.conf" || exit 1
fi
@ -3636,12 +3736,23 @@ connmark() {
do
case "${chain}" in
interface)
rule table mangle chain PREROUTING custom '-m conntrack --ctstate NEW' inface "${@}" action MARK to "${mark}" || return 1
rule table mangle chain POSTROUTING custom '-m conntrack --ctstate NEW' outface "${@}" action MARK to "${mark}" || return 1
if [ ${MARKS_STATEFUL[connmark]} -eq 1 ]
then
rule table mangle chain PREROUTING custom '-m conntrack --ctstate NEW' inface "${@}" action MARK to "${mark}" || return 1
rule table mangle chain POSTROUTING custom '-m conntrack --ctstate NEW' outface "${@}" action MARK to "${mark}" || return 1
else
rule table mangle chain PREROUTING inface "${@}" action MARK to "${mark}" || return 1
rule table mangle chain POSTROUTING outface "${@}" action MARK to "${mark}" || return 1
fi
;;
*)
rule table mangle chain "${chain}" custom '-m conntrack --ctstate NEW' "${@}" action MARK to "${mark}" || return 1
if [ ${MARKS_STATEFUL[connmark]} -eq 1 ]
then
rule table mangle chain "${chain}" custom '-m conntrack --ctstate NEW' "${@}" action MARK to "${mark}" || return 1
else
rule table mangle chain "${chain}" action MARK to "${mark}" || return 1
fi
;;
esac
done
@ -3673,7 +3784,12 @@ custommark() {
local mark="$(mark_value $name $num)"
test -z "${mark}" && work_error=$[work_error + 1] && return 1
rule table mangle chain "${where}" custom '-m conntrack --ctstate NEW' "${@}" action MARK to "${mark}" || return 1
if [ ${MARKS_STATEFUL[$name]} -eq 1 ]
then
rule table mangle chain "${where}" custom '-m conntrack --ctstate NEW' "${@}" action MARK to "${mark}" || return 1
else
rule table mangle chain "${where}" "${@}" action MARK to "${mark}" || return 1
fi
return 0
}
@ -4826,13 +4942,27 @@ close_router() {
close_master() {
set_work_function "Finilizing firewall policies"
# copy CONNMARK to MARK at the top of mangle, on entry points
iptables_both -t mangle -I OUTPUT 1 -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark
iptables_both -t mangle -I PREROUTING 1 -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark
if [ ! "${MARKS_SAVERESTORE_STATEFUL_MASK}" = "0x00000000" ]
then
# copy CONNMARK to MARK at the top of mangle, on entry points
iptables_both -t mangle -I OUTPUT 1 -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --mask ${MARKS_SAVERESTORE_STATEFUL_MASK}
iptables_both -t mangle -I PREROUTING 1 -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --mask ${MARKS_SAVERESTORE_STATEFUL_MASK}
# save MARK to CONNMARK at the end of mangle, on exit points
iptables_both -t mangle -A INPUT -m conntrack --ctstate NEW -j CONNMARK --save-mark
iptables_both -t mangle -A POSTROUTING -m conntrack --ctstate NEW -j CONNMARK --save-mark
# save MARK to CONNMARK at the end of mangle, on exit points
iptables_both -t mangle -A INPUT -m conntrack --ctstate NEW -j CONNMARK --save-mark --mask ${MARKS_SAVERESTORE_STATEFUL_MASK}
iptables_both -t mangle -A POSTROUTING -m conntrack --ctstate NEW -j CONNMARK --save-mark --mask ${MARKS_SAVERESTORE_STATEFUL_MASK}
fi
if [ ! "${MARKS_SAVERESTORE_STATELESS_MASK}" = "0x00000000" ]
then
# copy CONNMARK to MARK at the top of mangle, on entry points
iptables_both -t mangle -I OUTPUT 1 -j CONNMARK --restore-mark --mask ${MARKS_SAVERESTORE_STATELESS_MASK}
iptables_both -t mangle -I PREROUTING 1 -j CONNMARK --restore-mark --mask ${MARKS_SAVERESTORE_STATELESS_MASK}
# save MARK to CONNMARK at the end of mangle, on exit points
iptables_both -t mangle -A INPUT -j CONNMARK --save-mark --mask ${MARKS_SAVERESTORE_STATELESS_MASK}
iptables_both -t mangle -A POSTROUTING -j CONNMARK --save-mark --mask ${MARKS_SAVERESTORE_STATELESS_MASK}
fi
# Accept all related traffic to the established connections
rule chain INPUT state RELATED action ACCEPT || return 1