Optimized Example


In the example that follows, the shell variables and kernel-level protection services are the same as those listed in the example in Chapter 4. One new variable is declared, USER_CHAINS, which contains the names of all the user-defined chains used in the script.

User-Defined Chains in the Script

The chains are listed here:

  • tcp-state-flags Contains the rules to check for invalid TCP state flag combinations.

  • connection-tracking Contains the rules to check for state-related matches, INVALID, ESTABLISHED, and RELATED.

  • source-address-check Contains the rules to check for illegal source addresses.

  • destination-address-check Contains the rules to check for illegal destination addresses.

  • EXT-input Contains the interface-specific user-defined chains for the INPUT chain. In this example, the host has one interface connected to the Internet.

  • EXT-output Contains the interface-specific user-defined chains for the OUTPUT chain. In this example, the host has one interface connected to the Internet.

  • local_dns_server_query Contains the rules for outgoing queries from either the local DNS server or local clients.

  • remote_dns_server_response Contains the rules for incoming responses from a remote DNS server.

  • local_tcp_client_request Contains the rules for outgoing TCP connection requests and locally generated client traffic to remote servers.

  • remote_tcp_server_response Contains the rules for incoming responses from remote TCP servers.

  • remote_tcp_client_request Contains the rules for incoming TCP connection requests and remotely generated client traffic to local servers.

  • local_tcp_server_response Contains the rules for outgoing responses to remote clients.

  • local_udp_client_request Contains the rules for outgoing UDP client traffic to remote servers.

  • remote_udp_server_response Contains the rules for incoming responses from remote UDP servers.

  • EXT-icmp-out Contains the rules for outgoing ICMP packets.

  • EXT-icmp-in Contains the rules for incoming ICMP packets.

  • EXT-log-in Contains the logging rules for incoming packets before dropping them by the default INPUT policy.

  • EXT-log-out Contains the logging rules for outgoing packets before dropping them by the default OUTPUT policy.

  • log-tcp-state Contains the logging rules for TCP packets with illegal state flag combinations, before dropping them.

  • remote_dhcp_server_response Contains the rules for incoming packets from this host's DHCP server.

  • local_dhcp_client_query Contains the rules for outgoing DHCP client packets.

Some interface-specific chains are prefaced with EXT to differentiate them from any user-defined chains containing rules for any LAN interfaces. This firewall example assumes that there is only one interface, the external interface. The point is to suggest that different rules and security policies could be defined on a per-interface basis.

The actual declaration in the firewall shell script would be as shown here:

 USER_CHAINS="EXT-input                  EXT-output \               tcp-state-flags            connection-tracking  \               source-address-check       destination-address-check  \               local-dns-server-query     remote-dns-server-response  \               local-tcp-client-request   remote-tcp-server-response \               remote-tcp-client-request  local-tcp-server-response \               local-udp-client-request   remote-udp-server-response \               local-dhcp-client-query    remote-dhcp-server-response \               EXT-icmp-out               EXT-icmp-in \               EXT-log-in                 EXT-log-out \               log-tcp-state" 

Firewall Initialization

The firewall script starts out identically to the example in Chapter 4. Recall that a number of shell variables were set, including one called $IPT to define the location of the iptables firewall administration command:

 #!/bin/sh IPT="/sbin/iptables"                 # Location of iptables on your system INTERNET="eth0"                      # Internet-connected interface LOOPBACK_INTERFACE="lo"              # however your system names it IPADDR="my.ip.address"               # your IP address MY_ISP="my.isp.address.range"        # ISP server & NOC address range SUBNET_BASE="my.subnet.network"      # Your subnet's network address SUBNET_BROADCAST="my.subnet.bcast"   # Your subnet's broadcast address LOOPBACK="127.0.0.0/8"               # reserved loopback address range CLASS_A="10.0.0.0/8"                 # class A private networks CLASS_B="172.16.0.0/12"              # class B private networks CLASS_C="192.168.0.0/16"             # class C private networks CLASS_D_MULTICAST="224.0.0.0/4"      # class D multicast addresses CLASS_E_RESERVED_NET="240.0.0.0/5"   # class E reserved addresses BROADCAST_src="/books/3/251/1/html/2/0.0.0.0"              # broadcast source address BROADCAST_DEST="255.255.255.255"     # broadcast destination address PRIVPORTS="0:1023"                   # well-known, privileged port range UNPRIVPORTS="1024:65535"             # unprivileged port range 

