blacklist and iptrap except rules now accept negative expressions too; firehol explain now has a history

This commit is contained in:
Costa Tsaousis (ktsaou) 2015-02-08 10:44:00 +02:00
parent 4359d24aa7
commit 1a80afc8c8
2 changed files with 150 additions and 77 deletions

@ -19,16 +19,12 @@ firehol-iptrap - dynamically put IP addresses in an ipset
`ipuntrap` deletes the IP adresses of the matching packets from `ipset`.
Both helpers do not affect the flow of traffic. They does not `ACCEPT`,
Both helpers do not affect the flow of traffic. They do not `ACCEPT`,
`REJECT`, `DROP` packets or affect the firewall in any way.
`type` selects which of the IP addresses of the matching packets will be used
(added or removed from the ipset). `type` can be `src`, `dst`, `src,dst`,
`dst,src`.
Both helpers will create the `ipset` specified, if that ipset is not already
created by other statements. When the ipset is created by the `iptrap` helper,
the ipset will not be reset (emptied) when the firewall is restarted.
`dst,src`. If type is a pair, then the ipset must be an ipset of pairs too.
`timeout` is required by `iptrap` and gives the duration in seconds of the
lifetime of each IP address that is added to `ipset`. Every matching packet
@ -52,12 +48,38 @@ incoming traffic.
`iptrap` and `ipuntrap` cannot setup both IPv4 and IPv6 traps with one call.
The reason is that the `ipset` can either be IPv4 or IPv6.
Both helpers will create the `ipset` specified, if that ipset is not already
created by other statements. When the ipset is created by the `iptrap` helper,
the ipset will not be reset (emptied) when the firewall is restarted.
The ipset options used when these helpers create ipsets can be controlled
with the variable IPTRAP_DEFAULT_IPSET_OPTIONS.
# EXAMPLES
~~~~
iptrap4 src trap 3600 inface eth0 proto tcp dport 80 log "TRAPPED HTTP"
# Example: mini-IDS
# add to the ipset `trap` for an hour (3600 seconds) all IPs from all packets
# comming from eth0 and going to tcp/3306 (mysql).
iptrap4 src trap 3600 inface eth0 proto tcp dport 3306 log "TRAPPED HTTP"
# block them
blacklist4 full inface eth0 log "BLOCKED" src ipset:trap except src ipset:whitelist
# Example: ipuntrap
ipuntrap4 src trap inface eth0 src ipset:trap proto tcp dport 80 log "UNTRAPPED HTTP"
# Example: a knock
# The user will be able to knock at tcp/12345
iptrap4 src knock1 30 inface eth0 proto tcp dport 12345 log "KNOCK STEP 1"
# in 30 seconds knock at tcp/23456
iptrap4 src knock2 60 inface eth0 proto tcp dport 23456 src ipset:knock1 log "KNOCK STEP 2"
# in 60 seconds knock at tcp/34566
iptrap4 src knock3 90 inface eth0 proto tcp dport 34567 src ipset:knock2 log "KNOCK STEP 3"
#
# and in 90 seconds ssh
interface ...
server ssh accept src ipset:knock3
~~~~
# SEE ALSO

