#!/bin/bash # $Id: packetfilter,v 1.46 2003/02/19 22:32:58 aleks Exp $ # # Name: /usr/local/sbin/packetfilter # purpose: packetfilter for use@home # Author: Alexander Stielau # Codebase: nightmare.sailtraining.de ipchains for 2.2.x # Karl-Heinz Haag # # HOOK FOR STARTUP in /etc/ppp/ip-up.d/ # SEE ALSO: http://www.buug.de/~aleks/iptables # /usr/local/bin/restorefilter # /etc/firewall/fw-config # # GET ANNOUNCES FOR NEW FEATURES BY MAIL: # mail -s "subscribe shrekskripte" shrekskripte-request@buug.de < /dev/null # # cvs-changelog # $Log: packetfilter,v $ # Revision 1.46 2003/02/19 22:32:58 aleks # Falsches File eingecheckt... # # Revision 1.44 2003/02/19 22:01:41 aleks # GW_WORKSTATION für Alles -> internes Netz erweitert # # Revision 1.43 2003/01/30 20:10:09 aleks # Colins Patches eingespielt # # Revision 1.42 2002/05/23 17:35:28 aleks # Hinweis von Matthias Hölsche auf einen Fehler in Zeile 753 gefixt # # Revision 1.41 2002/03/20 22:50:32 aleks # Von jjfux gefundene Fiptehler eingearbeitet # # Revision 1.40 2002/02/25 23:38:58 aleks # - Idiot-Mode entfernt - nutzt eh keiner. # - -m unclean Regel auskommentiert - macht Ärger mit T-Online, zumindest # manchmal. Gründe sind noch /etwas/ unklar. # - einige größere redaktionelle am begleitenden Text # # Revision 1.39 2002/02/21 18:20:12 aleks # - diverse Fiptehler korrigiert # - eine hyperfluide SSH-Regel entfernt # - Die Fußschuss-Bremse wird nun wie in der Doku angekündigt durch TESTING=1 # getriggert und nicht durch DEBUG # # Revision 1.38 2002/02/18 23:14:52 aleks # - ein fi in Zeile 789 entfernt # # Revision 1.37 2002/02/17 21:07:04 aleks # - diverse Bugs zur Vorversion gefixt. # - all_gate hinter die transproxy-Regeln geschoben # - Regel für gesperrte Dienste vereinfacht # # Revision 1.36 2002/02/16 17:46:36 aleks # - Reject-Regel für übliche Windows-Protokolle und anderes, was man garantiert # nicht haben will, eingefügt (STOP_HERE). # - Eine sinnvolle Regelung für https gefunden. # - Dokumentation weiter ergänzt # # Revision 1.35 2002/02/10 17:43:17 aleks # Doku zum SSH-Tunnel durch ein Beispiel ergänzt, Doku zu APT-Feature # korrigiert. # # Revision 1.34 2002/02/09 22:31:47 aleks # Hinzufügung einer TCPMMS-Regel, um die MSS von TCP-SYN-Paketen auf einen # ungefährlichen Wert für krank konfigurierte Router bei DSL-Providern zu # setzen. # Scheinbar nicht notwendig, wenn man einen Proxy benutzt. Jedenfalls hatte ich # das Problem noch nie. Danke an Gunnar für den Tipp. # # Revision 1.33 2002/02/09 19:37:18 aleks # FTP/WWW-Freigabe für das Gateway selbst an die Variable APT gekoppelt. # (apt-get&Co direkt aus dem Netz) # # Revision 1.32 2002/02/01 00:49:09 aleks # Alle eigenen Chains entsprechend HOWTO auf lowercase gesetzt. # Doppelte Skizze entfernt. # # Revision 1.31 2002/01/29 23:27:46 aleks # Umstellung auf CVS-Log-IDs als Versionshistory. Mal sehen, wie das aussieht. # :-) # # # # Old changelog (major changes): # # 29.12.01 1.28 Debug-Level eingefügt, Policy-Änderung # 21.12.01 1.26 Spoofing-rules rewritten. # 15.12.01 1.18 switching to a separate config-file # 13.12.01 1.14 script will find device-defs for external and internal # net by itself. # Also network and netmask for the internal net # 12.12.01 1.12 fixes in rulebase, local loopback iface was wrong # named, causes in problems with rules which using this # iface. # Changed default for ALL_GATE, every outgoing traffic # from gate is accepted now. # # 12.12.01 1.5 niceing the comments # 11.12.01 1.4 New Versions, using CVS now # 11.12.01 3.2 IDIOT-Mode enabled. For Lusers which cannot read. # SET IDIOT=yes. More documentation # 10.12.01 3.1 NOW EXTENSIVE COMMENTING FOR UEBERLUSER # 17.07.01 3.0 changed back to my handmade rules # 15.07.01 2.6 switch kernel-console logging to 7 # 06.05.01 2.5 ssh-connection enabled # 06.05.01 2.4 new rule for spoofing-protection # 25.03.01 2.3 logging enabled :-) # 23.03.01 2.2 playing around with policies and logging # 17.03.01 2.1 logging of dropped packets, check for ppp0-Device # before running rule-creation # 17.03.01 2.0 complete rewriting for iptables 1.1.1. with Kernel # 2.4.2 and test # 14.03.01 1.1 minor enhancemends for variables-handling # 11.03.01 1.0 inital version for test # # ===================================================================== # # Dieses Skript dient eher der Betrachtung der Arbeitsweise von iptables. # Mehr als nur Logging-Rules ein- oder auszukommentieren erfordert etwas Wissen, # also behutsam vorgehen, wenn überhaupt. # # Die Variablen werden alle in /etc/firewall/fw-config gesetzt. # Und zwar alle! # # Hier mit wird die Datei eingelesen. Alle Variablen darin sind nun auch in # diesem File gültig. # . /etc/firewall/fw-config # # Das externe Interface wird gecheckt und bei Vorhandensein ausgelesen. # Dies funktioniert, wenn die Verbindung besteht, automatisch. # Ansonsten wird die Aktion komplett abgebrochen. # # Zur Kontrolle wird die IP ausgegeben. # # CHECK_EXT="`$IFCONFIG $EXT_IFACE 2>/dev/null`" # if [ "$CHECK_EXT" != "" -a $? -eq 0 ] ; then # EXT_IP="`$IFCONFIG $EXT_IFACE | $AWK '/inet addr:/ \ {print $2}'| $SED 's/addr://'`" $ECHO "Die IP-Nummer des externen Interfaces ist ${EXT_IP}" # else # switch off fw and warn. # $ECHO "W A R I N G - EXTERNAL IFACE CHECK FAILED" $ECHO "============================================" $ECHO "Filter will switched off now" /usr/local/sbin/restorefilter $ECHO "============================================" $ECHO "FILTER IS OFF NOW. Device ${EXT_IFACE} is unsecure!" $ECHO "============================================" exit 1 fi # # Das interne Interface wird gecheckt und bei Vorhandensein ausgelesen. # Ansonsten wird eine Fehlermeldung abgegeben, aber nicht abgebrochen. # Das externe Interface funktioniert ja. # # Die Bestimmung des internen Netzes funktioniert nur, wenn das externe # Interface die Defaultroute hat, und keine weiteren internen Netze # existieren, die am gleichen Interface hängen. Grund für diese Einschränkung # ist die relativ billig Art des Parsens an dieser Stelle. # # Zur Kontrolle wird die IP ausgegeben. # if [ "$LOC_NET_ENABLE" = "yes" ] ; then # # Check, ob das Interface vorhanden ist CHECK_LOC="`$IFCONFIG $LOC_IFACE 2>/dev/null`" # if [ "$CHECK_LOC" != "" -a $? -eq 0 ] ; then # LOC_IP # Nun wird die IP des internen Devices ausgelesen und ausgegeben. LOC_IP="`$IFCONFIG $LOC_IFACE | $AWK '/inet addr:/ \ {print $2}'| $SED 's/addr://'`" $ECHO "Die IP-Nummer des internen Interfaces ist ${LOC_IP}" # # LOC_NET LOC_NET="`$ROUTE -n | $GREP $LOC_IFACE | $GREP -v UG | \ $AWK '{print $1 "/" $3}'`" $ECHO "Das lokale Netz hat das Netz ${LOC_NET}" else # warning $ECHO "W A R I N G - INTERNAL IFACE CHECK FAILED" $ECHO "============================================" $ECHO "Filter will not work correctly for local net" $ECHO "============================================" fi # else $ECHO "Es ist kein lokales Netz definiert." fi # ########################################################### # # Erklärungen zu der iptables-Notation erfolgen im laufenden # Skript. Also weiterlesen. # ########################################################### # insert modules # ============== # Die folgenden Module werden benötigt, bitte Kernel (2.4.x) entsprechend # basteln. Wenn der Kernel monolithisch ist, einfach alles # auskommentieren. # # Zum Thema Module siehe auch Kernel-HOWTO. # $INSMOD ip_tables &> /dev/null $INSMOD ip_conntrack &> /dev/null $INSMOD ip_conntrack_ftp &> /dev/null $INSMOD ipt_state &> /dev/null $INSMOD iptable_nat &> /dev/null $INSMOD ipt_REJECT &> /dev/null $INSMOD ipt_MASQUERADE &> /dev/null $INSMOD ipt_tcpmss &> /dev/null # # switching kernel-console logging to 7 # ===================================== # Verhindert wirksam das Vollmüllen der Konsole mit Logging-Kram. # $ECHO "4 4 1 7"> /proc/sys/kernel/printk # # deactivate forwarding first # =========================== # Schaltet erstmal das Routing zwischen den Interfaces ab, bis # alle Regeln gesetzt sind. Wird am Ende des Skriptes wieder geändert. # # Auf einem Gateway sollte das Forwarding zwischen den Interfaces auf dem # distributionspezifischen Wege sowieso abgeschaltet sein. # $ECHO "0" > /proc/sys/net/ipv4/ip_forward # # flushing old rules; setting default-policy # ========================================== # Löschen der eventuell vorhandenen alten Regeln. # # Die Bedeutung der Optionen werden im Laufe des Skriptes erklärt. # Soviel vorab: # -F flush, löschen der Regeln einer Kette # -X delete, löschen der Kette selbst # das geht nur in dieser Reihenfolge, erst leere Ketten können # gelöscht werden. # Eine Kette (chain) ist eine Gruppe von Regeln, die unter einem Namen # zusammengefasst sind. Es gibt einige Standardchains - diese sind in # diesem Skript GROSS geschrieben, eigene Ketten sind klein # geschrieben. # -t table. Tabellen für z.B. filter, nat und mangle # -P Policy. Wenn keine Regel matcht, wird diese Defaultregel # genutzt. # $IPTABLES -F $IPTABLES -X $IPTABLES -F -t nat $IPTABLES -F -t mangle $IPTABLES -t nat -X $IPTABLES -t mangle -X if [ "$TESTING" = "0" ] ; then $IPTABLES -P INPUT DROP $IPTABLES -P FORWARD DROP $IPTABLES -P OUTPUT DROP else $IPTABLES -P INPUT ACCEPT $IPTABLES -P FORWARD ACCEPT $IPTABLES -P OUTPUT ACCEPT fi $IPTABLES -t nat -P PREROUTING ACCEPT $IPTABLES -t nat -P POSTROUTING ACCEPT # # # Setting new policies # ==================== # Alles, was nicht explizit erlaubt ist, wird verboten. # Sinnvoll, nicht nur für Paranoide. # # Hier funktioniert übrigens REJECT nicht. Um usenet(dcsf-faq)kompatibel # zu sein - also REJECT zu allen falschen Paketen - siehe letzte # Regel im Skript. # $IPTABLES -P INPUT DROP $IPTABLES -P OUTPUT DROP $IPTABLES -P FORWARD DROP # # ########################################################### # HERE WE GO! # =========== # # Generelles zur Syntax von iptables gibt es unter # http://www.netfilter.org/documentation/HOWTO/de/NAT-HOWTO.txt # # Ansonsten man iptables. Zum Nachsehen, was das alles soll. # # Wichtig zum Vergleich mit ipchains: Der Regellauf ist ein anderer: # Pakete, die nicht für den Router selbst bestimmt sind, werden nur # durch die FORWARD-Regel geschoben - den Router selbst betreffende # Pakete müssen durch INPUT bzw. OUTPUT. Siehe: # # Eingehend Ausgehend # ---> --PREROUTING--+--FORWARD--+--POSTROUTING-- ---> # | | # INPUT OUTPUT # | | # +-localhost-+ # # Das ist aus dem o.g. HOWTO, also LESEN, ist auf deutsch und gut # übersetzt. # # Die Regeln werden nach dem First-Match-Prinzip durchlaufen, # d. h., wenn eine Regel matcht, werden ab diesen Zeitpunkt nur noch # die Regeln durchlaufen, die zum Sprungziel der matchenden Regel # gehören. # # Es folgen diverse Regeln, um 'malicious' Pakete abzuwehren, wie # z.B. Scans oder absichtlich kaputte Pakete. # # -A appended eine neue Regel, die mit '-N Kettenname' eingeführt wird. # # Nochmal : Festeingebaute Ketten werden GROSS geschrieben (INPUT, OUTPUT, # FORWARD im wesentlichen), eigene Ketten werden klein geschrieben. # ########## WALLING & BLOCKING ############################# # # Erstmal alles plattmachen, was generell kaputt ist oder # Angriffsversuche darstellen könnte. # # kill irregular packets # $IPTABLES -N invalid $IPTABLES -A INPUT -m state --state INVALID -i ! $LOOP_IFACE -j invalid if [ "$LOC_NET_ENABLE" = "yes" ] ; then $IPTABLES -A FORWARD -m state --state INVALID -j invalid fi # unclean bereitet ab und zu im Zusammenhang mit T-Online (nicht nur?) # Probleme. Also erstmal raus, ist eh ein testing-feature. #$IPTABLES -A INPUT -m unclean -i ! $LOOP_IFACE -j invalid if [ "$DEBUG" = "1" ] ; then $IPTABLES -A invalid -j LOG --log-prefix "invalid " else $IPTABLES -A invalid -m limit -j LOG --log-prefix "invalid " fi $IPTABLES -A invalid -j REJECT # # Allgemein: # -m state definiert den Status eines Paketes, wie zum Beispiel, # ob es zu einer bestehenden Verbindung, zu einer neuen # Verbindung oder zu einer anderen Verbindung (z.B. ftp, # Datenkanal/Steuerkanal) gehört. Werte: Siehe manpage # -j ist ein Sprungziel. Pakete, die die vorhergehenden # Bedingungen erfüllen (ja, alles andere sind Bedingungen, # die geprüft werden, und alle zutreffen müssen), werden damit # an eine andere Kette übergeben und dort weiter verarbeitet. # Das können vordefinierte Ketten (INPUT, OUTPUT), oder auch # selbst definierte (-N) sein. # # LOG Das Sprungziel LOG verhält sich anders als die anderen # eingebauten Chains - nach dem Loggen (im Syslog # /var/log/messages) mit dem Logeintrag # --log-prefix "sowieso " wird das Paket wieder in die # Main-Regel übergeben. Also zum Loggen zwei Regeln, eine, die # loggt, eine die dann was macht. Wenn man sicher ist, das # alles geht, kann man dann das Logging auskommentieren. # Das Bauen von neuen Ketten begünstigt das Logging, # weil man für jede Kette einzeln loggen kann. # # Also bedeutet die obige Kette 'invalid' das folgende: # Alles, was in das System reinkommt (INPUT), dabei aber nicht vom Interface # lo (-i ! $LOOP_IFACE) sondern von allen anderen kommt und den Status # ungültig (-m state --state INVALID) hat, wird in die Kette 'invalid' # weitergeleitet. # Das gleiche wird auch mit Paketen gemacht, die nur geforwardet werden # sollen, wenn die Firewall mit einem lokalen Netz verbunden ist (if [ # "$LOC_NET_ENABLE" = "yes" ] ; then). # Je nach Debug-Level wird jedes Paket, daß die Kette invalid durchläuft # geloggt, oder nur jeweils die ersten drei in einer definierten Zeiteinheit # (-m limit). Nach dem Loggen werde die Pakete abgelehnt (-J REJECT). # # # scan-packets log and drop # block XMAS packets # $IPTABLES -N xmas $IPTABLES -A INPUT -p tcp --tcp-flags ALL ALL -j xmas if [ "$LOC_NET_ENABLE" = "yes" ] ; then $IPTABLES -A FORWARD -p tcp --tcp-flags ALL ALL -j xmas fi if [ "$DEBUG" = "1" ] ; then $IPTABLES -A xmas -j LOG --log-level info \ --log-prefix "xmas-scan " else $IPTABLES -A xmas -m limit -j LOG --log-level info \ --log-prefix "xmas-scan " fi $IPTABLES -A xmas -j REJECT # # -p beschreibt das Protokoll, das ist entweder tcp, udp oder icmp. # Wenn -p gesetzt ist, kann auch der Port (bei tcp/udp) # definiert werden, und dies als Source-(Quell-) und/oder # Destination-(Ziel-)Port. # Später kommen Beispiele, die Optionen heißen --sport, --dport # Die tcp-flags sind die das, was in der Literatur unter ACK-Bits # läuft, und die eine Verbindung starten, beenden, bestätigen usw. # # block NULL packets # $IPTABLES -N null_scan $IPTABLES -A INPUT -p tcp --tcp-flags ALL NONE -j null_scan if [ "$LOC_NET_ENABLE" = "yes" ] ; then $IPTABLES -A FORWARD -p tcp --tcp-flags ALL NONE -j null_scan fi if [ "$DEBUG" = "1" ] ; then $IPTABLES -A null_scan -j LOG --log-level info --log-prefix "null-scan " else $IPTABLES -A null_scan -m limit -j LOG --log-level info \ --log-prefix "null-scan " fi $IPTABLES -A null_scan -j REJECT # # spoofed packets log and drop # # Das ganze ist komplizierter, wenn es im lokalen Netz mehrere # unterschiedliche Netzbereiche gibt, die durch die Netzmaske des eigenen # Subnetzes nicht erfaßt werden. Die Spoofing-Regeln für das lokale Netz # funktionieren dann sehr kontraproduktiv. Für Home-Einsatz wird dies aber # nicht der Fall sein. # $IPTABLES -N spoofing if [ "$LOC_NET_ENABLE" = "yes" ] ; then $IPTABLES -A INPUT -i $LOC_IFACE -s ! $LOC_NET -j spoofing $IPTABLES -A FORWARD -i $LOC_IFACE -s ! $LOC_NET -j spoofing $IPTABLES -A FORWARD -i $EXT_IFACE -s 192.168.0.0/16 -j spoofing $IPTABLES -A FORWARD -i $EXT_IFACE -s 172.16.0.0/12 -j spoofing $IPTABLES -A FORWARD -i $EXT_IFACE -s 10.0.0.0/8 -j spoofing fi # # Wenn das externe Interface ein lokales Netz ist (z.B., wenn man seinen # Laptop in ein fremdes, privates Netz hängt und diesen davor schützen will, # braucht man spezielle Spoofing-Regeln. # (das ist ziemlich mit der Kneifzange gemacht): # SPOOF_CHECK1="`$ECHO $EXT_IP|$CUT -f 1,2 -d.`" SPOOF_CHECK2="`$ECHO $EXT_IP|$CUT -f 1 -d.`" # if [ "$SPOOF_CHECK1" = "192.168" ] ; then $IPTABLES -A INPUT -i $EXT_IFACE -s 172.16.0.0/12 -j spoofing $IPTABLES -A INPUT -i $EXT_IFACE -s 10.0.0.0/8 -j spoofing fi if [ "$SPOOF_CHECK1" = "172.16" ] ; then $IPTABLES -A INPUT -i $EXT_IFACE -s 10.0.0.0/8 -j spoofing $IPTABLES -A INPUT -i $EXT_IFACE -s 192.168.0.0/16 -j spoofing fi if [ "$SPOOF_CHECK2" = "10" ] ; then $IPTABLES -A INPUT -i $EXT_IFACE -s 172.16.0.0/12 -j spoofing $IPTABLES -A INPUT -i $EXT_IFACE -s 192.168.0.0/16 -j spoofing fi if [ "$DEBUG" = "1" ] ; then $IPTABLES -A spoofing -j LOG --log-level info \ --log-prefix "spoofing " else $IPTABLES -A spoofing -m limit -j LOG --log-level info \ --log-prefix "spoofing " fi $IPTABLES -A spoofing -j REJECT # # -i bezeichnet das Interface, über das die Daten in der Regel # reinkommen (incoming). Das Gegenteil wäre -o (outgoing). # ########## END WALLING & BLOCKING ######################### # # ########## CONNECTING & ADMITTING ######################### # # connect to the loopback # $IPTABLES -N lo_accept $IPTABLES -A INPUT -i $LOOP_IFACE -m state --state NEW -j lo_accept $IPTABLES -A OUTPUT -o $LOOP_IFACE -m state --state NEW -j lo_accept if [ "$DEBUG" = "1" ] ; then $IPTABLES -A lo_accept -j LOG --log-prefix "lo_accept " fi $IPTABLES -A lo_accept -j ACCEPT # icmp handling # # In der Literatur wird immer wieder darum gestritten, ob es sinnvoll ist, daß # ein im Netz hängender Rechner auf ICMP-Anfragen (z.B. ping) antwortet oder # nicht. # # Die Leute, die behaupten, daß ein Rechner, der nicht auf ICMP-Requests # antwortet, wäre sicherer, haben nicht begriffen, wozu ICMP dient: # # 1. Kann ein Rechner, der keine Services nach draußen anbietet, beim Einsatz # von aktueller Software nicht durch ICMP-Requests angegriffen werden. # 2. Wird ICMP genutzt, um Fehlermeldungen zu übertragen - diesen Mechanismus # sollte man nicht unterdrücken. # 3. Ist auch ein Rechner, der nicht auf ICMP-Requests reagiert, im Netz zu # orten. So etwas wie stealth gibt es nur in der Vorstellung von fertigen # Marketingdroids. # # Dieses Firewallskript antwortet also korrekt auf ICMP-Anfragen - mit einer # Ausnahme. ICMP type 5 (redirection) wird abgewiesen. In einem privaten # Dialup-Netz gibt es keine Instanz, die das Recht hätte, das Routing # verändern zu wollen. # $IPTABLES -N icmp_allow $IPTABLES -N icmp_reject $IPTABLES -A INPUT -p icmp --icmp-type ! 5 -j icmp_allow $IPTABLES -A INPUT -i $EXT_IFACE -p icmp --icmp-type 5 -m limit \ -j icmp_reject if [ "$DEBUG" = "1" ] ; then $IPTABLES -A icmp_allow -j LOG --log-prefix "icmp " fi $IPTABLES -A icmp_allow -j ACCEPT if [ "$DEBUG" = "1" ] ; then $IPTABLES -A icmp_reject -j LOG --log-prefix "icmp_rej " else $IPTABLES -A icmp_reject -m limit -j LOG --log-prefix "icmp_rej " fi $IPTABLES -A icmp_reject -j REJECT --reject-with icmp-host-unreachable # ######### REGULAR SERVICES ################################ # # Hier beginnen die regulären Regeln. Als erstes das, was das Gateway # selbst benötigt: DNS, bei Debian der Kram für APT, ICMP. # Weil es nur um das Gateway selbst geht, keine Forward-Regeln in diesem # Abschnitt. # ######### services for gate ############################### # allow pings from gate # $IPTABLES -N icmp_gate $IPTABLES -A OUTPUT -p icmp -j icmp_gate if [ "$DEBUG" = "1" ] ; then $IPTABLES -A icmp_gate -j LOG --log-prefix "icmp_gate_out " fi $IPTABLES -A icmp_gate -j ACCEPT # # allow ftp/www outgoing (for apt) # # Für Debian-Systeme zum Updaten und Einspielen von neuen Paketen direkt aus # dem Netz. Dies ist eventuell auch mit YOU (YaST Online Update) so nutzbar. # Vielleicht schickt mir mal jemand seine Erfahrungen mit YOU. if [ "$APT" = "yes" ] ; then $IPTABLES -N apt_gate $IPTABLES -A OUTPUT -p tcp --dport $FTP -s $EXT_IP -m state --state \ NEW -o $EXT_IFACE -j apt_gate $IPTABLES -A OUTPUT -p tcp --dport $WWW -s $EXT_IP -m state --state \ NEW -o $EXT_IFACE -j apt_gate if [ "$DEBUG" = "1" ] ; then $IPTABLES -A apt_gate -j LOG --log-prefix "apt_gate " fi $IPTABLES -A apt_gate -j ACCEPT fi # Wie angekündigt, hier nun eine explizite Nennung des Ports, der # erlaubt ist. Damit ist es möglich, die Regel wesentlich präziser zu # fassen. # # --dport Destinationport. Der Port, der dort, wo das Päckchen hin # soll, angesprochen wird. # --sport umgekehrt, also der Port, von dem das Päckchen kommt. # # Die Ports der üblichen Services sind in /etc/services gelistet. # # -o beschreibt das Device, auf dem das Paket rausgeht # -i beschreibt das Device, auf dem das Paket reinkommt. # NEW ist ein Status, der Pakete kennzeichnet, die eine # Verbindungsaufnahme wünschen. Die Regel trifft nur für # diese zu, Pakete, die zu einer bereits etablierten oder # zugehörigen Verbindung gehören, werden als generell # ungefährlich eingeschätzt und weiter unten unter # Generalamnestie gestellt. # Damit hat man beim Logging automagisch nur # Verbindungsanforderungen drin, was die Sache # übersichtlicher macht. # # get the time # # Um diese Regel zu nutzen, muß auf dem Gateway ein Programm laufen, daß sich # die Systemzeit von außen holt. Sehr zu empfehlen ist zu diesem Zweck chrony. # $IPTABLES -N ntp_gate $IPTABLES -A OUTPUT -p udp --dport $NTP -s $EXT_IP -m state --state \ NEW -o $EXT_IFACE -j ntp_gate if [ "$DEBUG" = "1" ] ; then $IPTABLES -A ntp_gate -j LOG --log-prefix "ntp_gate " fi $IPTABLES -A ntp_gate -j ACCEPT # # Wenn man paranoid ist, kann man natürlich die Timeserver hier genau # festnageln, in dem man eine -d(estination) festlegt. Genauso bei den folgenden # DNS-Regeln. Ist aber wohl für zuhause overkill. # # allow local dns-querys # $IPTABLES -N dns_gate $IPTABLES -A OUTPUT -p udp -o $EXT_IFACE --dport $DNS \ -m state --state NEW -j dns_gate if [ "$DEBUG" = "1" ] ; then $IPTABLES -A dns_gate -j LOG --log-prefix "dns_gate " fi $IPTABLES -A dns_gate -j ACCEPT # # allow gate ssh connections # $IPTABLES -N ssh_gate if [ "$SSH_FROM_OUTSIDE" = "yes" ] ; then $IPTABLES -A INPUT -p tcp -m state --state NEW -d $EXT_IP \ --dport $SSH -j ssh_gate fi $IPTABLES -A OUTPUT -p tcp -m state --state NEW \ --dport $SSH -j ssh_gate if [ "$LOC_NET_ENABLE" = "yes" ] ; then $IPTABLES -A INPUT -p tcp -m state --state NEW -s $LOC_NET \ --dport $SSH -d $LOC_IP -j ssh_gate fi if [ "$DEBUG" = "1" ] ; then $IPTABLES -A ssh_gate -j LOG --log-prefix "ssh_gate " fi $IPTABLES -A ssh_gate -j ACCEPT # allow gate smtp connections to outside # $IPTABLES -N smtp_gate $IPTABLES -A OUTPUT -p tcp -o $EXT_IFACE -m state --state NEW \ --dport $SMTP -j smtp_gate if [ "$LOC_NET_ENABLE" = "yes" ] ; then $IPTABLES -A OUTPUT -p tcp -o $LOC_IFACE -m state --state NEW \ --dport $SMTP -d $LOC_NET -j smtp_gate fi if [ "$DEBUG" = "1" ] ; then $IPTABLES -A smtp_gate -j LOG --log-prefix "smtp_gate " fi $IPTABLES -A smtp_gate -j ACCEPT ########## services for gate end ######################### # ########## services to/from localnet ##################### # # Hier würde man jetzt für ein richtiges Netz festlegen, # was alles erlaubt ist. Zuhause sage ich aber, alles, was von innen # kommt, ist erlaubt. # # Und das lokale Netz ist bei mir mit einer Ausnahme von aussen nicht # zu erreichen. Wer das will, kann sich ja über die obigen ssh-Regeln # reintunneln. # # nating/masquerading of outgoing packets only from $LOC_NET # if [ "$LOC_NET_ENABLE" = "yes" ] ; then $IPTABLES -t nat -A POSTROUTING -o $EXT_IFACE -s $LOC_NET -j SNAT \ --to-source $EXT_IP fi # # Das ist eine sehr wichtige Regel, mit der der gesamte lokale Traffic # nach außen maskiert wird. # -t nat ist eine neue Form, die nun volles NAT macht (im # Gegensatz zu ipchains, das nur MASQ konnte). # Das hier ist allerdings nur MASQ, alles aus dem lokalen # Netzwerk wird auf die IP des exteren Interfaces gemappt. # POSTROUTING/PREROUTING bestimmt den Zeitpunkt, wann genattet # wird, beim MASQ will man das nach dem Routing. Will man die # Zieladresse ändern, macht man dies vor dem Routing, damit die # richtige Routing-Entscheidung getroffen werden kann. # -j SNAT ist also Soure-Network-Address-Translation, die # Quell-IP des Paketes wird umgewandelt. Beim DNAT (also # Destination-NAT) wird entsprechend die Zieladresse manipuliert. # --to-source gibt die neue Quelladresse an. Beim DNAT kann man # da auch noch den gewünschten Zielport angeben. # # MTU-Spielchen # if [ "$LOC_NET_ENABLE" = "yes" ] ; then $IPTABLES -I FORWARD -p tcp --tcp-flags SYN,RST SYN \ -j TCPMSS --clamp-mss-to-pmtu fi # # Mit dieser eher obskuren Option werden die MSS-Werte von TCP-SYN-Paketen auf # einen für krank konfigurierte Router brauchbaren Wert gesetzt. # # Dazu aus der Kernel-Doku: # TCPMSS target support # CONFIG_IP_NF_TARGET_TCPMSS # This option adds a `TCPMSS' target, which allows you to alter the # MSS value of TCP SYN packets, to control the maximum size for that # connection (usually limiting it to your outgoing interface's MTU # minus 40). # # This is used to overcome criminally braindead ISPs or servers which # block ICMP Fragmentation Needed packets. The symptoms of this # problem are that everything works fine from your Linux # firewall/router, but machines behind it can never exchange large # packets: # 1) Web browsers connect, then hang with no data received. # 2) Small mail works fine, but large emails hang. # 3) ssh works fine, but scp hangs after initial handshaking. # # Workaround: activate this option and add a rule to your firewall # configuration like: # # iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \ # -j TCPMSS --clamp-mss-to-pmtu # # PORTFORWARDING # ============== # Ich erlaube es mir, auf dem Port 21 (eigentlich FTP) meiner Firewall ssh # nach innen zu tunneln und damit direkt auf meinem Server im internen Netz # anzukommen: # if [ "$SSH_TUNNEL_ALLOW" = "yes" ] ; then $IPTABLES -t nat -A PREROUTING -i $EXT_IFACE -p tcp --dport $FTP \ -d $EXT_IP -j DNAT --to-destination $SSH_TUNNEL_TO:$SSH $IPTABLES -A FORWARD -p tcp --dport $SSH -d $SSH_TUNNEL_TO -i $EXT_IFACE \ -o $LOC_IFACE -j ACCEPT fi # # Der passende ssh-Befehl ist in der Datei fw-config zu finden. # # TRANSPROXY # ========== # Wer einen transparenten Proxy für das interne Netz einsetzen will, # fügt noch die folgende Regel ein, dann müssen alle internen User, die http # nutzen, über den Squid auf dem Gateway und brauchen das auch nicht einzustellen. # Die Konfiguration des Proxies kann hier nachgelesen werden. # http://www.linuxdoc.org/HOWTO/mini/TransparentProxy-4.html # # Nur einkommentieren, wenn man einen Squid entsprechend konfiguriert # hat. Sonst ist das Web am Arsch! # # Auf Grund der verwendeten PREROUTING-Regel funktioniert das nur für # Rechner aus dem lokalen Netz, nicht aber für den Gatewayrechner selbst. # Wie das auch noch geht, ist im obigen HOWTO (oder aber in der # Squid-FAQ, ich habs vergessen) beschrieben. # # Ebenso funktionieren die untigen Regeln nicht, wenn der Squid auf einer # anderen Maschine als dem Gateway liegt. # # ACHTUNG: Bei Galeon reicht dies nicht aus, da er die DNS-Auflösung # selbst machen will. Kaputtes Teil. Workaround gibts später mal. # # https über einen transparenten Proxy ist nicht möglich, weil der # Proxy dann eine man-in-the-middle Instanz wäre - das Protokoll ist dafür aus # Sicherheitsgründen nicht geeignet. # SSL-Verbindungen werden einfach geforwardet. # if [ "$USE_TRANSPROXY" = "yes" ] ; then $IPTABLES -t nat -A PREROUTING -i $LOC_IFACE -j DNAT -p tcp \ --dport $WWW --to-destination $LOC_IP:$SQUID $IPTABLES -N transproxy $IPTABLES -A INPUT -i $LOC_IFACE -s $LOC_NET -p tcp --dport $WWWS \ -m state --state NEW -j transproxy if [ "$APT" = "no" ] ; then $IPTABLES -A OUTPUT -o $EXT_IFACE -p tcp --dport $WWWS \ -m state --state NEW -j transproxy fi $IPTABLES -A FORWARD -i $LOC_IFACE -s $LOC_NET -p tcp --dport $WWWS \ -o $EXT_IFACE -m state --state NEW -j transproxy if [ "$APT" = "no" ] ; then $IPTABLES -A OUTPUT -o $EXT_IFACE -p tcp --dport $WWW \ -m state --state NEW -j transproxy fi if [ "$DEBUG" = "1" ] ; then $IPTABLES -A transproxy -j LOG --log-prefix "TRANSP " fi $IPTABLES -A transproxy -j ACCEPT fi # # allow gate everything to the outside # (courtesy to Ueberluser) # # Okay, wer auf dem Gateway direkt arbeiten möchte, will auch # von dort ins Netz und nicht nur die obigen mikrigen Dienste # nutzen. Hier mit werden alle Tore (bis auf $STOP_HERE) vom Filtersystem # in das interne Netz und nach außen auf dem Gateway geöffnet. # Wer das nicht tun möchte, weil er sowieso nicht auf dem Gateway selbst # arbeitet, setzt in /etc/firewall/fw-config $GW_WORKSTAT auf "no", damit # wird aller Traffic vom Gateway nach außen, der nicht oben explizit # erlaubt ist, verboten und geloggt. # # all_gate ist nun nach der Transproxy-Chain angesiedelt, weil sonst bei # $GW_WORKSTAT=no die Transproxy-Chain nicht mehr zum Zuge kommen würde. # $IPTABLES -N all_gate $IPTABLES -A OUTPUT -o $EXT_IFACE -m state --state NEW \ -j all_gate if [ "$GW_WORKSTAT" = "yes" ] ; then if [ "$LOC_NET_ENABLE" = "yes" ] ; then for SERVICE in $STOP_HERE do for DIREC in $SD_PORT do $IPTABLES -A OUTPUT -p tcp $DIREC $SERVICE \ -m state --state NEW -j REJECT --reject-with tcp-reset $IPTABLES -A OUTPUT -p udp $DIREC $SERVICE \ -m state --state NEW -j REJECT done done $IPTABLES -A OUTPUT -o $LOC_IFACE -m state --state NEW \ -j all_gate fi if [ "$DEBUG" = "1" ] ; then $IPTABLES -A all_gate -j LOG --log-prefix "all_gate " fi $IPTABLES -A all_gate -j ACCEPT else if [ "$DEBUG" = "1" ] ; then $IPTABLES -A all_gate -j LOG --log-prefix "all_gate_rej " else $IPTABLES -A all_gate -m limit -j LOG --log-prefix "all_gate_rej " fi $IPTABLES -A all_gate -j REJECT fi # # Allow all outbound traffic from local net. # # alles andere aus dem lokalen Netz wird einfach mal so erlaubt. # Wenn nicht, muß jeder einzelne Dienst freigegeben werden. # Zuhause wäre dies imho Quark und kostet viel Zeit. # # Falls es Windowskisten im Netz gibt, werden die üblichen Verdächtigen von # vornherein rejected, erstens, um die Daten zu schützen, und zweitens, um das # Logfille zu schützen. Ebenso mit portmapper, bootp, telnet usw. # Weitere Dienste, die gesperrt werden sollen, können in fw-config unter # $STOP_HERE eingetragen werden. # # if [ "$LOC_NET_ENABLE" = "yes" ] ; then for SERVICE in $STOP_HERE do for DIREC in $SD_PORT do $IPTABLES -A INPUT -p tcp $DIREC $SERVICE -j REJECT --reject-with tcp-reset $IPTABLES -A FORWARD -p tcp $DIREC $SERVICE -j REJECT --reject-with tcp-reset $IPTABLES -A INPUT -p udp $DIREC $SERVICE -j REJECT $IPTABLES -A FORWARD -p udp $DIREC $SERVICE -j REJECT done done # Die folgende Konstruktion ergibt in diesem Zustand noch nicht besonders # viel Sinn - mal abgesehen davon, daß dadurch der Traffic aus dem lokalen # Netz nach draußen und auf das Gateway extra geloggt wird. $IPTABLES -N locnet_out $IPTABLES -A INPUT -s $LOC_NET -i $LOC_IFACE -m state \ --state NEW -j locnet_out $IPTABLES -A FORWARD -s $LOC_NET -i $LOC_IFACE -o $EXT_IFACE \ -m state --state NEW -j locnet_out if [ "$DEBUG" = "1" ] ; then $IPTABLES -A locnet_out -j LOG --log-prefix "locnet_o " fi $IPTABLES -A locnet_out -j ACCEPT fi # ########################################################## # allow all for established connections # # Wie schon oben beschrieben - alles, was zu einer bereits bestehenden # Verbindung gehört, wird erlaubt. # $IPTABLES -A INPUT -m state --state ESTABLISHED -j ACCEPT $IPTABLES -A INPUT -m state --state RELATED -j ACCEPT $IPTABLES -A OUTPUT -m state --state ESTABLISHED -j ACCEPT $IPTABLES -A OUTPUT -m state --state RELATED -j ACCEPT if [ "$LOC_NET_ENABLE" = "yes" ] ; then $IPTABLES -A FORWARD -m state --state ESTABLISHED -j ACCEPT $IPTABLES -A FORWARD -m state --state RELATED -j ACCEPT fi # ######### END CONNECTING & ADMITTING ##################### # # Hier folgen die letzten Regeln. # Alles, was noch nicht gematcht hat, wird hier geloggt, um entweder # zu sterben[TM], oder um das Skript zu verbessern, bis es tierisch # den Arsch wegregelt. # # The final rules (logging for debugging) # if [ "$DEBUG" = "1" ] ; then $IPTABLES -A INPUT -j LOG --log-prefix "FINAL IN " $IPTABLES -A OUTPUT -j LOG --log-prefix "FINAL OUT " $IPTABLES -A FORWARD -j LOG --log-prefix "FINAL FOR " else $IPTABLES -A INPUT -m limit -j LOG --log-prefix "FINAL IN " $IPTABLES -A OUTPUT -m limit -j LOG --log-prefix "FINAL OUT " $IPTABLES -A FORWARD -m limit -j LOG --log-prefix "FINAL FOR " fi $IPTABLES -A INPUT -p tcp -j REJECT --reject-with tcp-reset $IPTABLES -A OUTPUT -p tcp -j REJECT --reject-with tcp-reset $IPTABLES -A FORWARD -p tcp -j REJECT --reject-with tcp-reset $IPTABLES -A INPUT -j REJECT $IPTABLES -A OUTPUT -j REJECT $IPTABLES -A FORWARD -j REJECT # ########################################################### # # Das Forwarding und damit das Routing zwischen den Devices wird # eingeschaltet, nachdem alle Regeln gesetzt sind. # if [ "$LOC_NET_ENABLE" = "yes" ] ; then $ECHO "1" > /proc/sys/net/ipv4/ip_forward fi $ECHO "1" > /proc/sys/net/ipv4/conf/all/proxy_arp # # Spoof protection by JVT if [ -e /proc/sys/net/ipv4/conf/all/rp_filter ] ; then $ECHO -n "Setting up IP spoofing protection..." for f in /proc/sys/net/ipv4/conf/*/rp_filter; do $ECHO 1 > $f done $ECHO "done." else $ECHO "PROBLEMS SETTING UP IP SPOOFING PROTECTION. BE WORRIED." fi # # Es folgt die Auswertung gegen den Remote-Knieschuss. # if [ "$TESTING" = "1" ] ; then if [ "$BACKSECONDS" != "0" ] ; then # switch off rules $ECHO "W A R N I N G - FILTER ONLY IN TESTMODE !!!" $ECHO "============================================" $ECHO "Filter will be switched of again in ${BACKSECONDS}s" sleep $BACKSECONDS /usr/local/sbin/restorefilter $ECHO "===========================================" $ECHO "FILTER IS OFF NOW. Device ${EXT_IFACE} is unsecure!" $ECHO "===========================================" fi fi # for debugging purposes: Print all rules after setting. # # Es scrollen alle Regeln durch. Sieht nett aus und dient dem # Kapieren von dem, was man da gerade gemacht hat. # if [ "$DEBUG" = "1" ] ; then $IPTABLES -L -n -x -v $IPTABLES -L -t nat -n fi # mail me the ip # # Sehr witzige Sache für Flaträter. So weiß man immer die IP, wenn # sich die Kiste zuhause automagisch einwählt. # Schöner ist es, wenn man eine entsprechende Webseite irgendwo hoch kopiert, # mit scp oder so. Wenn das jemand realisiert, bitte an mich. # if [ "$MAIL_IP" = "yes" ] ; then #Mailen der IP an eine definierte Adresse für remote-login /usr/bin/mail -s "home_ip $EXT_IP" "$MAIL_TO" < /dev/null fi exit 0