A number of kernel parameters were also set; refer to Chapter 4 for an explanation of these parameters:

 # Enable broadcast echo Protection echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts # Disable Source Routed Packets for f in /proc/sys/net/ipv4/conf/*/accept_source_route; do     echo 0 > $f done # Enable TCP SYN Cookie Protection echo 1 > /proc/sys/net/ipv4/tcp_syncookies # Disable ICMP Redirect Acceptance for f in /proc/sys/net/ipv4/conf/*/accept_redirects; do     echo 0 > $f done # Don't send Redirect Messages for f in /proc/sys/net/ipv4/conf/*/send_redirects; do     echo 0 > $f done # Drop Spoofed Packets coming in on an interface, which, if replied to, # would result in the reply going out a different interface. for f in /proc/sys/net/ipv4/conf/*/rp_filter; do     echo 1 > $f done # Log packets with impossible addresses. for f in /proc/sys/net/ipv4/conf/*/log_martians; do     echo 1 > $f done 

The built-in chains and any preexisting user-defined chains are emptied:

 # Remove any existing rules from all chains $IPT --flush $IPT -t nat --flush $IPT -t mangle --flush 

The next step would be to delete the user-defined chains. They can be deleted with the following commands:

 $IPT -X $IPT -t nat -X $IPT -t mangle -X 

The default policy is first set to ACCEPT for all built-in chains:

 # Reset the default policy $IPT --policy INPUT   ACCEPT $IPT --policy OUTPUT  ACCEPT $IPT --policy FORWARD ACCEPT $IPT -t nat --policy PREROUTING  ACCEPT $IPT -t nat --policy OUTPUT ACCEPT $IPT -t nat --policy POSTROUTING ACCEPT $IPT -t mangle --policy PREROUTING ACCEPT $IPT -t mangle --policy OUTPUT ACCEPT 

Here is the final code for the beginning of the firewall script, namely the code to enable the firewall to be stopped easily. With this code placed below the preceding code, when you call the script with an argument of stop the script will flush, clear, and reset the default policies, and the firewall will effectively stop.

 if [ "$1" = "stop" ] then echo "Firewall completely stopped!  WARNING: THIS HOST HAS NO FIREWALL RUNNING." exit 0 fi 

Now reset the real default policy to DROP:

 $IPT --policy INPUT   DROP $IPT --policy OUTPUT  DROP $IPT --policy FORWARD DROP $IPT -t nat --policy PREROUTING DROP $IPT -t nat --policy OUTPUT DROP $IPT -t nat --policy POSTROUTING DROP $IPT -t mangle --policy PREROUTING DROP $IPT -t mangle --policy OUTPUT DROP 

Traffic through the loopback interface is enabled:

 # Unlimited traffic on the loopback interface $IPT -A INPUT  -i lo -j ACCEPT $IPT -A OUTPUT -o lo -j ACCEPT 

Now the script starts differing from the example in Chapter 4.

The user-defined chains can now be created. Their names were included in the single shell variable, USER_CHAINS, for just this purpose:

 # Create the user-defined chains for i in $USER_CHAINS; do     $IPT -N $i done 

Installing the Chains

Unfortunately, the function calllike nature of building and installing the chains doesn't lend itself to a serial, step-by-step explanation without the capability to show different places in the script simultaneously, side by side.

The idea is to place the rules on the user-defined chains and then to install those chains on the built-in INPUT, OUTPUT, and FORWARD chains. If the script contains an error and exits while building the user-defined chains, the built-in chains will contain no rules, the default DROP policy will be in effect, and, presumably, the loopback traffic will be enabled.

So, this first installation section is actually placed at the end of the firewall script. The first step is to check for illegal TCP state flag combinations:

 # If TCP: Check for common stealth scan TCP state patterns $IPT -A INPUT  -p tcp -j tcp-state-flags $IPT -A OUTPUT -p tcp -j tcp-state-flags 

Notice that the same chain can be referenced from more than one calling chain. The rules on the user-defined chains needn't be duplicated for the INPUT and OUTPUT chains. Now when the packet processing reaches this point, the processing will "jump" to the user-defined tcp-state-flags chain. When the processing is complete within that chain, the processing will be passed back here and continue on, unless a final disposition for the packet was found in the user-defined chain.

If the state module is being used, the next step is to bypass the firewall altogether if the packet is part of an ongoing, previously accepted exchange:

 if [ "$CONNECTION_TRACKING" = "1" ]; then     # Bypass the firewall filters for established exchanges     $IPT -A INPUT  -j connection-tracking     $IPT -A OUTPUT -j connection-tracking fi 

If the machine is a DHCP client, a provision must be made for the broadcast messages sent between the client and the server during initialization. A provision must also be made to accept the broadcast source address, 0.0.0.0. The source and destination address-checking tests would drop the initial DHCP traffic:

 if [ "$DHCP_CLIENT" = "1" ]; then     $IPT -A INPUT  -i $INTERNET -p udp \              --sport 67 --dport 68 -j remote-dhcp-server-response     $IPT -A OUTPUT -o $INTERNET -p udp \              --sport 68 --dport 67 -j local-dhcp-client-query fi 