@ -3701,7 +3701,7 @@ blacklist() {
iptables_both -t mangle -N "${chain}.in"
# add the excepted rules
test ! -z "${1}" && ( rule nonot table mangle chain "${chain}.in" in action RETURN "${@}" || return 1 )
test ! -z "${1}" && ( rule return_negatives_in_place ignore_empty_positive table mangle chain "${chain}.in" in action RETURN "${@}" || return 1 )
# add the accounting rules
test ! -z "${accounting}" && ( iptables_both -t mangle -A "${chain}.in" -m nfacct --nfacct-name "${accounting}" || return 1 )
@ -3851,7 +3851,7 @@ iptrap() {
iptables_both -t mangle -N "${chain}"
# add the excepted rules
test ! -z "${1}" && ( rule nonot table mangle chain "${chain}" in action RETURN "${@}" || return 1 )
test ! -z "${1}" && ( rule return_negatives_in_place ignore_empty_positive table mangle chain "${chain}" in action RETURN "${@}" || return 1 )
# do the job
if [ ${undo} -eq 1 ]
@ -3860,7 +3860,12 @@ iptrap() {
iptables_both -t mangle -A "${chain}" -j SET --del-set ${ipset} ${type}
else
# add the ip
iptables_both -t mangle -A "${chain}" -j SET --add-set ${ipset} ${type} --exist --timeout ${timeout}
if [ -z "${timeout}" -o "${timeout}" = "default" ]
then
iptables_both -t mangle -A "${chain}" -j SET --add-set ${ipset} ${type}
else
iptables_both -t mangle -A "${chain}" -j SET --add-set ${ipset} ${type} --exist --timeout ${timeout}
fi
fi
# log and return
@ -5897,7 +5902,7 @@ rule() {
local nolog=0
# if set to 1, negative expressions will give an error
local nonot=0
local nonot=0 return_negatives_in_place=0 ignore_empty_positive=0
# if set to 1, detection algorithm about overwriting optional rule
# parameters will take place.
@ -5914,6 +5919,16 @@ rule() {
shift
;;
return_negatives_in_place)
return_negatives_in_place=1
shift
;;
ignore_empty_positive)
ignore_empty_positive=1
shift
;;
reverse|REVERSE)
reverse=1
shift
@ -7100,6 +7115,7 @@ rule() {
inf= outf= inph= outph= \
mc= ipv= iptables= src= dst= s= d= sp= dp= \
negative_chain= negative_action= \
not= \
DYNAMIC_CHAIN_COUNTER
# log mode selection
@ -7162,13 +7178,27 @@ rule() {
return 1
fi
if [ ${action_is_chain} -eq 1 ]
if [ ${return_negatives_in_place} -eq 1 ]
then
# we can implement negatives by entering
# RETURN rules in the main flow.
# this should only be done on dedicated chains
# i.e. chains that they will end at the positive
# rules
negative_chain="${chain}"
negative_action=
not="!"
elif [ ${action_is_chain} -eq 1 ]
then
# if the action is a chain name, then just add the negative
# expressions to this chain. Nothing more.
negative_chain="${action}"
negative_action=
not=
else
# if the action is a native iptables action, then create
# an intermidiate chain to store the negative expression,
@ -7182,13 +7212,14 @@ rule() {
iptables_both ${table} -N "${negative_chain}"
negative_action="${action}"
action="${negative_chain}"
not=
fi
if [ ! -z "${infacenot}" ]
then
for inf in ${inface}
do
iptables_both ${table} -A "${negative_chain}" -i "${inf}" -j RETURN
iptables_both ${table} -A "${negative_chain}" ${not} -i "${inf}" -j RETURN
done
infacenot=
inface=any
@ -7198,7 +7229,7 @@ rule() {
then
for outf in ${outface}
do
iptables_both ${table} -A "${negative_chain}" -o "${outf}" -j RETURN
iptables_both ${table} -A "${negative_chain}" ${not} -o "${outf}" -j RETURN
done
outfacenot=
outface=any
@ -7208,7 +7239,7 @@ rule() {
then
for inph in ${physin}
do
iptables_both ${table} -A "${negative_chain}" -m physdev ${physbridge} --physdev-in "${inph}" -j RETURN
iptables_both ${table} -A "${negative_chain}" -m physdev ${physbridge} ${not} --physdev-in "${inph}" -j RETURN
done
physinnot=
physin=any
@ -7218,7 +7249,7 @@ rule() {
then
for outph in ${physout}
do
iptables_both ${table} -A "${negative_chain}" -m physdev ${physbridge} --physdev-out "${outph}" -j RETURN
iptables_both ${table} -A "${negative_chain}" -m physdev ${physbridge} ${not} --physdev-out "${outph}" -j RETURN
done
physoutnot=
physout=any
@ -7228,7 +7259,7 @@ rule() {
then
for mc in ${mac}
do
iptables_both ${table} -A "${negative_chain}" -m mac --mac-source "${mc}" -j RETURN
iptables_both ${table} -A "${negative_chain}" -m mac ${not} --mac-source "${mc}" -j RETURN
done
macnot=
mac=any
@ -7255,10 +7286,10 @@ rule() {
[ ${IPSET_WARNING} -eq 1 ] && ipset_warning
s="${s/ipset:/}"
test -z "${FIREHOL_IPSETS_USED[$s]}" && FIREHOL_IPSETS_USED[$s]="USED"
${iptables} ${table} -A "${negative_chain}" -m set --match-set "${s}" src -j RETURN
${iptables} ${table} -A "${negative_chain}" -m set ${not} --match-set "${s}" src -j RETURN
;;
*)
${iptables} ${table} -A "${negative_chain}" -s "${s}" -j RETURN
${iptables} ${table} -A "${negative_chain}" ${not} -s "${s}" -j RETURN
;;
esac
done
@ -7289,10 +7320,10 @@ rule() {
[ ${IPSET_WARNING} -eq 1 ] && ipset_warning
d="${d/ipset:/}"
test -z "${FIREHOL_IPSETS_USED[$d]}" && FIREHOL_IPSETS_USED[$d]="USED"
${iptables} ${table} -A "${negative_chain}" -m set --match-set "${d}" dst -j RETURN
${iptables} ${table} -A "${negative_chain}" -m set ${not} --match-set "${d}" dst -j RETURN
;;
*)
${iptables} ${table} -A "${negative_chain}" -d "${d}" -j RETURN
${iptables} ${table} -A "${negative_chain}" ${not} -d "${d}" -j RETURN
;;
esac
done
@ -7312,7 +7343,7 @@ rule() {
for pr in ${proto}
do
iptables_both ${table} -A "${negative_chain}" -p "${pr}" -j RETURN
iptables_both ${table} -A "${negative_chain}" ${not} -p "${pr}" -j RETURN
done
protonot=
proto=any
@ -7330,7 +7361,7 @@ rule() {
do
for pr in ${proto}
do
iptables_both ${table} -A "${negative_chain}" -p "${pr}" --sport "${sp}" -j RETURN
iptables_both ${table} -A "${negative_chain}" -p "${pr}" ${not} --sport "${sp}" -j RETURN
done
done
sportnot=
@ -7349,7 +7380,7 @@ rule() {
do
for pr in ${proto}
do
iptables_both ${table} -A "${negative_chain}" -p "${pr}" --dport "${dp}" -j RETURN
iptables_both ${table} -A "${negative_chain}" -p "${pr}" ${not} --dport "${dp}" -j RETURN
done
done
dportnot=
@ -7360,7 +7391,7 @@ rule() {
then
for tuid in ${uid}
do
iptables_both ${table} -A "${negative_chain}" -m owner --uid-owner "${tuid}" -j RETURN
iptables_both ${table} -A "${negative_chain}" -m owner ${not} --uid-owner "${tuid}" -j RETURN
done
uidnot=
uid=any
@ -7370,7 +7401,7 @@ rule() {
then
for tgid in ${gid}
do
iptables_both ${table} -A "${negative_chain}" -m owner --gid-owner "${tgid}" -j RETURN
iptables_both ${table} -A "${negative_chain}" -m owner ${not} --gid-owner "${tgid}" -j RETURN
done
gidnot=
gid=any
@ -7380,7 +7411,7 @@ rule() {
then
for tpid in ${pid}
do
iptables_both ${table} -A "${negative_chain}" -m owner --pid-owner "${tpid}" -j RETURN
iptables_both ${table} -A "${negative_chain}" -m owner ${not} --pid-owner "${tpid}" -j RETURN
done
pidnot=
pid=any
@ -7390,7 +7421,7 @@ rule() {
then
for tsid in ${sid}
do
iptables_both ${table} -A "${negative_chain}" -m owner --sid-owner "${tsid}" -j RETURN
iptables_both ${table} -A "${negative_chain}" -m owner ${not} --sid-owner "${tsid}" -j RETURN
done
sidnot=
sid=any
@ -7400,7 +7431,7 @@ rule() {
then
for tcmd in ${cmd}
do
iptables_both ${table} -A "${negative_chain}" -m owner --cmd-owner "${tcmd}" -j RETURN
iptables_both ${table} -A "${negative_chain}" -m owner ${not} --cmd-owner "${tcmd}" -j RETURN
done
cmdnot=
cmd=any
@ -7410,7 +7441,7 @@ rule() {
then
for tmark in ${mark}
do
iptables_both ${table} -A "${negative_chain}" -m mark --mark "${tmark}" -j RETURN
iptables_both ${table} -A "${negative_chain}" -m mark ${not} --mark "${tmark}" -j RETURN
done
marknot=
mark=any
@ -7420,7 +7451,7 @@ rule() {
then
for ttos in ${tos}
do
iptables_both ${table} -A "${negative_chain}" -m tos --tos "${ttos}" -j RETURN
iptables_both ${table} -A "${negative_chain}" -m tos ${not} --tos "${ttos}" -j RETURN
done
tosnot=
tos=any
@ -7430,57 +7461,59 @@ rule() {
then
for tdscp in ${dscp}
do
iptables_both ${table} -A "${negative_chain}" -m dscp --dscp${dscptype} "${tdscp}" -j RETURN
iptables_both ${table} -A "${negative_chain}" -m dscp ${not} --dscp${dscptype} "${tdscp}" -j RETURN
done
dscpnot=
dscp=any
fi
# in case this is temporary chain we created for the negative expression,
# just make it have the final action of the rule.
# ipvall
for ipv in ${ipvall}
do
case "${ipv}" in
ipv4) iptables="iptables";;
ipv6) iptables="ip6tables";;
esac
for pr in ${proto}
if [ ! -z "${negative_action}" ]
then
# in case this is temporary chain we created for the negative expression,
# just make it have the final action of the rule.
# ipvall
for ipv in ${ipvall}
do
case ${pr} in
any|ANY)
proto_arg=()
;;
*)
proto_arg=("-p" "${pr}")
;;
case "${ipv}" in
ipv4) iptables="iptables";;
ipv6) iptables="ip6tables";;
esac
# since this is the target of the positive rules,
# logging and accounting can be attached here
[ "$logrule" = "limit" ] && ${iptables} ${table} -A "${negative_chain}" -m limit --limit "${FIREHOL_LOG_FREQUENCY}" --limit-burst "${FIREHOL_LOG_BURST}" -j ${FIREHOL_LOG_MODE} ${FIREHOL_LOG_OPTIONS} "${logopts_arg[@]}"
[ "$logrule" = "normal" ] && ${iptables} ${table} -A "${negative_chain}" -j ${FIREHOL_LOG_MODE} ${FIREHOL_LOG_OPTIONS} "${logopts_arg[@]}"
[ ! -z "${accounting}" ] && ${iptables} ${table} -A "${negative_chain}" -m nfacct --nfacct-name "${accounting}"
for pr in ${proto}
do
case ${pr} in
any|ANY)
proto_arg=()
;;
*)
proto_arg=("-p" "${pr}")
;;
esac
# the original action of the rule
test ! -z "${negative_action}" && ( rule_action_param ${iptables} "${negative_action}" "${pr}" "" "" "${table}" "${action_param[@]}" -- ${table} -A "${negative_chain}" "${proto_arg[@]}" || failed=$[failed + 1] )
# since this is the target of the positive rules,
# logging and accounting can be attached here
[ "$logrule" = "limit" ] && ( ${iptables} ${table} -A "${negative_chain}" -m limit --limit "${FIREHOL_LOG_FREQUENCY}" --limit-burst "${FIREHOL_LOG_BURST}" -j ${FIREHOL_LOG_MODE} ${FIREHOL_LOG_OPTIONS} "${logopts_arg[@]}" || failed=$[failed + 1] )
[ "$logrule" = "normal" ] && ( ${iptables} ${table} -A "${negative_chain}" -j ${FIREHOL_LOG_MODE} ${FIREHOL_LOG_OPTIONS} "${logopts_arg[@]}" || failed=$[failed + 1] )
[ ! -z "${accounting}" ] && ( ${iptables} ${table} -A "${negative_chain}" -m nfacct --nfacct-name "${accounting}" || failed=$[failed + 1] )
# the original action of the rule
rule_action_param ${iptables} "${negative_action}" "${pr}" "" "" "${table}" "${action_param[@]}" -- ${table} -A "${negative_chain}" "${proto_arg[@]}" || failed=$[failed + 1]
done
done
done
# The positive rules will just send traffic to a
# chains - there is not need for params
action_param=()
# The positive rules will just send traffic to a
# chains - there is not need for params
action_param=()
# disable logging and accounting
# already did it above
logrule=none
accounting=
# disable logging and accounting
# already did it above
logrule=none
accounting=
fi
fi
# ----------------------------------------------------------------------------------
# Process the positive rules
@ -7791,9 +7824,11 @@ rule() {
# build the command
basecmd=("${inf_arg[@]}" "${outf_arg[@]}" "${physdev_arg[@]}" "${inph_arg[@]}" "${outph_arg[@]}" "${limit_arg[@]}" "${iplimit_arg[@]}" "${proto_arg[@]}" "${s_arg[@]}" "${sp_arg[@]}" "${d_arg[@]}" "${dp_arg[@]}" "${owner_arg[@]}" "${uid_arg[@]}" "${gid_arg[@]}" "${pid_arg[@]}" "${sid_arg[@]}" "${cmd_arg[@]}" "${addrtype_arg[@]}" "${stp_arg[@]}" "${dtp_arg[@]}" "${state_arg[@]}" "${mc_arg[@]}" "${mark_arg[@]}" "${tos_arg[@]}" "${dscp_arg[@]}" ${custom})
[ "$logrule" = "limit" ] && ${iptables} ${table} -A "${chain}" "${basecmd[@]}" -m limit --limit "${FIREHOL_LOG_FREQUENCY}" --limit-burst "${FIREHOL_LOG_BURST}" -j ${FIREHOL_LOG_MODE} ${FIREHOL_LOG_OPTIONS} "${logopts_arg[@]}"
[ "$logrule" = "normal" ] && ${iptables} ${table} -A "${chain}" "${basecmd[@]}" -j ${FIREHOL_LOG_MODE} ${FIREHOL_LOG_OPTIONS} "${logopts_arg[@]}"
[ ! -z "${accounting}" ] && ${iptables} ${table} -A "${chain}" "${basecmd[@]}" -m nfacct --nfacct-name "${accounting}"
[ -z "${basecmd[*]}" -a ${ignore_empty_positive} -eq 1 ] && continue
[ "$logrule" = "limit" ] && ( ${iptables} ${table} -A "${chain}" "${basecmd[@]}" -m limit --limit "${FIREHOL_LOG_FREQUENCY}" --limit-burst "${FIREHOL_LOG_BURST}" -j ${FIREHOL_LOG_MODE} ${FIREHOL_LOG_OPTIONS} "${logopts_arg[@]}" || failed=$[failed + 1] )
[ "$logrule" = "normal" ] && ( ${iptables} ${table} -A "${chain}" "${basecmd[@]}" -j ${FIREHOL_LOG_MODE} ${FIREHOL_LOG_OPTIONS} "${logopts_arg[@]}" || failed=$[failed + 1] )
[ ! -z "${accounting}" ] && ( ${iptables} ${table} -A "${chain}" "${basecmd[@]}" -m nfacct --nfacct-name "${accounting}" || failed=$[failed + 1] )
# do it!
rule_action_param ${iptables} "${action}" "${pr}" "${statenot}" "${state}" "${table}" "${action_param[@]}" -- ${table} -A "${chain}" "${basecmd[@]}" || failed=$[failed + 1]
@ -9022,12 +9057,17 @@ You can now start typing firehol configuration directives.
Special interactive commands: help, show, quit
EOF
HISTFILE="${HOME}/.firehol_history"
test ! -f ${HISTFILE} && touch ${HISTFILE}
history -r
while [ 1 = 1 ]
do
echo -en "${COLOR_RESET}#${COLOR_GREEN} FireHOL ${COLOR_RESET}[${COLOR_BOLD}${COLOR_BLUE}${work_cmd}${COLOR_RESET}:${COLOR_CYAN}${work_name}${COLOR_RESET}]"
read -p " > " -e -r
prompt="${COLOR_RESET}#${COLOR_GREEN} FireHOL ${COLOR_RESET}[${COLOR_BOLD}${COLOR_BLUE}${work_cmd}${COLOR_RESET}:${COLOR_CYAN}${work_name}${COLOR_RESET}] > "
eval "read -ep \$'${prompt}' -e -r REPLY"
test -z "${REPLY}" && continue
history -s "${REPLY}"
history -w
set_work_function -ne "Executing user input"
@ -9051,7 +9091,8 @@ Additionaly, you can use the following commands:
quit to show the interactively given configuration file
and quit.
in same as typing: interface eth0 internet
in|in4|in6
same as typing: interface(4|6) eth0 world
This is used as a shortcut to get into the server/client
mode in which you can test the rules for certain
services.
@ -9067,7 +9108,7 @@ EOF
break
;;
quit)
quit|exit)
echo
${CAT_CMD} "${FIREHOL_TEMP_CONFIG}"
echo
@ -9075,7 +9116,17 @@ EOF
;;
in)
REPLY="interface eth0 internet"
REPLY="interface eth0 world"
continue
;;
in4)
REPLY="interface4 eth0 world"
continue
;;
in6)
REPLY="interface6 eth0 world"
continue
;;