Stateful Inspection mit FWbuilder und iptables
Hallo zusammen 
ich verzweifle grad ein bisschen an meiner iptables-Firewall..
Szenario:
Ein Kunde bekommt von uns einen mobilen Router mit Stromversorgung über einen USB-Port, der "stealth" zwischen den Rechner und den Netzwerkport geschaltet wird. Der Rechner bekommt dann ganz normal eine IP via DHCP aus dem Netzwerk, in dem er lokal angeschlossen wurde. Der Router hingegen hat eine feste IP, mit der er eine VPN-Verbindung zu unserem Kundensupport-System aufbaut. Nun kann der Kunde, wenn er die richtige IP im Browser mit HTTPs eingibt, auf eine Webseite zugreifen, über die der Kunde einige Funktionen zur Verfügung gestellt bekommt.
Die Funktion, für die ich gerade eine (oder mehrere) Firewallregel(n) konfigurieren muss, bevor das produktiv geschaltet wird, ist die, dass der Kunde über das Webportal eine virtuelle Maschine starten kann. Auf diese kann er dann per VNC zugreifen, um an einer seiner Produktionsmaschinen (die wir bauen und verkaufen) Wartungsprogramme laufen zu lassen. Der Vorteil ist einfach, dass nicht wegen jeder "Kleinigkeit" ein Monteur zum Kunden geschickt werden muss. Zusätzlich kann der Kunde und auch gleichzeitig ein Mitarbeiter aus unserem technischen Support auf die VM schauen, um zusammen einem eventuellen Problem auf die Schliche zu kommen.
Da wir jedoch wesentlich viele Maschinen haben (es laufen immer nur einige wenige, jedoch halten wir viele auf Bedarf vor) werden die IP's der Maschinen via DHCP vergeben, was für mich die Firewallkonfiguration nicht unbedingt leichter macht ;)
Zielsetzung:
Ein fester Parameter, den ich für die von der Webseite dynamisch angepassten iptables-Firewall nutzen kann, ist natürlich die MAC-Adresse. Diese ist für jede VM in der Datenbank hinterlegt, um beispielsweise für Firewallregeln auf diese zurückgreifen zu können. Um nun den VNC-Zugriff auf diese Maschinen soweit einschränken zu können, dass der Kunde nur auf die ihm zugewiesenen VM's kommt, hatte ich mir überlegt, VNC-Anfragen (Syn) generell zu erlauben, und nur die Antwortpakete (ack) von der Firewall dynamisch durchzulassen oder eben zu verwerfen. Auf diese Idee bin ich gekommen, weil ich durch eine Recherche im Internet festgestellt habe, dass man bei iptables eine MAC-Adresse nur als Source angeben kann, leider nicht als Destination. Sollte für dieses Szenario jemand eine bessere Idee haben, bin ich gerne bereit darüber zu sprechen ;)
Problem:
Heute habe ich nach langem googlen (am Freitag hatte ich es aus Frust abgebrochen..) herausgefunden, dass der FWbuilder wohl ein Modul lädt, was automatisch für jede Regel entsprechende Regeln für die Antwortpakete erstellt, was ja auch erstmal ne super Sache ist, und die Konfiguration wesentlich vereinfacht. der Nachteil ist, dass diese Funktionalität für dieses eine Szenario sehr hinderlich ist. Wenn ich nun in Regel 16 die Verbindungsanfrage mit folgender Regel freischalte (gekürzt auf einen Kunden mit einer Maschine, um die Übersichtlichkeit nicht zu verlieren):
Diese Regel schaltet jedoch dummerweise auch automatisch durch dieses geladene Modul die Antwortpakete frei, was allerdings denkbar ungünstig ist, weil der Kunde A so beispielsweise auf die VM einer Maschine von Kunde B gelangen kann. Daher habe ich eine Regel für die Antwortpakete erstellt, die jedoch beim Compilieren im FWBuilder eine Fehlermeldung ausspuckt
Frage:
Welche Möglichkeiten habe ich nun, um dieses Szenario zu realisieren? Irgendwelche Ideen? (Am besten, ohne dass ich die ganzen anderern Regeln anfassen muss, weil das sind dann doch schon einige Hundert Zeilen Code -.-*
Von FWbuilder generierter Code (ohne die ganzen Regeln):
Anbei noch der Rest der Firewall-Konfiguration, die vom FWbuilder generiert wird. Ausgenommen habe ich sämtliche von mir erstellten Regeln, jedoch habe ich einen Hinweis an der Stelle eingebaut, wo normal das Regelwerk käme. Ich denke, dass das "Vorgeplänkel" vor dem Regelwerk bei der Problemlösung sinnvoll sein könnte. Also bei Bedarf stehen die folgenden 400 Zeilen zur Verfügung ;)
Bin für jede Hilfe Dankbar!!
Viele Grüße pkrix89
ich verzweifle grad ein bisschen an meiner iptables-Firewall..
Szenario:
Ein Kunde bekommt von uns einen mobilen Router mit Stromversorgung über einen USB-Port, der "stealth" zwischen den Rechner und den Netzwerkport geschaltet wird. Der Rechner bekommt dann ganz normal eine IP via DHCP aus dem Netzwerk, in dem er lokal angeschlossen wurde. Der Router hingegen hat eine feste IP, mit der er eine VPN-Verbindung zu unserem Kundensupport-System aufbaut. Nun kann der Kunde, wenn er die richtige IP im Browser mit HTTPs eingibt, auf eine Webseite zugreifen, über die der Kunde einige Funktionen zur Verfügung gestellt bekommt.
Die Funktion, für die ich gerade eine (oder mehrere) Firewallregel(n) konfigurieren muss, bevor das produktiv geschaltet wird, ist die, dass der Kunde über das Webportal eine virtuelle Maschine starten kann. Auf diese kann er dann per VNC zugreifen, um an einer seiner Produktionsmaschinen (die wir bauen und verkaufen) Wartungsprogramme laufen zu lassen. Der Vorteil ist einfach, dass nicht wegen jeder "Kleinigkeit" ein Monteur zum Kunden geschickt werden muss. Zusätzlich kann der Kunde und auch gleichzeitig ein Mitarbeiter aus unserem technischen Support auf die VM schauen, um zusammen einem eventuellen Problem auf die Schliche zu kommen.
Da wir jedoch wesentlich viele Maschinen haben (es laufen immer nur einige wenige, jedoch halten wir viele auf Bedarf vor) werden die IP's der Maschinen via DHCP vergeben, was für mich die Firewallkonfiguration nicht unbedingt leichter macht ;)
Zielsetzung:
Ein fester Parameter, den ich für die von der Webseite dynamisch angepassten iptables-Firewall nutzen kann, ist natürlich die MAC-Adresse. Diese ist für jede VM in der Datenbank hinterlegt, um beispielsweise für Firewallregeln auf diese zurückgreifen zu können. Um nun den VNC-Zugriff auf diese Maschinen soweit einschränken zu können, dass der Kunde nur auf die ihm zugewiesenen VM's kommt, hatte ich mir überlegt, VNC-Anfragen (Syn) generell zu erlauben, und nur die Antwortpakete (ack) von der Firewall dynamisch durchzulassen oder eben zu verwerfen. Auf diese Idee bin ich gekommen, weil ich durch eine Recherche im Internet festgestellt habe, dass man bei iptables eine MAC-Adresse nur als Source angeben kann, leider nicht als Destination. Sollte für dieses Szenario jemand eine bessere Idee haben, bin ich gerne bereit darüber zu sprechen ;)
Problem:
Heute habe ich nach langem googlen (am Freitag hatte ich es aus Frust abgebrochen..) herausgefunden, dass der FWbuilder wohl ein Modul lädt, was automatisch für jede Regel entsprechende Regeln für die Antwortpakete erstellt, was ja auch erstmal ne super Sache ist, und die Konfiguration wesentlich vereinfacht. der Nachteil ist, dass diese Funktionalität für dieses eine Szenario sehr hinderlich ist. Wenn ich nun in Regel 16 die Verbindungsanfrage mit folgender Regel freischalte (gekürzt auf einen Kunden mit einer Maschine, um die Übersichtlichkeit nicht zu verlieren):
$IPT="/sbin/iptables"
#Dem Kunden VNC-Anfragen gestatten:
$IPT -N Cid4937X3018.0
$IPT -a INPUT -i br3 -p tcp -m tcp -d 192.168.0.0/24 --dport 5900 -m state --state NEW -j Cid4937X3018.0
$IPT -N In_RULE_16
$IPT -A Cid4937X3018.0 -s 192.168.0.x -j In_RULE_16
# Für jeden Kunden eine Zeile, da ich VNC-SYN ja für die Kunden global freischalten lassen möchte
$IPT -N Cid4937X3018.1
$IPT -A FORWARD -i br3 -p tcp -m tcp -d 192.168.0.0/24 --dport 5900 -m state --state NEW -j Cid4937X3018.1
$IPT -A Cid4937X3018.1 -s 192.168.0.x -j In_RULE_16
# Für jeden Kunden eine Zeile, da ich VNC-SYN ja für die Kunden global freischalten lassen möchte
$IPT -A In_RULE_16 -j LOG --log-level info --log-prefix "RULE 16 -- ACCEPT "
$IPT -A In_RULE_16 -j ACCEPT
#Dem Kunden die VNC-Antworten SEINER VM's gestatten:
Firewall:Policy:17: error: TCPService object with option "established" is not dupportet by firewall platform "iptables". Use stateful rule instead.
Frage:
Welche Möglichkeiten habe ich nun, um dieses Szenario zu realisieren? Irgendwelche Ideen? (Am besten, ohne dass ich die ganzen anderern Regeln anfassen muss, weil das sind dann doch schon einige Hundert Zeilen Code -.-*
Von FWbuilder generierter Code (ohne die ganzen Regeln):
Anbei noch der Rest der Firewall-Konfiguration, die vom FWbuilder generiert wird. Ausgenommen habe ich sämtliche von mir erstellten Regeln, jedoch habe ich einen Hinweis an der Stelle eingebaut, wo normal das Regelwerk käme. Ich denke, dass das "Vorgeplänkel" vor dem Regelwerk bei der Problemlösung sinnvoll sein könnte. Also bei Bedarf stehen die folgenden 400 Zeilen zur Verfügung ;)
FWBDEBUG=""
PATH="/sbin:/usr/sbin:/bin:/usr/bin:${PATH}"
export PATH
LSMOD="/sbin/lsmod"
MODPROBE="/sbin/modprobe"
IPTABLES="/usr/sbin/iptables"
IP6TABLES="/usr/sbin/ip6tables"
IPTABLES_RESTORE="/usr/sbin/iptables-restore"
IP6TABLES_RESTORE="/usr/sbin/ip6tables-restore"
IP="/sbin/ip"
IFCONFIG="/sbin/ifconfig"
VCONFIG="/sbin/vconfig"
BRCTL="/sbin/brctl"
IFENSLAVE="/sbin/ifenslave"
IPSET="/usr/sbin/ipset"
LOGGER="/usr/bin/logger"
log() {
echo "$1"
command -v "$LOGGER" >/dev/null 2>&1 && $LOGGER -p info "$1"
}
getInterfaceVarName() {
echo $1 | sed 's/\./_/'
}
getaddr_internal() {
dev=$1
name=$2
af=$3
L=$($IP $af addr show dev $dev | sed -n '/inet/{s!.*inet6* !!;s!/.*!!p}' | sed 's/peer.*//')
test -z "$L" && {
eval "$name=''"
return
}
eval "${name}_list=\"$L\""
}
getaddr() {
getaddr_internal $1 $2 "-4"
}
getaddr6() {
getaddr_internal $1 $2 "-6"
}
# function getinterfaces is used to process wildcard interfaces
getinterfaces() {
NAME=$1
$IP link show | grep ": $NAME" | while read L; do
OIFS=$IFS
IFS=" :"
set $L
IFS=$OIFS
echo $2
done
}
diff_intf() {
func=$1
list1=$2
list2=$3
cmd=$4
for intf in $list1
do
echo $list2 | grep -q $intf || {
# $vlan is absent in list 2
$func $intf $cmd
}
done
}
find_program() {
PGM=$1
command -v $PGM >/dev/null 2>&1 || {
echo "$PGM not found"
exit 1
}
}
check_tools() {
find_program $IPTABLES
find_program $MODPROBE
find_program $IP
}
reset_iptables_v4() {
$IPTABLES -P OUTPUT DROP
$IPTABLES -P INPUT DROP
$IPTABLES -P FORWARD DROP
cat /proc/net/ip_tables_names | while read table; do
$IPTABLES -t $table -L -n | while read c chain rest; do
if test "X$c" = "XChain" ; then
$IPTABLES -t $table -F $chain
fi
done
$IPTABLES -t $table -X
done
}
reset_iptables_v6() {
$IP6TABLES -P OUTPUT DROP
$IP6TABLES -P INPUT DROP
$IP6TABLES -P FORWARD DROP
cat /proc/net/ip6_tables_names | while read table; do
$IP6TABLES -t $table -L -n | while read c chain rest; do
if test "X$c" = "XChain" ; then
$IP6TABLES -t $table -F $chain
fi
done
$IP6TABLES -t $table -X
done
}
P2P_INTERFACE_WARNING=""
missing_address() {
address=$1
cmd=$2
oldIFS=$IFS
IFS="@"
set $address
addr=$1
interface=$2
IFS=$oldIFS
$IP addr show dev $interface | grep -q POINTOPOINT && {
test -z "$P2P_INTERFACE_WARNING" && echo "Warning: Can not update address of interface $interface. fwbuilder can not manage addresses of point-to-point interfaces yet"
P2P_INTERFACE_WARNING="yes"
return
}
test "$cmd" = "add" && {
echo "# Adding ip address: $interface $addr"
echo $addr | grep -q ':' && {
$FWBDEBUG $IP addr $cmd $addr dev $interface
} || {
$FWBDEBUG $IP addr $cmd $addr broadcast + dev $interface
}
}
test "$cmd" = "del" && {
echo "# Removing ip address: $interface $addr"
$FWBDEBUG $IP addr $cmd $addr dev $interface || exit 1
}
$FWBDEBUG $IP link set $interface up
}
list_addresses_by_scope() {
interface=$1
scope=$2
ignore_list=$3
$IP addr ls dev $interface | \
awk -v IGNORED="$ignore_list" -v SCOPE="$scope" \
'BEGIN {
split(IGNORED,ignored_arr);
for (a in ignored_arr) {ignored_dict[ignored_arr[a]]=1;}
}
(/inet |inet6 / && $0 ~ SCOPE && !($2 in ignored_dict)) {print $2;}' | \
while read addr; do
echo "${addr}@$interface"
done | sort
}
update_addresses_of_interface() {
ignore_list=$2
set $1
interface=$1
shift
FWB_ADDRS=$(
for addr in $*; do
echo "${addr}@$interface"
done | sort
)
CURRENT_ADDRS_ALL_SCOPES=""
CURRENT_ADDRS_GLOBAL_SCOPE=""
$IP link show dev $interface >/dev/null 2>&1 && {
CURRENT_ADDRS_ALL_SCOPES=$(list_addresses_by_scope $interface 'scope .*' "$ignore_list")
CURRENT_ADDRS_GLOBAL_SCOPE=$(list_addresses_by_scope $interface 'scope global' "$ignore_list")
} || {
echo "# Interface $interface does not exist"
# Stop the script if we are not in test mode
test -z "$FWBDEBUG" && exit 1
}
diff_intf missing_address "$FWB_ADDRS" "$CURRENT_ADDRS_ALL_SCOPES" add
diff_intf missing_address "$CURRENT_ADDRS_GLOBAL_SCOPE" "$FWB_ADDRS" del
}
clear_addresses_except_known_interfaces() {
$IP link show | sed 's/://g' | awk -v IGNORED="$*" \
'BEGIN {
split(IGNORED,ignored_arr);
for (a in ignored_arr) {ignored_dict[ignored_arr[a]]=1;}
}
(/state/ && !($2 in ignored_dict)) {print $2;}' | \
while read intf; do
echo "# Removing addresses not configured in fwbuilder from interface $intf"
$FWBDEBUG $IP addr flush dev $intf scope global
$FWBDEBUG $IP link set $intf down
done
}
check_file() {
test -r "$2" || {
echo "Can not find file $2 referenced by address table object $1"
exit 1
}
}
check_run_time_address_table_files() {
:
}
load_modules() {
:
OPTS=$1
MODULES_DIR="/lib/modules/`uname -r`/kernel/net/"
MODULES=$(find $MODULES_DIR -name '*conntrack*' \! -name '*ipv6*'|sed -e 's/^.*\///' -e 's/\([^\.]\)\..*/\1/')
echo $OPTS | grep -q nat && {
MODULES="$MODULES $(find $MODULES_DIR -name '*nat*'|sed -e 's/^.*\///' -e 's/\([^\.]\)\..*/\1/')"
}
echo $OPTS | grep -q ipv6 && {
MODULES="$MODULES $(find $MODULES_DIR -name nf_conntrack_ipv6|sed -e 's/^.*\///' -e 's/\([^\.]\)\..*/\1/')"
}
for module in $MODULES; do
if $LSMOD | grep ${module} >/dev/null; then continue; fi
$MODPROBE ${module} || exit 1
done
}
verify_interfaces() {
:
echo "Verifying interfaces: br0 br2 br3 br4 lo"
for i in br0 br2 br3 br4 lo ; do
$IP link show "$i" > /dev/null 2>&1 || {
log "Interface $i does not exist"
exit 1
}
done
}
prolog_commands() {
echo "Running prolog script"
}
epilog_commands() {
echo "Running epilog script"
}
run_epilog_and_exit() {
epilog_commands
exit $1
}
configure_interfaces() {
:
# Configure interfaces
update_addresses_of_interface "br0 172.16.0.x/24" ""
update_addresses_of_interface "br2 172.17.0.y/24" ""
update_addresses_of_interface "br3 192.168.0.x/24" ""
update_addresses_of_interface "lo 127.0.0.1/8" ""
}
script_body() {
# ================ IPv4
##############################################
##############################################
# #
# Regelwerk weggelassen #
# #
##############################################
##############################################
ip_forward() {
:
echo 1 > /proc/sys/net/ipv4/ip_forward
}
reset_all() {
:
reset_iptables_v4
}
block_action() {
reset_all
}
stop_action() {
reset_all
$IPTABLES -P OUTPUT ACCEPT
$IPTABLES -P INPUT ACCEPT
$IPTABLES -P FORWARD ACCEPT
}
check_iptables() {
IP_TABLES="$1"
[ ! -e $IP_TABLES ] && return 151
NF_TABLES=$(cat $IP_TABLES 2>/dev/null)
[ -z "$NF_TABLES" ] && return 152
return 0
}
status_action() {
check_iptables "/proc/net/ip_tables_names"
ret_ipv4=$?
check_iptables "/proc/net/ip6_tables_names"
ret_ipv6=$?
[ $ret_ipv4 -eq 0 -o $ret_ipv6 -eq 0 ] && return 0
[ $ret_ipv4 -eq 151 -o $ret_ipv6 -eq 151 ] && {
echo "iptables modules are not loaded"
}
[ $ret_ipv4 -eq 152 -o $ret_ipv6 -eq 152 ] && {
echo "Firewall is not configured"
}
exit 3
}
# See how we were called.
# For backwards compatibility missing argument is equivalent to 'start'
cmd=$1
test -z "$cmd" && {
cmd="start"
}
case "$cmd" in
start)
log "Activating firewall script by FWbuilder"
check_tools
prolog_commands
check_run_time_address_table_files
load_modules " "
configure_interfaces
verify_interfaces
reset_all
script_body
ip_forward
epilog_commands
RETVAL=$?
;;
stop)
stop_action
RETVAL=$?
;;
status)
status_action
RETVAL=$?
;;
block)
block_action
RETVAL=$?
;;
reload)
$0 stop
$0 start
RETVAL=$?
;;
interfaces)
configure_interfaces
RETVAL=$?
;;
test_interfaces)
FWBDEBUG="echo"
configure_interfaces
RETVAL=$?
;;
*)
echo "Usage $0 [start|stop|status|block|reload|interfaces|test_interfaces]"
;;
esac
exit $RETVAL
Bin für jede Hilfe Dankbar!!
Viele Grüße pkrix89
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 194082
Url: https://administrator.de/forum/stateful-inspection-mit-fwbuilder-und-iptables-194082.html
Ausgedruckt am: 25.04.2025 um 02:04 Uhr
1 Kommentar