Now jump to the user-defined chain to drop incoming packets that are using this host's IP address as their source address. Then test for other illegal source and destination addresses:

 # Test for illegal source and destination addresses in incoming packets $IPT -A INPUT  -p ! tcp -j source-address-check $IPT -A INPUT  -p tcp --syn -j source-address-check $IPT -A INPUT  -j destination-address-check # Test for illegal destination addresses in outgoing packets $IPT -A OUTPUT -j destination-address-check 

Locally generated outgoing packets don't need their source address checked because the firewall rules explicitly require this host's IP address in the source field. Destination address checking is performed on outgoing packets, however.

At this point, regular incoming packets addressed to this host's IP address can be handed off to the main section of the firewall. Any incoming packet that doesn't match a rule on the EXT-input chain will return here to be logged and dropped:

 # Begin standard firewall tests for packets addressed to this host $IPT -A INPUT -i $INTERNET -d $IPADDR -j EXT-input 

A final set of tests on destination address is necessary. Broadcast and multicast packets are not addressed to this host's unicast IP address. They are addressed to a broadcast or multicast address.

As mentioned in Chapter 4, multicast packets won't be received unless you register to receive packets addressed to a particular multicast address. If you want to receive multicast packets, you must either accept all of them or add a rule specific to the particular address and port used for any given session. The following code enables you to choose whether to drop or accept the traffic:

 # Multicast traffic $IPT -A INPUT  -i $INTERNET -p udp -d $CLASS_D_MULTICAST -j [ DROP | ACCEPT ] $IPT -A OUTPUT -o $INTERNET -p udp -s $IPADDR -d $CLASS_D_MULTICAST \     -j [ DROP | ACCEPT ] 

At this point, regular outgoing packets from this host can be handed off to the main section of the firewall. Any outgoing packet that doesn't match a rule on the EXT-_output chain will return here to be logged and dropped:

 # Begin standard firewall tests for packets sent from this host # Source address spoofing by this host is not allowed due to the # test on source address in this rule. $IPT -A OUTPUT -o $INTERNET -s $IPADDR -j EXT-output 

Any broadcast messages are implicitly ignored by the last input and output rules. Depending on the nature of the public or external network that the machine is directly connected to, broadcasts could be very common on the local subnet. You probably don't want to log such messages, even with rate-limited logging.

Finally, any remaining packets are dropped by the default policy. Any logging would be done at this point:

 # Log anything of interest that fell through, # before the default policy drops the packet. $IPT -A INPUT  -j EXT-log-in $IPT -A OUTPUT -j EXT-log-out 

This marks the end of the firewall and is the last reference to the INPUT and OUTPUT chains.

Building the User-Defined EXT-input and EXT-output Chains

This section describes the construction of the user-defined chains that were jumped to in the preceding section. At the top level, rules are built on the general EXT-input and EXT-output chains. These rules are jumps to more specific sets of matches contained in the dedicated user-defined chains you've created.

Note that the EXT-input and EXT-output layer is not necessary. The following rules and jumps could just as easily have been associated with the built-in INPUT and OUTPUT chains.

Using these chains has one advantage, however. Because the jumps to these chains were dependent on the source or destination address, you know at this point that the incoming packet is addressed to this host and has a source address believed to be legitimate. The outgoing packet is addressed from this host and has a destination address believed to be legitimate. Also, if the state module is in use, the packet is either the first packet in an exchange or a new, unrelated ICMP packet.

In summary, the EXT-input and EXT-output chains will be used to select traffic by protocol and by direction, in terms of client or server. Each rule will provide the branch point to the firewall rules specific to that protocol and packet characteristics. The matches performed by the EXT-input and EXT-output rules are the heart of the optimization available with user-defined chains.

DNS TRAFFIC

The rules to identify DNS traffic come first. Until the DNS rules are installed, your network software won't be capable of locating services and hosts out on the Internet unless you use the IP address.

The first pair of rules match on queries from the local cache and forward name server, if you have one, and responses from the remote DNS server. The local server is configured as a slave to the remote, primary server, so the local server will fail if the lookup doesn't succeed. This configuration is less common for a small office/home office:

 $IPT -A EXT-output -p udp --sport 53 --dport 53 \          -j local-dns-server-query $IPT -A EXT-input -p udp --sport 53 --dport 53 \          -j remote-dns-server-response 

