#!/bin/bash ################################################################################ # # # " K I S S M y F i r e w a l l " # # e t i t # # e m u # # p p p # # l i # # e d # # --------------------------------- # # iptables for a typical web server # # # ################################################################################ # # # Version: 1.4 # # License: Public Domain # # Disclaimer: USE IT AT YOUR OWN RISK! # # Official Site: http://www.geocities.com/steve93138 # # Suggestions / Comments: steve93138@yahoo.com # # # ################################################################################ # # # version 2.0 Release Notes: * Modified by ray@oneunified.net # # * http://www.oneunified.net # # * configured for transit server # # # Version 1.4 Release Notes: * Added $IPTABLES variable. # # * Put all "-j ACCEPT" parameters at the end # # of each iptables command. # # * Added lines for outgoing traceroutes. You # # need to uncomment the lines in order for # # this to work. # # # # Version 1.3 Release Notes: * Added support for whois lookups. # # # # Version 1.2 Release Notes: * Added support for multiple SUBNET_BASE & # # SUBNET_BROADCAST addresses. # # # # Version 1.1 Release Notes: * Allowed access to external nameservers. # # * Allowed outgoing ping. # # * Fixed problems with outgoing services. # # * Fixed problem with sending email. # # * Minor optimizations & improvements. # # * Tested with Ensim WEBppliance. # # # # Version 1.0: * Initial release. # # # ################################################################################ # # # # # After much frustration with third party firewalls, I decided to create my # # own iptables script and place it in the public domain. Everything is # # contained within this one file and can be easily modified. Blocking one or # # more IP addresses is simple and changes take effect by simply restarting # # this script. # # # # KISS My Firewall was built from the ground up using information from many # # sources found on the web as well as from the book, "Linux Firewalls - Second # # Edition". It incorporates stateful packet inspection and also contains some # # preventative measures for port scanning, DoS attacks, and IP spoofing, among # # other things. While I am no expert, I hope that by placing this in the # # public domain, it can be improved upon and shared. # # # # This script is designed for a typical web server running services on # # standard ports. By default, the following ports are open on the INPUT chain: # # # # FTP, SSH, SMTP, DNS, HTTP, POP3, IMAP, and HTTPS. # # # # Open ports on the OUTPUT chain include: # # # # FTP, SSH, SMTP, WHOIS, DNS, HTTP, HTTPS. # # # # KISS My Firewall can be configured to work with *any* other port including # # those used by Ensim WEBppliance, Plesk, Secure IMAP, and Secure POP3. Note # # that passive FTP connections are permitted through this firewall. Since KISS # # My Firewall uses 'ip_conntrack_ftp' for tracking FTP connections, it does # # not need to explicitly open all of the unprivileged ports for passive mode # # FTP or port 20 for active mode FTP. This makes your server much more secure! # # # # For faster FTP connections, KISS My Firewall explicitly REJECTS port 113 # # (inetd). The default OUTPUT policy of DROP is what produces the long delay # # before an inbound FTP connection is accepted. # # # # This scripts assumes that only one ethernet connection ("eth0") is used and # # that it is your external Internet connection. There are only 5 variables # # that need to be configured. # # # # # # ############################################################################ # # # # ***** WARNING! ***** WARNING! ***** WARNING! ***** WARNING! ***** WARNING! * # # **** WARNING! ***** WARNING! ***** WARNING! ***** WARNING! ***** WARNING! ** # # *** WARNING! ***** WARNING! ***** WARNING! ***** WARNING! ***** WARNING! *** # # ** WARNING! ***** WARNING! ***** WARNING! ***** WARNING! ***** WARNING! **** # # * WARNING! ***** WARNING! ***** WARNING! ***** WARNING! ***** WARNING! ***** # # # # __________________________________________________________________________ # # # # DO NOT ISSUE AN "iptables --flush" COMMAND OR YOU WILL LOCK YOURSELF OUT!! # # __________________________________________________________________________ # # # # # # If you flush iptables after running this script, you will lock yourself out. # # The reason for this is that the default policy of DROP will still be in # # effect and no one will be able to access your box except someone with # # console (i.e. physical) access. If you do lock yourself out of your box, a # # hard reboot may be the only way to get back in. # # # # Golden iptables rule: DON'T ISSUE IPTABLES COMMANDS ON THE COMMAND LINE. # # # # If you follow this rule, then you know that to disable iptables safely, you # # should create a script. Here's one that you can use with KISS My Firewall: # # # # /sbin/iptables -P INPUT ACCEPT # # /sbin/iptables -P OUTPUT ACCEPT # # /sbin/iptables -F # # # # ############################################################################ # # # # CONSIDER YOURSELF WARNED! # # # ################################################################################ ################################################################################ # # # CONFIGURATION: # # # # There are only 5 variables that need configuring. They are: # # # # 1. SERVER_IPS # # 2. SUBNET_BASE # # 3. SUBNET_BROADCAST # # 4. BLOCK_LIST # # 5. ADDITIONAL_PORTS # # # # NOTE: You must configure these 5 variables properly. If you don't, you might # # lock yourself out of your server! # # # ################################################################################ ################################################################################ # # # CONFIG #1 (of 5): SERVER_IPS # # # # You need to include at least your main IP address here. If you are hosting # # any IP-BASED sites, you MUST include the additional IP's in this variable. # # Failure to do this will result in your client not being able to log into # # their site via FTP among other things. So make sure you include this here! # # And don't forget to put "modification of this file" on your To-Do list when # # you add a new IP-BASED site. # # # # NOTE: Additional IP's can be added with a space in the string: # # Ex. SERVER_IPS="192.168.1.33 192.168.1.47" # # # # P.S. Yes, it is possible to write some code to automatically determine which # # IP's are on the machine already. But keep in mind that this script would # # have to be restarted for it to take effect anyway. Perhaps you could find a # # way around that as well... # # # ################################################################################ SERVER_IPS="" ################################################################################ # # # CONFIG #2 (of 5): SUBNET_BASE # # # # This variable holds the base address(es) of your subnet(s). This is usually # # equal to your main IP address with a ".0" at the end. # # # # NOTE: More than one IP can be specified by separating with a space: # # Ex. SUBNET_BASE="10.42.23.0 192.168.1.0" # # # # xxx.xxx.xxx.0 # # # ################################################################################ SUBNET_BASE="" ################################################################################ # # # CONFIG #3 (of 5): SUBNET_BROADCAST # # # # This variable holds the broadcast address(es) of your subnet(s). This is # # usually equal to your main IP address with a ".255" at the end. # # # # NOTE: More than one IP can be specified by separating with a space: # # Ex. SUBNET_BROADCAST="10.42.23.255 192.168.1.255" # # # # xxx.xxx.xxx.255 # # # ################################################################################ SUBNET_BROADCAST="" ################################################################################ # # # CONFIG #4 (of 5): BLOCK_LIST # # # # This is where you can specify IP Addresses that you wish to block. If you # # add a new one, simply restart this script for the changes to take effect. # # # # NOTE: More than one IP can be specified by separating with a space: # # Ex. BLOCK_LIST="192.168.1.33 192.168.1.47" # # # ################################################################################ BLOCK_LIST="" ################################################################################ # # # CONFIG #5 (of 5): ADDITIONAL_PORTS # # # # This is where you can specify any additional ports that you like to have # # open. Here's some examples: # # # # 465 - Secure SMTP # # 993 - Secure IMAP # # 995 - Secure POP3 # # 3306 - Remote MySQL Access # # 8443 - Plesk # # 10000 - Webmin # # 19638 - Ensim WEBppliance # # # # NOTE: More than one Port can be specified by separating with a space: # # Ex. ADDITIONAL_PORTS="19638" # # # ################################################################################ ADDITIONAL_PORTS="" ################################################################################ # Primary Interface to be protected, typically the outside/public interface ProtectInterface="eth0" # Interfaces which do not require protection, typically all internal interfaces UnProtectInterfaces="" ################################################################################ ################################################################################ # # # ALL DONE WITH CONFIGURATIONS! # # # ################################################################################ IPTABLES="/sbin/iptables" # May need to be changed to: IPTABLES="/usr/local/sbin/iptables" LOOPBACK="127.0.0.0/8" CLASS_A="10.0.0.0/8" CLASS_B="172.16.0.0/12" CLASS_C="192.168.0.0/16" CLASS_D_MULTICAST="224.0.0.0/4" CLASS_E_RESERVED_NET="240.0.0.0/5" BROADCAST_SRC="0.0.0.0" BROADCAST_DEST="255.255.255.255" PRIVPORTS="0:1023" UNPRIVPORTS="1024:65535" ################################################################################ /sbin/modprobe ip_conntrack_ftp ################################################################################ # Remove any existing rules from all chains $IPTABLES --flush $IPTABLES -t nat --flush $IPTABLES -t mangle --flush # Allow unlimited traffic on the loopback interface $IPTABLES -A INPUT -i lo -j ACCEPT $IPTABLES -A OUTPUT -o lo -j ACCEPT # Set the default policy to DROP $IPTABLES --policy INPUT DROP $IPTABLES --policy OUTPUT DROP $IPTABLES --policy FORWARD DROP # DO NOT MODIFY THESE! # # If you set these to DROP, you will be locked out of your server. # $IPTABLES -t nat --policy PREROUTING ACCEPT $IPTABLES -t nat --policy OUTPUT ACCEPT $IPTABLES -t nat --policy POSTROUTING ACCEPT $IPTABLES -t mangle --policy PREROUTING ACCEPT $IPTABLES -t mangle --policy OUTPUT ACCEPT # Remove any pre-existing user-defined chains $IPTABLES --delete-chain $IPTABLES -t nat --delete-chain $IPTABLES -t mangle --delete-chain ################################################################################ # Enable broadcast echo Protection echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts # Disable Source Routed Packets echo "0" > /proc/sys/net/ipv4/conf/all/accept_source_route # Enable TCP SYN Cookie Protection echo "1" > /proc/sys/net/ipv4/tcp_syncookies # Disable ICMP Redirect Acceptance echo "0" > /proc/sys/net/ipv4/conf/all/accept_redirects # Don't send Redirect Messages # IS THIS SAFE ON A WEB SERVER ??? echo "0" > /proc/sys/net/ipv4/conf/all/send_redirects # Drop Spoofed Packets coming in on an interface, which if replied to, would # result in the reply going out a different interface. echo "1" > /proc/sys/net/ipv4/conf/all/rp_filter # Log packets with impossible addresses echo "1" > /proc/sys/net/ipv4/conf/all/log_martians # Reduce DoS'ing ability by reducing timeouts echo "30" > /proc/sys/net/ipv4/tcp_fin_timeout echo "2400" > /proc/sys/net/ipv4/tcp_keepalive_time echo "0" > /proc/sys/net/ipv4/tcp_window_scaling echo "0" > /proc/sys/net/ipv4/tcp_sack ################################################################################ # Silently Drop Stealth Scans # All of the bits are cleared $IPTABLES -A INPUT -p tcp --tcp-flags ALL NONE -j DROP # SYN and FIN are both set $IPTABLES -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP # SYN and RST are both set $IPTABLES -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j DROP # FIN and RST are both set $IPTABLES -A INPUT -p tcp --tcp-flags FIN,RST FIN,RST -j DROP # FIN is the only bit set, without the expected accompanying ACK $IPTABLES -A INPUT -p tcp --tcp-flags ACK,FIN FIN -j DROP # PSH is the only bit set, without the expected accompanying ACK $IPTABLES -A INPUT -p tcp --tcp-flags ACK,PSH PSH -j DROP # URG is the only bit set, without the expected accompanying ACK $IPTABLES -A INPUT -p tcp --tcp-flags ACK,URG URG -j DROP ################################################################################ # Provide some syn-flood protection # # THIS CODE SLOWS DOWN WEB PAGE LOADS DRAMATICALLY!!! # # Only enable this code if you find that you are the victim of a syn-flood # attack! # #$IPTABLES -N syn-flood #$IPTABLES -A INPUT -p tcp --syn -j syn-flood #$IPTABLES -A syn-flood -m limit --limit 1/s --limit-burst 4 -j RETURN #$IPTABLES -A syn-flood -j DROP ################################################################################ # BLOCK_LIST # # To add someone to this block list, use the BLOCK_LIST configuration variable # above. # # We block here, before our stateful packet inspection below, because if the # offender is already logged in, he won't be kicked out. Note also that we # include the offender's IP in the OUTPUT chain. This should help to reduce the # threat a little bit more. # for blocked_ip in $BLOCK_LIST; do # Lock him out: $IPTABLES -A INPUT -s $blocked_ip -j DROP # Make sure that he never hears from us again: $IPTABLES -A OUTPUT -d $blocked_ip -j DROP done ################################################################################ # Use Connection State to Bypass Rule Checking # # By accepting established and related connections, we don't need to explicitly # set various input and output rules. For example, by accepting an established # and related output connection, we don't need to specify that the firewall # needs to open a hole back out to client when the client requests SSH access. # $IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT $IPTABLES -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT $IPTABLES -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT $IPTABLES -A INPUT -m state --state INVALID -j DROP $IPTABLES -A OUTPUT -m state --state INVALID -j DROP $IPTABLES -A FORWARD -i $ProtectInterface -m state --state INVALID -j DROP ################################################################################ # Source Address Spoofing and Other Bad Addresses # Refuse Spoofed packets pretending to be from the external interface's IP for server_ips in $SERVER_IPS; do $IPTABLES -A INPUT -i $ProtectInterface -s $server_ips -j DROP done # Refuse packets claiming to be from a Class A private network $IPTABLES -A INPUT -i $ProtectInterface -s $CLASS_A -j DROP # Refuse packets claiming to be from a Class B private network $IPTABLES -A INPUT -i $ProtectInterface -s $CLASS_B -j DROP # Refuse packets claiming to be from a Class C private network $IPTABLES -A INPUT -i $ProtectInterface -s $CLASS_C -j DROP # Refuse packets claiming to be from the loopback interface $IPTABLES -A INPUT -i $ProtectInterface -s $LOOPBACK -j DROP # Refuse malformed broadcast packets $IPTABLES -A INPUT -i $ProtectInterface -s $BROADCAST_DEST -j DROP $IPTABLES -A INPUT -i $ProtectInterface -d $BROADCAST_SRC -j DROP # Refuse directed broadcasts # Used to map networks and in Denial of Service attacks for subnet_base in $SUBNET_BASE; do $IPTABLES -A INPUT -i $ProtectInterface -d $subnet_base -j DROP done for subnet_broadcast in $SUBNET_BROADCAST; do $IPTABLES -A INPUT -i $ProtectInterface -d $subnet_broadcast -j DROP done # Refuse limited broadcasts $IPTABLES -A INPUT -i $ProtectInterface -d $BROADCAST_DEST -j DROP # Refuse Class D multicast addresses - illegal as a source address $IPTABLES -A INPUT -i $ProtectInterface -s $CLASS_D_MULTICAST -j DROP $IPTABLES -A INPUT -i $ProtectInterface -p ! udp -d $CLASS_D_MULTICAST -j DROP $IPTABLES -A INPUT -i $ProtectInterface -p udp -d $CLASS_D_MULTICAST -j ACCEPT # Refuse Class E reserved IP addresses $IPTABLES -A INPUT -i $ProtectInterface -s $CLASS_E_RESERVED_NET -j DROP # Refuse addresses defined as reserved by the IANA # 0.*.*.* - Can't be blocked unilaterally with DHCP # 169.254.0.0/16 - Link Local Networks # 192.0.2.0/24 - TEST-NET $IPTABLES -A INPUT -i $ProtectInterface -s 0.0.0.0/8 -j DROP $IPTABLES -A INPUT -i $ProtectInterface -s 169.254.0.0/16 -j DROP $IPTABLES -A INPUT -i $ProtectInterface -s 192.0.2.0/24 -j DROP ################################################################################ # Enable forwarding to work between interfaces # Also allow all traffic on unprotected interfaces for interface_ids in $UnProtectInterfaces; do $IPTABLES -A INPUT -i $interface_ids -j ACCEPT $IPTABLES -A FORWARD -i $interface_ids -j ACCEPT $IPTABLES -A OUTPUT -o $interface_ids -j ACCEPT done ################################################################################ # Now we can open up some holes in our firewall. We optimize it a bit to allow # the most common services first. Feel free to arrange this to suit your needs. # # 20 21 22 25 53 80 110 113 143 443 19638 # ################################################################################ ################################################################################ # INPUT - PORT 80 - HTTP ################################################################################ for server_ips in $SERVER_IPS; do $IPTABLES -A INPUT -i $ProtectInterface -d $server_ips -p tcp -m state --state NEW --sport $UNPRIVPORTS --dport 80 -j ACCEPT done ################################################################################ # INPUT - PORT 443 - HTTPS ################################################################################ for server_ips in $SERVER_IPS; do $IPTABLES -A INPUT -i $ProtectInterface -d $server_ips -p tcp -m state --state NEW --sport $UNPRIVPORTS --dport 443 -j ACCEPT done ################################################################################ # OUTPUT - PORT 443 - HTTPS ################################################################################ for server_ips in $SERVER_IPS; do $IPTABLES -A OUTPUT -o $ProtectInterface -s $server_ips -p tcp -m state --state NEW --sport $UNPRIVPORTS --dport 443 -j ACCEPT done ################################################################################ # INPUT - ADDITIONAL_PORTS ################################################################################ for add_ports in $ADDITIONAL_PORTS; do for server_ips in $SERVER_IPS; do $IPTABLES -A INPUT -i $ProtectInterface -d $server_ips -p tcp -m state --state NEW --sport $UNPRIVPORTS --dport $add_ports -j ACCEPT done done ################################################################################ # INPUT - PORT 21 - FTP ################################################################################ for server_ips in $SERVER_IPS; do $IPTABLES -A INPUT -i $ProtectInterface -p tcp --sport $UNPRIVPORTS -d $server_ips --dport 21 -m state --state NEW -j ACCEPT done ################################################################################ # INPUT - PORT 110 - POP3 ################################################################################ for server_ips in $SERVER_IPS; do $IPTABLES -A INPUT -i $ProtectInterface -d $server_ips -p tcp -m state --state NEW --sport $UNPRIVPORTS --dport 110 -j ACCEPT done ################################################################################ # OUTPUT - PORT 80 - HTTP ################################################################################ for server_ips in $SERVER_IPS; do $IPTABLES -A OUTPUT -o $ProtectInterface -s $server_ips -p tcp -m state --state NEW --sport $UNPRIVPORTS --dport 80 -j ACCEPT done ################################################################################ # INPUT - PORT 143 - IMAP ################################################################################ for server_ips in $SERVER_IPS; do $IPTABLES -A INPUT -i $ProtectInterface -d $server_ips -p tcp -m state --state NEW --sport $UNPRIVPORTS --dport 143 -j ACCEPT done ################################################################################ # OUTPUT - PORT 113 - IDENTD ################################################################################ for server_ips in $SERVER_IPS; do $IPTABLES -A OUTPUT -o $ProtectInterface -s $server_ips -p tcp --syn --sport $UNPRIVPORTS --dport 113 -m state --state NEW -j REJECT --reject-with tcp-reset done ################################################################################ # INPUT - PORT 22 - SSH ################################################################################ for server_ips in $SERVER_IPS; do $IPTABLES -A INPUT -i $ProtectInterface -d $server_ips -p tcp -m state --state NEW --sport $UNPRIVPORTS --dport 22 -j ACCEPT done # # If panic mode, kill all SMTP # # (Note: "panic mode" is just something I use for temporarily stopping outgoing # SPAM. It is used from one of my antiSPAM scripts. As long as you don't # call this script with the "panic" argument, everything will work as it # should anyway. # if [ "$1" = "panic" ] then echo "Panic mode enabled. Incoming and Outgoing mail is not permitted." else ################################################################################ # OUTPUT - PORT 25 - SMTP ################################################################################ for server_ips in $SERVER_IPS; do $IPTABLES -A OUTPUT -o $ProtectInterface -p tcp -s $server_ips --sport $UNPRIVPORTS --dport 25 -j LOG --log-prefix " KISS_LOG " $IPTABLES -A OUTPUT -o $ProtectInterface -p tcp -s $server_ips --sport $UNPRIVPORTS --dport 25 -m state --state NEW -j ACCEPT done ################################################################################ # INPUT - PORT 25 - SMTP ################################################################################ for server_ips in $SERVER_IPS; do $IPTABLES -A INPUT -i $ProtectInterface -p tcp --sport $UNPRIVPORTS -d $server_ips --dport 25 -m state --state NEW -j ACCEPT done fi ################################################################################ # OUTPUT - PORT 21 - FTP ################################################################################ for server_ips in $SERVER_IPS; do $IPTABLES -A OUTPUT -o $ProtectInterface -s $server_ips -p tcp -m state --state NEW --sport $UNPRIVPORTS --dport 21 -j ACCEPT done ################################################################################ # OUTPUT - PORT 22 - SSH ################################################################################ for server_ips in $SERVER_IPS; do $IPTABLES -A OUTPUT -o $ProtectInterface -s $server_ips -p tcp -m state --state NEW --sport $UNPRIVPORTS --dport 22 -j ACCEPT done ################################################################################ # Allow outgoing access to external nameservers ################################################################################ $IPTABLES -A OUTPUT -o $ProtectInterface -p udp --sport $UNPRIVPORTS --dport 53 -m state --state NEW -j ACCEPT $IPTABLES -A OUTPUT -o $ProtectInterface -p tcp --sport $UNPRIVPORTS --dport 53 -m state --state NEW -j ACCEPT ################################################################################ # Allow outgoing access to external dhcp server ################################################################################ $IPTABLES -A OUTPUT -o $ProtectInterface -p udp --sport 68 --dport 67 -m state --state NEW -j ACCEPT ################################################################################ # Not running your own DNS? Then comment out the next 6 $IPTABLES command lines ################################################################################ # INPUT - PORT 53 - DNS ################################################################################ $IPTABLES -A INPUT -i $ProtectInterface -p udp --sport $UNPRIVPORTS --dport 53 -m state --state NEW -j ACCEPT $IPTABLES -A INPUT -i $ProtectInterface -p tcp --sport $UNPRIVPORTS --dport 53 -m state --state NEW -j ACCEPT ################################################################################ # Allow local DNS server to communicate with other DNS servers: ################################################################################ $IPTABLES -A INPUT -i $ProtectInterface -p udp --sport 53 --dport 53 -m state --state NEW -j ACCEPT $IPTABLES -A INPUT -i $ProtectInterface -p tcp --sport 53 --dport 53 -m state --state NEW -j ACCEPT $IPTABLES -A OUTPUT -o $ProtectInterface -p udp --sport 53 --dport 53 -m state --state NEW -j ACCEPT $IPTABLES -A OUTPUT -o $ProtectInterface -p tcp --sport 53 --dport 53 -m state --state NEW -j ACCEPT ################################################################################ # Allow for pinging external servers ################################################################################ $IPTABLES -A OUTPUT -o $ProtectInterface -m state --state NEW -p icmp --icmp-type ping -j ACCEPT ################################################################################ # Uncomment this line to allow pinging of this server by a trusted IP. Get rid # of "-s xxx.xxx.xxx.xxx" to trust everyone. # # NOTE: Ping can be used for a DoS attack against your server. Specifying only # trusted IP addresses, such as your own, is recommended. Some ISP's require # that they be able to ping your server. Check with your ISP. # # $IPTABLES -A INPUT -s 10.0.0.0/20 -i eth0.3 -m state --state NEW -p icmp --icmp-type ping -j ACCEPT # $IPTABLES -A INPUT -s 10.0.0.0/20 -i eth0 -m state --state NEW -p icmp --icmp-type ping -j ACCEPT ################################################################################ # OUTPUT - PORT 43 - WHOIS ################################################################################ for server_ips in $SERVER_IPS; do $IPTABLES -A OUTPUT -o $ProtectInterface -s $server_ips -p tcp -m state --state NEW --sport $UNPRIVPORTS --dport 43 -j ACCEPT done ################################################################################ # Uncomment these lines only if you wish to allow outgoing traceroutes. # for server_ips in $SERVER_IPS; do $IPTABLES -A OUTPUT -o $ProtectInterface -p udp -s $server_ips --sport 32769:65535 --dport 33434:33523 -m state --state NEW -j ACCEPT done ################################################################################ # Get the forwarding to work as this is a transit server $IPTABLES -t nat -A POSTROUTING -o $ProtectInterface -j MASQUERADE