Enhance IPv6 ban functionality: add dynamic mask handling and prevent banning own addresses
This commit is contained in:
@@ -10,8 +10,10 @@
|
|||||||
# -
|
# -
|
||||||
# -
|
# -
|
||||||
# - Note:
|
# - Note:
|
||||||
# - - If no mask is given mask will be set to '64'
|
# - - If no mask is given mask will be set to 'ban_ipv6_mask' (main_ipv6.conf),
|
||||||
|
# - default is '128'
|
||||||
# - - wrong addresses like '2g01::1' or '2a01::1/129' will be ignored
|
# - - wrong addresses like '2g01::1' or '2a01::1/129' will be ignored
|
||||||
|
# - - entries covering an own (global) address of this host will be ignored
|
||||||
# -
|
# -
|
||||||
# - Example:
|
# - Example:
|
||||||
# - 240e:ec:4ab1:feba:e8b4:4fb1:7984:4c
|
# - 240e:ec:4ab1:feba:e8b4:4fb1:7984:4c
|
||||||
|
|||||||
@@ -90,6 +90,11 @@ default_max_concurrent_http_conn_per_ip=50
|
|||||||
set_max_new_http_conn_per_second=true
|
set_max_new_http_conn_per_second=true
|
||||||
default_max_new_http_conn_per_second=200
|
default_max_new_http_conn_per_second=200
|
||||||
|
|
||||||
|
# ip6t-firewall-server:
|
||||||
|
# Prefix length for entries in 'ban_ipv6.list' given without mask.
|
||||||
|
#
|
||||||
|
default_ban_ipv6_mask=128
|
||||||
|
|
||||||
|
|
||||||
# - Dovecot Service
|
# - Dovecot Service
|
||||||
# -
|
# -
|
||||||
|
|||||||
@@ -73,6 +73,54 @@ containsElement () {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## - Expand a given IPv6 address (parameter 1) to 32 hex digits without colons.
|
||||||
|
## - Returns 1 if the address cannot be parsed.
|
||||||
|
## -
|
||||||
|
ipv6_expand() {
|
||||||
|
local _addr="${1,,}"
|
||||||
|
local _head _tail _group _n _out=""
|
||||||
|
local -a _h=() _t=()
|
||||||
|
|
||||||
|
if [[ "$_addr" == *::* ]] ; then
|
||||||
|
_head="${_addr%%::*}"
|
||||||
|
_tail="${_addr#*::}"
|
||||||
|
[[ "$_tail" == *::* ]] && return 1
|
||||||
|
[[ -n "$_head" ]] && IFS=':' read -ra _h <<< "$_head"
|
||||||
|
[[ -n "$_tail" ]] && IFS=':' read -ra _t <<< "$_tail"
|
||||||
|
_n=$(( 8 - ${#_h[@]} - ${#_t[@]} ))
|
||||||
|
[[ $_n -lt 1 ]] && return 1
|
||||||
|
for (( ; _n > 0; _n-- )) ; do
|
||||||
|
_h+=("0")
|
||||||
|
done
|
||||||
|
_h+=("${_t[@]}")
|
||||||
|
else
|
||||||
|
IFS=':' read -ra _h <<< "$_addr"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ ${#_h[@]} -eq 8 ]] || return 1
|
||||||
|
for _group in "${_h[@]}" ; do
|
||||||
|
[[ "$_group" =~ ^[0-9a-f]{1,4}$ ]] || return 1
|
||||||
|
_out+="$(printf '%04x' "0x$_group")"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "$_out"
|
||||||
|
}
|
||||||
|
|
||||||
|
## - Check if a given IPv6 address (parameter 1) lies within the network
|
||||||
|
## - given by address (parameter 2) and prefix length (parameter 3).
|
||||||
|
## -
|
||||||
|
ipv6_in_net() {
|
||||||
|
local _a _n _full _rest
|
||||||
|
_a="$(ipv6_expand "$1")" || return 1
|
||||||
|
_n="$(ipv6_expand "$2")" || return 1
|
||||||
|
_full=$(( $3 / 4 ))
|
||||||
|
_rest=$(( $3 % 4 ))
|
||||||
|
|
||||||
|
[[ "${_a:0:_full}" == "${_n:0:_full}" ]] || return 1
|
||||||
|
[[ $_rest -eq 0 ]] && return 0
|
||||||
|
(( (0x${_a:_full:1} >> (4 - _rest)) == (0x${_n:_full:1} >> (4 - _rest)) ))
|
||||||
|
}
|
||||||
|
|
||||||
is_number() {
|
is_number() {
|
||||||
|
|
||||||
return $(test ! -z "${1##*[!0-9]*}" > /dev/null 2>&1);
|
return $(test ! -z "${1##*[!0-9]*}" > /dev/null 2>&1);
|
||||||
|
|||||||
@@ -753,6 +753,10 @@ portforward_udp=""
|
|||||||
|
|
||||||
blocked_ips=""
|
blocked_ips=""
|
||||||
|
|
||||||
|
# - Prefix length for entries in 'ban_ipv6.list' given without mask
|
||||||
|
# -
|
||||||
|
ban_ipv6_mask=${default_ban_ipv6_mask}
|
||||||
|
|
||||||
|
|
||||||
# -------------
|
# -------------
|
||||||
# --- Block Ports
|
# --- Block Ports
|
||||||
|
|||||||
+56
-1
@@ -448,6 +448,29 @@ fi
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ---
|
||||||
|
# - ICMPv6 Neighbor Discovery and Packet Too Big
|
||||||
|
# ---
|
||||||
|
# Accept these before any rule blocking by source address (blocked_ips,
|
||||||
|
# ban_ipv6.list). Otherwise a blocked network containing a router of the
|
||||||
|
# own link breaks neighbor discovery - the router can no longer reach this host.
|
||||||
|
#
|
||||||
|
# 2 = packet-too-big
|
||||||
|
# 133= router-solicitation
|
||||||
|
# 134= router-advertisement
|
||||||
|
# 135= neighbor-solicitation
|
||||||
|
# 136= neighbor-advertisement
|
||||||
|
# ---
|
||||||
|
echononl "\tICMPv6 neighbor discovery / packet-too-big (before blocking rules).."
|
||||||
|
for t in 2 133 134 135 136 ; do
|
||||||
|
$ip6t -A INPUT -p ipv6-icmp --icmpv6-type $t -j ACCEPT
|
||||||
|
done
|
||||||
|
if $kernel_forward_between_interfaces ; then
|
||||||
|
$ip6t -A FORWARD -p ipv6-icmp --icmpv6-type 2 -j ACCEPT
|
||||||
|
fi
|
||||||
|
echo_done
|
||||||
|
|
||||||
|
|
||||||
# -------------
|
# -------------
|
||||||
# --- Block IPs / Networks / Interfaces
|
# --- Block IPs / Networks / Interfaces
|
||||||
# -------------
|
# -------------
|
||||||
@@ -509,6 +532,19 @@ if [[ -f "$conf_ban_ipv6_list" ]] ; then
|
|||||||
|
|
||||||
declare -a ban_ipv6_arr=()
|
declare -a ban_ipv6_arr=()
|
||||||
declare -a no_valid_ipv6=()
|
declare -a no_valid_ipv6=()
|
||||||
|
declare -a own_ipv6_banned_arr=()
|
||||||
|
|
||||||
|
if [[ -z "$ban_ipv6_mask" || ! "$ban_ipv6_mask" =~ ^[0-9]+$ ]] || [[ $ban_ipv6_mask -gt 128 ]] ; then
|
||||||
|
ban_ipv6_mask=${default_ban_ipv6_mask:-128}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Own global IPv6 addresses (read at runtime, also covers SLAAC addresses).
|
||||||
|
# Entries covering one of them would block the own prefix including its routers.
|
||||||
|
#
|
||||||
|
declare -a own_ipv6_arr=()
|
||||||
|
for _own_ip in $(ip -6 -o addr show scope global | awk '{split($4, a, "/"); print a[1]}') ; do
|
||||||
|
own_ipv6_arr+=("$_own_ip")
|
||||||
|
done
|
||||||
|
|
||||||
# Regex valid ipv6 address
|
# Regex valid ipv6 address
|
||||||
#
|
#
|
||||||
@@ -568,7 +604,7 @@ if [[ -f "$conf_ban_ipv6_list" ]] ; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
mask=64
|
mask=$ban_ipv6_mask
|
||||||
is_valid_mask=true
|
is_valid_mask=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -586,6 +622,22 @@ if [[ -f "$conf_ban_ipv6_list" ]] ; then
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Never ban a network containing an own address
|
||||||
|
#
|
||||||
|
_covers_own_ip=false
|
||||||
|
for _own_ip in "${own_ipv6_arr[@]}" ; do
|
||||||
|
if ipv6_in_net "$_own_ip" "$ipv6" "$mask" ; then
|
||||||
|
_covers_own_ip=true
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if $_covers_own_ip ; then
|
||||||
|
if ! containsElement "$_ip" "${own_ipv6_banned_arr[@]}" ; then
|
||||||
|
own_ipv6_banned_arr+=("$_ip")
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
for _dev in ${ext_if_arr[@]} ; do
|
for _dev in ${ext_if_arr[@]} ; do
|
||||||
if $log_blocked_ip || $log_all ; then
|
if $log_blocked_ip || $log_all ; then
|
||||||
$ip6t -A INPUT -i $_dev -s $_ip -j $LOG_TARGET $tag_log_prefix "$log_prefix Blocked by ban_ipv6.list: "
|
$ip6t -A INPUT -i $_dev -s $_ip -j $LOG_TARGET $tag_log_prefix "$log_prefix Blocked by ban_ipv6.list: "
|
||||||
@@ -614,6 +666,9 @@ if [[ -f "$conf_ban_ipv6_list" ]] ; then
|
|||||||
if [[ ${#no_valid_ipv6_arr[@]} -gt 0 ]]; then
|
if [[ ${#no_valid_ipv6_arr[@]} -gt 0 ]]; then
|
||||||
warn "Ignored: ${no_valid_ipv6_arr[@]}"
|
warn "Ignored: ${no_valid_ipv6_arr[@]}"
|
||||||
fi
|
fi
|
||||||
|
if [[ ${#own_ipv6_banned_arr[@]} -gt 0 ]]; then
|
||||||
|
warn "Ignored (covers own address): ${own_ipv6_banned_arr[@]}"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
echo_skipped
|
echo_skipped
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user