The next pair of rules match on standard DNS client lookup requests over TCP, when the server's response is too large to fit in a UDP DNS packet. These rules would be used by both a forwarding name server and a standard client:

 $IPT -A EXT-output -p tcp \          --sport $UNPRIVPORTS --dport 53 \          -j local-dns-server-query $IPT A EXT-input -p tcp ! --syn \          --sport 53 --dport $UNPRIVPORTS \          -j remote-dns-server-response 

What follows are the user-defined chains containing the actual ACCEPT and DROP rules.

local_dns_server_query AND remote_dns_server_response

These two user-defined chains, local_dns_server_query and remote_dns_server_response, perform the final determination on the packet.

The local_dns_server_query chain selects the outgoing request packets based on the remote server's destination address. For this chain, you must define the nameservers you'd like to use:

 NAMESERVER_1="your.name.server" NAMESERVER_2="your.secondary.nameserver" NAMESERVER_3="your.tertiary.nameserver" # DNS Forwarding Name Server or client requests if [ "$CONNECTION_TRACKING" = "1" ]; then     $IPT -A local-dns-server-query \              -d $NAMESERVER_1 \              -m state --state NEW -j ACCEPT     $IPT -A local-dns-server-query \              -d $NAMESERVER_2 \              -m state --state NEW -j ACCEPT     $IPT -A local-dns-server-query \              -d $NAMESERVER_3 \              -m state --state NEW -j ACCEPT fi $IPT -A local-dns-server-query \          -d $NAMESERVER_1 -j ACCEPT $IPT -A local-dns-server-query \          -d $NAMESERVER_2 -j ACCEPT $IPT -A local-dns-server-query \          -d $NAMESERVER_3 -j ACCEPT 

The remote_dns_server_response chain selects the incoming response packets based on the remote server's source address:

 # DNS server responses to local requests $IPT -A remote-dns-server-response \          -s $NAMESERVER_1 -j ACCEPT $IPT -A remote-dns-server-response \          -s $NAMESERVER_2 -j ACCEPT $IPT -A remote-dns-server-response \          -s $NAMESERVER_3 -j ACCEPT 

Notice that the final rules select on only the remote server's IP address. The calling rules on the EXT-input and EXT-output chains already have matched on the UDP or TCP header fields. Those match tests don't need to be performed again.

local_dns_client_request AND remote_dns_server_response

These two user-defined chains, local_dns_client_request and remote_dns_server_response, perform the final determination on packets exchanged between local TCP clients and remote servers.

The local_dns_client_request chain selects the outgoing request packets based on the remote server's destination address and port. The remote_dns_server_response chain selects the incoming response packets based on the remote server's source address and port.

LOCAL CLIENT TRAFFIC OVER TCP

The next pair of rules match on standard, local client traffic to remote servers over TCP:

 $IPT -A EXT-output -p tcp \          --sport $UNPRIVPORTS \          -j local-tcp-client-request $IPT -A EXT-input -p tcp ! --syn \          --dport $UNPRIVPORTS \          -j remote-tcp-server-response 

Remember that these rules normally are not tested when the state module is used, with the exception of the first outgoing SYN request.

The specific reference to the TCP protocol is required in the following rules, even though the protocol field was matched on by the calling rule, because the source or destination port is specified. This is a syntactic requirement of iptables. Also note that you need to define the source and destination hosts within these rules, as indicated by the <selected host> and other such calls. In addition, if you use these rules, be sure to define variables for the ones you choose, such as POP_SERVER, MAIL_SERVER, NEWS_SERVER, and so on. The following code enables TCP traffic from local clients:

 # Local TCP client output and remote server input chains # SSH client if [ "$CONNECTION_TRACKING" = "1" ]; then     $IPT -A local-tcp-client-request -p tcp \              -d <selected host> --dport 22 \              -m state --state NEW \              -j ACCEPT fi $IPT -A local-tcp-client-request -p tcp \          -d <selected host> --dport 22 \          -j ACCEPT $IPT -A remote-tcp-server-response -p tcp ! --syn \          -s <selected host> --sport 22  \          -j ACCEPT # Client rules for HTTP, HTTPS and FTP control requests if [ "$CONNECTION_TRACKING" = "1" ]; then     $IPT -A local-tcp-client-request -p tcp \              -m multiport --destination-port 80,443,21 \              --syn -m state --state NEW \              -j ACCEPT fi $IPT -A local-tcp-client-request -p tcp \          -m multiport --destination-port 80,443,21 \          -j ACCEPT $IPT -A remote-tcp-server-response -p tcp \          -m multiport --source-port 80,443,21  ! --syn \          -j ACCEPT # POP client if [ "$CONNECTION_TRACKING" = "1" ]; then     $IPT -A local-tcp-client-request -p tcp \              -d $POP_SERVER --dport 110 \              -m state --state NEW \              -j ACCEPT fi $IPT -A local-tcp-client-request -p tcp \          -d $POP_SERVER --dport 110 \          -j ACCEPT $IPT -A remote-tcp-server-response -p tcp ! --syn \          -s $POP_SERVER --sport 110  \          -j ACCEPT # SMTP mail client if [ "$CONNECTION_TRACKING" = "1" ]; then     $IPT -A local-tcp-client-request -p tcp \              -d $MAIL_SERVER --dport 25 \              -m state --state NEW \              -j ACCEPT fi $IPT -A local-tcp-client-request -p tcp \          -d $MAIL_SERVER --dport 25 \          -j ACCEPT $IPT -A remote-tcp-server-response -p tcp ! --syn \          -s $MAIL_SERVER --sport 25  \          -j ACCEPT # Usenet news client if [ "$CONNECTION_TRACKING" = "1" ]; then     $IPT -A local-tcp-client-request -p tcp \              -d $NEWS_SERVER --dport 119 \              -m state --state NEW \              -j ACCEPT fi $IPT -A local-tcp-client-request -p tcp \          -d $NEWS_SERVER --dport 119 \          -j ACCEPT $IPT -A remote-tcp-server-response -p tcp ! --syn \          -s $NEWS_SERVER --sport 119  \          -j ACCEPT # FTP client - passive mode data channel connection if [ "$CONNECTION_TRACKING" = "1" ]; then     $IPT -A local-tcp-client-request -p tcp \              --dport $UNPRIVPORTS \              -m state --state NEW \              -j ACCEPT fi $IPT -A local-tcp-client-request -p tcp \          --dport $UNPRIVPORTS -j ACCEPT $IPT -A remote-tcp-server-response -p tcp  ! --syn \          --sport $UNPRIVPORTS -j ACCEPT 

LOCAL SERVER TRAFFIC OVER TCP

The next pair of rules match on standard, local server traffic to remote clients over TCP. These would be applicable only if you're actually offering services to remote hosts:

 $IPT -A EXT-input -p tcp \          --sport $UNPRIVPORTS \          -j remote-tcp-client-request $IPT -A EXT-output -p tcp ! --syn \          --dport $UNPRIVPORTS \          -j local-tcp-server-response 

The next pair of rules handle incoming data channel connections from remote FTP servers when using port mode:

 # Kludge for incoming FTP data channel connections # from remote servers using port mode. # The state modules treat this connection as RELATED # if the ip_conntrack_ftp module is loaded. $IPT -A EXT-input -p tcp \          --sport 20 --dport $UNPRIVPORTS \          -j ACCEPT $IPT -A EXT-output -p tcp ! --syn \          --sport $UNPRIVPORTS --dport 20 \          -j ACCEPT 

remote_tcp_client_request AND local_tcp_server_response

These two user-defined chains, remote_tcp_client_request and local_tcp_server_response, perform the final determination on packets exchanged between remote TCP clients and local servers.

The remote_tcp_client_request chain selects the incoming request packets based on the remote client's source address and port. The local_tcp_server_response chain selects the outgoing response packets based on the remote client's destination address and port:

 # Remote TCP client input and local server output chains # SSH server if [ "$CONNECTION_TRACKING" = "1" ]; then     $IPT -A remote-tcp-client-request -p tcp \              -s <selected host> --destination-port 22 \              -m state --state NEW \              -j ACCEPT fi $IPT -A remote-tcp-client-request -p tcp \          -s <selected host> --destination-port 22 \          -j ACCEPT $IPT -A local-tcp-server-response -p tcp  ! --syn \          --source-port 22 -d <selected host> \          -j ACCEPT # AUTH identd server $IPT -A remote-tcp-client-request -p tcp \          --destination-port 113 \          -j REJECT --reject-with tcp-reset 

LOCAL CLIENT TRAFFIC OVER UDP

The next pair of rules match on standard, local client traffic to remote servers over UDP:

 # Local UDP client, remote server $IPT -A EXT-output -p udp \          --sport $UNPRIVPORTS \          -j local-udp-client-request $IPT -A EXT-input -p udp \          --dport $UNPRIVPORTS \          -j remote-udp-server-response 

BYPASSING SOURCE ADDRESS CHECKING WITHOUT USING THE STATE MODULE

If you aren't using the state module, most TCP rules could still be placed before the source address spoofing rules. TCP maintains connection state information itself. Only the first incoming connection request, the first SYN packet, requires source address checking. You can do this by reorganizing the rules and splitting the rule for incoming client traffic into two tests, one for the initial SYN flag and one for all subsequent ACK flags.

Using the rules for a local web server as an example, the first rule would follow the spoofing rules:

 if [ "$CONNECTION_TRACKING" = "1" ]; then     $IPT -A remote-tcp-client-request -p tcp \              --destination-port 80 \              -m state --state NEW \              -j ACCEPT else     $IPT -A remote-tcp-client-request -p tcp --syn \              --destination-port 80 \              -j ACCEPT fi 

The next two rules would precede the spoofing rules:

 $IPT -A INPUT -p tcp ! --syn \          --source-port $UNPRIVPORTS \          -d $IPADDR --destination-port 80 \          -j ACCEPT $IPT -A OUTPUT -p tcp  ! --syn \          -s $IPADDR --source-port 80  \          --destination-port $UNPRIVPORTS \          -j ACCEPT 


local_udp_client_request AND remote_udp_server_response

These two user-defined chains, local_udp_client_request and remote_udp_server_response, perform the final determination on packets exchanged between local UDP clients and remote servers.

The local_udp_client_request chain selects the outgoing request packets based on the remote server's destination address and port. The remote_udp_server_response chain selects the incoming response packets based on the remote server's source address and port. Be sure to define the TIME_SERVER variable before implementing this rule:

 # NTP time client if [ "$CONNECTION_TRACKING" = "1" ]; then     $IPT -A local-udp-client-request -p udp \              -d $TIME_SERVER --dport 123 \              -m state --state NEW \              -j ACCEPT fi $IPT -A local-udp-client-request -p udp \          -d $TIME_SERVER --dport 123 \          -j ACCEPT $IPT -A remote-udp-server-response -p udp \          -s $TIME_SERVER --sport 123 \          -j ACCEPT 

ICMP TRAFFIC

Finally, the last pair of rules match on incoming and outgoing ICMP traffic:

 # ICMP traffic $IPT -A EXT-input -p icmp -j EXT-icmp-in $IPT -A EXT-output -p icmp -j EXT-icmp-out 

EXT-icmp-in AND EXT-icmp-out

These two user-defined chains, EXT-icmp-in and EXT-icmp-out, perform the final determination on ICMP packets exchanged between the local host and remote machines.

The EXT-icmp-in chain selects the incoming ICMP packets based on the message type. The EXT-icmp-out chain selects the outgoing ICMP packets based on the message type:

 # Log and drop initial ICMP fragments $IPT -A EXT-icmp-in --fragment -j LOG \          --log-prefix "Fragmented incoming ICMP: " $IPT -A EXT-icmp-in --fragment -j DROP $IPT -A EXT-icmp-out --fragment -j LOG \          --log-prefix "Fragmented outgoing ICMP: " $IPT -A EXT-icmp-out --fragment -j DROP # Outgoing ping if [ "$CONNECTION_TRACKING" = "1" ]; then     $IPT -A EXT-icmp-out -p icmp \              --icmp-type echo-request \              -m state --state NEW \              -j ACCEPT fi $IPT -A EXT-icmp-out -p icmp \          --icmp-type echo-request -j ACCEPT $IPT -A EXT-icmp-in -p icmp \          --icmp-type echo-reply -j ACCEPT # Incoming ping if [ "$CONNECTION_TRACKING" = "1" ]; then     $IPT -A EXT-icmp-in -p icmp \              -s $MY_ISP  \              --icmp-type echo-request \              -m state --state NEW \              -j ACCEPT fi $IPT -A EXT-icmp-in -p icmp \          --icmp-type echo-request \          -s $MY_ISP -j ACCEPT $IPT -A EXT-icmp-out -p icmp \          --icmp-type echo-reply \          -d $MY_ISP -j ACCEPT # Destination Unreachable Type 3 $IPT -A EXT-icmp-out -p icmp \          --icmp-type fragmentation-needed -j ACCEPT $IPT -A EXT-icmp-in -p icmp \          --icmp-type destination-unreachable -j ACCEPT # Parameter Problem $IPT -A EXT-icmp-out -p icmp \          --icmp-type parameter-problem -j ACCEPT $IPT -A EXT-icmp-in -p icmp \          --icmp-type parameter-problem -j ACCEPT # Time Exceeded $IPT -A EXT-icmp-in -p icmp \          --icmp-type time-exceeded -j ACCEPT # Source Quench $IPT -A EXT-icmp-out -p icmp \          --icmp-type source-quench -j ACCEPT $IPT -A EXT-icmp-in -p icmp \          --icmp-type source-quench -j ACCEPT 

tcp-state-flags

The tcp-state-flags chain is the very first user-defined chain you will attach to both the built-in INPUT and OUTPUT chains. The tests match on TCP state flag combinations that are artificially crafted and often are used in stealth scans:

 # All of the bits are cleared $IPT -A tcp-state-flags -p tcp --tcp-flags ALL NONE -j log-tcp-state # SYN and FIN are both set $IPT -A tcp-state-flags -p tcp --tcp-flags SYN,FIN SYN,FIN -j log-tcp-state # SYN and RST are both set $IPT -A tcp-state-flags -p tcp --tcp-flags SYN,RST SYN,RST -j log-tcp-state # FIN and RST are both set $IPT -A tcp-state-flags -p tcp --tcp-flags FIN,RST FIN,RST -j log-tcp-state # FIN is the only bit set, without the expected accompanying ACK $IPT -A tcp-state-flags -p tcp --tcp-flags ACK,FIN FIN -j log-tcp-state # PSH is the only bit set, without the expected accompanying ACK $IPT -A tcp-state-flags -p tcp --tcp-flags ACK,PSH PSH -j log-tcp-state # URG is the only bit set, without the expected accompanying ACK $IPT -A tcp-state-flags -p tcp --tcp-flags ACK,URG URG -j log-tcp-state 

log-tcp-state

The log-tcp-state chain is used for two reasons. First, the log message is prefixed with a specific explanatory message, and because this is a crafted packet, any IP or TCP options are reported. Second, the matching packet is dropped immediately. The two generalized logging chains that come up later are written under the assumption that the logged packets will be dropped by the default policy immediately upon return from the chains:

 $IPT -A log-tcp-state -p tcp -j LOG \          --log-prefix "Illegal TCP state: " \          --log-ip-options --log-tcp-options $IPT -A log-tcp-state -j DROP 

connection-tracking

The connection-tracking chain is the second user-defined chain you will attach to both the built-in INPUT and OUTPUT chains. Matching packets bypass the firewall rules and are accepted immediately:

 if [ "$CONNECTION_TRACKING" = "1" ]; then     # Bypass the firewall filters for established exchanges     $IPT -A connection-tracking -m state \              --state ESTABLISHED,RELATED \              -j ACCEPT     $IPT -A connection-tracking -m state --state INVALID \              -j LOG --log-prefix "INVALID packet: "     $IPT -A connection-tracking -m state --state INVALID -j DROP fi 

local_dhcp_client_query and remote_dhcp_server_response

The local_dhcp_client_query and remote_dhcp_server_response chains contain the rules required of a DHCP client. Placement of these rules in the chain hierarchy is important in relation to any spoofing or generalized broadcast rules. Furthermore, the host will not configure its IP address until after receiving the DHCPACK commitment message from the server. The destination address that the server uses in the DHCPACK message depends on the particular server implementation. If you want to use this rule, you'll need to set DHCP_CLIENT to 1 and also define the DHCP_SERVER variable:

 # Some broadcast packets are explicitly ignored by the firewall. # Others are dropped by the default policy. # DHCP tests must precede broadcast-related rules, as DHCP relies # on broadcast traffic initially. if [ "$DHCP_CLIENT" = "1" ]; then     DHCP_SERVER="my.dhcp.server"     # Initialization or rebinding: No lease or Lease time expired.     $IPT -A local-dhcp-client-query \              -s $BROADCAST_SRC \              -d $BROADCAST_DEST -j ACCEPT     # Incoming DHCPOFFER from available DHCP servers     $IPT -A remote-dhcp-server-response \              -s $BROADCAST_SRC \              -d $BROADCAST_DEST -j ACCEPT     # Fall back to initialization     # The client knows its server, but has either lost its lease,     # or else needs to reconfirm the IP address after rebooting.     $IPT -A local-dhcp-client-query \                  -s $BROADCAST_SRC \                  -d $DHCP_SERVER -j ACCEPT     $IPT -A remote-dhcp-server-response \              -s $DHCP_SERVER \              -d $BROADCAST_DEST -j ACCEPT     # As a result of the above, we're supposed to change our IP     # address with this message, which is addressed to our new     # address before the dhcp client has received the update.     # Depending on the server implementation, the destination address     # can be the new IP address, the subnet address, or the limited     # broadcast address.     # If the network subnet address is used as the destination,     # the next rule must allow incoming packets destined to the     # subnet address, and the rule must precede any general rules     # that block such incoming broadcast packets.     $IPT -A remote-dhcp-server-response \              -s $DHCP_SERVER -j ACCEPT     # Lease renewal     $IPT -A local-dhcp-client-query \              -s $IPADDR \              -d $DHCP_SERVER -j ACCEPT fi 

source-address-check

The source-address-check chain tests for identifiably illegal source addresses. The chain is attached to the INPUT chain alone. The firewall rules guarantee that packets generated by this host contain your IP address as their source address. Notice that these rules would need some adjustment if the host had more than one network interface or if a private LAN was using private class IP addresses.

A DHCP client needs to handle DHCP-related broadcast traffic before performing these tests:

 # Drop packets pretending to be originating from the receiving interface $IPT -A source-address-check -s $IPADDR -j DROP # Refuse packets claiming to be from private networks $IPT -A source-address-check -s $CLASS_A -j DROP $IPT -A source-address-check -s $CLASS_B -j DROP $IPT -A source-address-check -s $CLASS_C -j DROP $IPT -A source-address-check -s $CLASS_D_MULTICAST -j DROP $IPT -A source-address-check -s $CLASS_E_RESERVED_NET -j DROP $IPT -A source-address-check -s $LOOPBACK  -j DROP $IPT -A source-address-check -s 0.0.0.0/8 -j DROP $IPT -A source-address-check -s 169.254.0.0/16 -j DROP $IPT -A source-address-check -s 192.0.2.0/24 -j DROP 

destination-address-check

The destination-address-check chain tests for broadcast packets, misused multicast addresses, and well-known unprivileged service ports. The chain is attached to both the INPUT and OUTPUT chains. A DHCP client needs to handle DHCP-related broadcast traffic before performing these tests:

 # Block directed broadcasts from the Internet $IPT -A destination-address-check $BROADCAST_DEST -j DROP $IPT -A destination-address-check -d $SUBNET_BASE -j DROP $IPT -A destination-address-check -d $SUBNET_BROADCAST -j DROP $IPT -A destination-address-check -p ! udp \          -d $CLASS_D_MULTICAST -j DROP # Avoid ports subject to protocol and system administration problems # TCP unprivileged ports # Deny connection requests to NFS, SOCKS and X Window ports $IPT -A destination-address-check -p tcp -m multiport \          --destination-port $NFS_PORT,$OPENWINDOWS_PORT,$SOCKS_PORT,$SQUID_PORT \          --syn -j DROP $IPT -A destination-address-check -p tcp --syn \          --destination-port $XWINDOW_PORTS -j DROP # UDP unprivileged ports # Deny connection requests to NFS and lockd ports $IPT -A destination-address-check -p udp -m multiport \          --destination-port $NFS_PORT,$LOCKD_PORT -j DROP 

Logging Dropped Packets

The EXT-log-in and EXT-log-out chains contain the rules that log packets immediately before the packets fall off the end of their respective chains and are dropped by the default policy. Almost all outgoing packets to be dropped are logged because they indicate either a problem in the firewall rules or an unknown (or unauthorized service) attempting to contact the outside world:

 # ICMP rules $IPT -A EXT-log-in -p icmp \          --icmp-type ! echo-request -m limit -j LOG # TCP rules $IPT -A EXT-log-in -p tcp \          --dport 0:19 -j LOG # skip ftp, telnet, ssh $IPT -A EXT-log-in -p tcp \          --dport 24 -j LOG # skip smtp $IPT -A EXT-log-in -p tcp \          --dport 26:78 -j LOG # skip finger, www $IPT -A EXT-log-in -p tcp \          --dport 81:109 -j LOG # skip pop-3, sunrpc $IPT -A EXT-log-in -p tcp \          --dport 112:136 -j LOG # skip NetBIOS $IPT -A EXT-log-in -p tcp \          --dport 140:142 -j LOG # skip imap $IPT -A EXT-log-in -p tcp \          --dport 144:442 -j LOG # skip secure_web/SSL $IPT -A EXT-log-in -p tcp \          --dport 444:65535 -j LOG #UDP rules $IPT -A EXT-log-in -p udp \          --dport 0:110 -j LOG # skip sunrpc $IPT -A EXT-log-in -p udp \          --dport 112:160 -j LOG # skip snmp $IPT -A EXT-log-in -p udp \          --dport 163:634 -j LOG # skip NFS mountd $IPT -A EXT-log-in -p udp \          --dport 636:5631 -j LOG # skip pcAnywhere $IPT -A EXT-log-in -p udp \          --dport 5633:31336 -j LOG # skip traceroute's default ports $IPT -A EXT-log-in -p udp \          --sport $TRACEROUTE_SRC \          --dport $TRACEROUTE_DEST -j LOG # skip the rest $IPT -A EXT-log-in -p udp \          --dport 33434:65535 -j LOG # Outgoing Packets # Don't log rejected outgoing ICMP destination-unreachable packets $IPT -A EXT-log-out -p icmp \          --icmp-type destination-unreachable -j DROP $IPT -A EXT-log-out -j LOG 




Linux Firewalls
Linux Firewalls: Attack Detection and Response with iptables, psad, and fwsnort
ISBN: 1593271417
EAN: 2147483647
Year: 2005
Pages: 163
Authors: Michael Rash

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net