Tuesday, September 9, 2014

[Quick Tips] : IPTABLES Explained in detailled

IPTABLES

For those who are not sure of the term iptables let me clarify you (From Wiki) iptables are the tables provided by the Linux kernel firewall (implemented as different Netfilter modules) and the chains and rules it stores. 

Few important points on iptables
  • iptables requires elevated privileges to operate and must be executed by user root, otherwise it fails to function. 
  • On most Linux systems, iptables is installed as /usr/sbin/iptables and documented in its man pages which can be opened using man iptables when installed. It may also be found in /sbin/iptables, but since iptables is more like a service rather than an "essential binary", the preferred location remains /usr/sbin.
  • It generally works in Layer 3 and layer 4 i.e. network and transport layer.
  • iptables is also responsible for managing ICMP (Internet Control messaging Protocol) that comes in data link layer
  • iptables also supports MAC level filtering so it works on Layer 2 as well (Data Link layer)
  • Layer 3 focuses on source (192.168.0.x) and destination (172.168.0.x) addresses.
  • Layer 4 focuses on protocols, ports, TCP : 80, UDP : 69 (Most of the applications are dependent on TCP and UDP ports.
NOTE: TCP/UDP ports use a 16-bit range (0-65535) and IP addresses are based on 32-bit ranges (4 billion)

Package

Verify that iptables rpm is installed in your machine
# rpm -qa | grep iptables
iptables-1.4.7-4.el6.i686
iptables-ipv6-1.4.7-4.el6.i686

To check if kernel is compiled to use iptables (here config-2.6.x.x may vary as per your kernel)
# less /boot/config-2.6.32-220.el6.i686 | grep CONFIG_NETFILTER
CONFIG_NETFILTER=y

Make sure the first line as shown above should be "y"

Types of tables in iptables

  1. mangle - alter packets (TOS/TTL) with TCP/UDP/ICMP
  2. NAT (Network Address Translation)
  3. Filter (IP packet filtering)
NOTE: NAT allows to change IP address along with the port

ACL syntax for iptables

  1. name of chain - action (Append/Insert/Replace)
  2. name of table (filter) - mangle/nat/user-defined
  3. layer 3 object (source/destination)
  4. optionally layer 4 subject (tcp/udp protocols/ports)
  5. Jump/Target -j - ACCEPT/DROP/DENY/REJECT/LOG
Some Examples
Block a source IP 192.168.0.20 from communicating with our system

# iptables -A INPUT -s 192.168.0.30 -j DROP
So here I am appending a rule into the input chain for the source 192.168.0.30 and the action to be taken is DROP all the packets coming from the source machine.

To view the current rules in iptables
# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
DROP       all  --  192.168.0.30         anywhere
ACCEPT     tcp  --  anywhere             anywhere            tcp spt:ssh
DROP       tcp  --  anywhere             anywhere            tcp dpt:telnet

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

So now if 192.168.0.30 tries to connect to our local machine it would get a request time out.

Other commands to view the iptables
# iptables -L -v
Chain INPUT (policy ACCEPT 
2559 packets, 223K bytes)
 pkts bytes target     prot opt in     out   source        destination
    0    0 DROP       all  --  any    any   192.168.0.30    anywhere
    0    0 ACCEPT     tcp  --  any    any   anywhere        anywhere            tcp spt:ssh
    0    0 DROP       tcp  --  any    any   anywhere        anywhere            tcp dpt:telnet

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 297 packets, 40151 bytes)
 pkts bytes target     prot opt in     out     source               destination
Here -v reveals bytes in (k/M/G) which means the bytes of packets blocked or allowed for any rule which was applied in iptables

# iptables -L --line-numbers
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination
   DROP       all  --  192.168.0.30         anywhere
   ACCEPT     tcp  --  anywhere             anywhere          tcp spt:ssh
   DROP       tcp  --  anywhere             anywhere          tcp dpt:telnet

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination

# iptables --list
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
DROP       all  --  192.168.0.30         anywhere
ACCEPT     tcp  --  anywhere             anywhere            tcp spt:ssh
DROP       tcp  --  anywhere             anywhere            tcp dpt:telnet

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Appending/Inserting rules

You can either Append a new rule into any chain or you can insert the rule where the difference is while appending the rule will end up in the last row while if you want your rule to be preferred first beofre any other rule in the chain then use INSERT along with iptables as shown below

# iptables -I INSERT -s 192.168.0.30 -j DROP

Some more examples
Create a rule to permit ssh connection from everyone to your local machine
# iptables -A INPUT -p tcp --dport 22 -j ACCEPT

Create a rule to deny telnet access from everyone to your local machine
# iptables -A INPUT -p tcp --dport telnet -j DROP

Deleting rules

For deleting any rule from the chain you will require line number

For Example:
# iptables -L --line-numbers
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination
1    DROP       all  --  192.168.0.30         anywhere
2    ACCEPT     tcp  --  anywhere             anywhere          tcp spt:ssh
3    DROP       tcp  --  anywhere             anywhere          tcp dpt:telnet

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination

Suppose I want to delete the rule for source 192.168.0.30
# iptables -D INPUT 1

In case you want to go the hard way, you will have to delete rule on the basis of the first match by giving the complete rule along with D switch
# iptables -D INPUT -s 192.168.0.30 -j DROP

Replace rules

You can also replace rules instead of deleting and creating any rule if there are some change which you want to do.

For example in the above question suppose we want to block communication from 192.168.0.25 instead of 192.168.0.30 so we can easily replace the rule

# iptables -R INPUT 1 -s 192.168.0.25 -j DROP

Saving or Restoring rules in iptables

# iptables -save (defaults dumps to STDOUT)

# iptables -restore (default reads rule from STDIN)

Example:
# iptables-save > rules.txt
# iptables-restore < rules.txt

Flushing rules

This term is used to delete all the rules from all the chains.
# iptables -F

This command will temporarily remove all the rules but once you restart your iptables services all the rules will come back to default setup.

Creating user defined chains

Now by default as I had said in my last post Basic iptables tutorials in Linux I 3 chains are present in iptables which are NAT, filter and mangle but what if you want to create or add an extra CHAIN, so is it possible?

Well the answer is YES, you can create a new chain and use it as per your requirement where mostly this is done to reduce the complexity.
To create a new chain
# iptables -n INTRANET
This will create a new chain

You can verify the same
# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain INTRANET (o references)
target     prot opt source               destination

Now as you can see above a new chain has been created now you need to divide the traffic or rules toINTRANET chain as per your requirement. Now for our case we can take any example to show you how it works

Create references for user defined chain

For our scenario we want all the rules for source 192.168.0.0/24 should be under INTRANET chain so remove the complexity as I don't want to struggle find my rules in the complete rules list as it can be very hectic with more than 100 rules.# iptables -I INPUT 1 -s 192.168.0.0/24 -j INTRANET
So as per the above rule I am creating and inserting a new rule inside INPUT chain at no. 1 position as I want to give this rule max priority which says any rule which is created with source IP 192.168.0.0/24will be visible under INTRANET chain.

# iptables -I INTRANET -p tcp --dport telnet -j DROP
So as per the above rule I am inserting a new rule inside INTRANET chain for source 192.168.0.0/24(as we have already defined this IP source using our last rule for INTRANET chain) connection to telnet port 23 should be dropped.

Now lets see if our rule has been implemented properly using
# iptables -L INTRANET
Chain INTRANET (1 references)
target     prot opt source               destination
DROP       tcp  --  anywhere             anywhere            tcp dpt:telnet

As per the above rule list any connection coming from 192.168.0.0/24 using port 23 will be dropped.

Rules can be varied for various sport, dport, source destination inside any user defined chain.

Some more example
Block port 22 from 192.168.0.30 for the local machine inside INTRANET chain.
# iptables -A INTRANET -s 192.168.0.30 -p tcp --dport 22 -j DROP
So as you see in the above rule I am appending a new rule inside INTRANET chain for source 192.168.0.30 and blocking communication from port no. 22

Rename user defined chain

# iptables -E old_chain_name  new_chain_name
# iptables -E INTRANET EXTRANET
# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
EXTRANET   all  --  192.168.1.0/24       anywhere

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain EXTRANET (1 references)
target     prot opt source               destination


Delete user defined chain

NOTE: Make sure the chain you are deleting has no rules in it
# iptables -X INTRANET
IMPORTANT NOTE: Default chains cannot be deleted

Chain Policies

By this term I mean the default policies for all the chains which most of us miss. In case you re look at the chains below, consider the highlighted term.
# iptables -L
Chain INPUT 
(policy ACCEPT)
target     prot opt source               destination
INTRANET   all  --  192.168.0.0/24       anywhere
ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED
ACCEPT     icmp --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ssh
REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain INTRANET (1 references)
target     prot opt source               destination
DROP       tcp  --  anywhere             anywhere            tcp dpt:telnet

Now as you see by default all the chains have default ACCEPT policy which can be dangerous for critical machines as apart from any rule which you have created all other connections are allowed.

Change default policies of chains

Now since we have created a new chain so we should change the default policy of INPUT chain as we only want those users to communicate with us whom we have allowed in our rules
# iptables -P INPUT DROP

NOTE: Default DROP policy may prevent typical TCP/UDP/ICMP communications
TCP - uses 3-way handshake
1. SYN
2. SYN-ACK
3. ACK

# iptables -L INPUT
Chain INPUT 
(policy DROP)
target     prot opt source               destination
INTRANET   all  --  192.168.0.0/24       anywhere
ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED

So as you see now only those machines will be allowed to communicate with us which you will allow through rules in your machine.

TCP Matches - Connection Oriented


  1. TCP works on layer 4 also known as Connection oriented protocol. 
  2. TCP packets contains information of sender as well as receiver.
  3. Eg: HTTP, FTP, telnet etc
The syntax used
-p tcp, --protocol tcp

--sport,--source-port
NOTE: The source port is generally picked arbitrarily from > 1024

Example:
Block telnet connection from 192.168.1.0/24 for localhost using EXTRANET chain
# iptables -A EXTRANET -p tcp --dport telnet -j DROP

UDP Matches: - Connectionless


  1. UDP works on Layer 4 and is considered connection less protocol. 
  2. UDP considered packets are considered much faster as compared to TCP because they are not as heavy as TCP as they do not contain much details on the packet. 
  3. These are generally used for broadcasting.
  4. Eg: DNS, DHCP, syslog, NTP etc

The syntax used
-p udp, --protocol udp
--sport,--source-port - same source port as destination port


Internet Control Messaging Protocol (ICMP)

ICMP Types:
a. echo-request - PING
b. echo-reply - pong
PING - local system sends via OUTPUT chain an echo-request(PING)
Remote system received echo-request in its INPUT chain => Remote system responds with an echo-reply(Pong)

The sysntax used
-p icmp, --protocol icmp

For more details on icmp ping protocol usage follow the below link

Match multiple ports with fewer rules

Now suppose you want to block multiple ports more than 5-6 for the same machine so imagine you will have to write 5-6 rules which will make the rules list look messy which you can fix by using a single rule for multiple ports.

Let me give you an example

Block connection from 192.168.0.100 from port 22,23,80,8080 to your machine in a single rule
# iptables -A INTRANET -s 192.168.0.30 -p tcp -m multiport --dport 22,23,80,8080 -j DROP
Here in above rule I am appending a new rule in INTRANET chain for source 192.168.0.30 defining that the rule is for multiple ports using -m switch for --dport 22,23,80,8080 to drop any connection from these ports.

Lets see if our rule was implemented properly
# iptables -L INTRANET

Chain INTRANET (1 references)
target     prot opt source               destination
DROP       tcp  --  anywhere             anywhere            tcp dpt:telnet
DROP       tcp  --  192.168.0.30         anywhere            multiport dports ssh,telnet,http,webcache


Block the above ports for all machines from source 192.168.0.0/24
# iptables -A INTRANET -p tcp -m multiport --dport 22,23,80,8080  -j DROP

NOTE: Maximum of 15 ports can be blocked or permitted in a single rule

MAC address level filtering

Suppose you have blocked any source with IP 192.168.0.100 from connecting your machine, but what if it chages its ip to some other range. In that case your machine is not secure any more. So for these cases we use MAC address filtering where you block the MAC ID of the source machine from connection.This is a layer 2 blocking i.e. Data Link Layer

Block connection from machine with mac id 00:0C:29:BD:AC:81 from connecting your machine using port 23
# iptables -A INPUT -p tcp -m mac --mac-source 00:0C:29:BD:AC:81 --dport 23 -j DROP

# iptables -L INPUT
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
DROP       tcp  --  anywhere             anywhere            MAC 00:0C:29:BD:AC:81 tcp dpt:telnet

Log iptables traffic

Now how do you collect logs for all the rules in your iptables? 

By default all the generated logs are stored in /var/log/messages and it not easy to look out for particularly iptables log inside /var/log/messages as it stores many other logs as well. So it is always a good idea to use a different file for iptables logs

NOTE: To enable logging by firewall we need to enable kernel level logging in the linux machine

Follow these steps for the same
# vi /etc/rsyslog.conf (In RHEL 5 or older /etc/syslog.conf) #### RULES ####

# Log all kernel messages to the console.
# Logging much else clutters up the screen.
kern.*                                                 /var/log/firewall.log
Uncomment the above line and make necessary change as shown with blue color

# Log anything (except mail) of level info or higher.
# Don't log private authentication messages!
*.info;mail.none;authpriv.none;cron.none;kern.none                /var/log/messages
Add an extra word "kern.none" as shown above

Restart the services
# service rsyslog restart

For RHEL 5 or older
# service syslog restart

Create a new rule to log all the taffic for telnet port
# iptables -A INPUT 1 -p tcp --dport telnet -j LOG

Now I will try to do telnet to my linux box(10.10.20.26) from source (10.10.20.30)
Let us check the log generated in firewall.log
# less /var/log/firewall.log
Sep 16 12:23:34 localhost kernel: IN=eth0 OUT= MAC=00:0c:29:bd:ac:80:ac:16:2d:00:00:87:08:00
SRC=10.10.20.30 DST=10.10.20.26 LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=12317 DF PROTO=TCP SPT=58754DPT=23 WINDOW=8192 RES=0x00 SYN URGP=0

Examples
Log all the traffic for ssh and telnet port on 10.10.20.26
# iptables -A INPUT -d 10.10.20.26 -p tcp -m multiport --dport 22,23 -j LOG

# less /var/log/firewall.log
Sep 16 12:32:22 localhost kernel: IN=eth0 OUT= MAC=00:0c:29:bd:ac:80:ac:16:2d:00:00:87:08:00
SRC=10.10.20.30 DST=10.10.20.26 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=4022 DF PROTO=TCP SPT=58707DPT=22 WINDOW=256 RES=0x00 ACK URGP=0 

Sep 16 12:32:22 localhost kernel: IN=eth0 OUT= MAC=00:0c:29:bd:ac:80:ac:16:2d:00:00:87:08:00SRC=10.10.20.30 DST=10.10.20.26 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=4023 DF PROTO=TCP SPT=58707DPT=22 WINDOW=246 RES=0x00 ACK URGP=0
So as you see a log has been reported for the attempt of connection inside firewall.log

But again what if you have created a log entry for multiple ports and sources so for those cases you can use --log-prefix to distribute the log traffic and makes easy visibility inside log.

LOG PREFIX

Examples:

# iptables -A INPUT -d 10.10.20.26 -p tcp -m multiport --dport 22,23 -j LOG --log-prefix "SSH ACCESS ATTEMPT: "

# less /var/log/messages
Sep 16 12:34:49 localhost kernel: 
SSH ACCESS ATTEMPT: IN=eth0 OUT= MAC=00:0c:29:bd:ac:80:ac:16:2d:00:00:87:08:00 SRC=10.10.20.30 DST=10.10.20.26 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=11101 DF PROTO=TCP SPT=58707 DPT=22 WINDOW=2429 RES=0x00 ACK URGP=0

Sep 16 12:34:49 localhost kernel: 
SSH ACCESS ATTEMPT: IN=eth0 OUT= MAC=00:0c:29:bd:ac:80:ac:16:2d:00:00:87:08:00 SRC=10.10.20.30 DST=10.10.20.26 LEN=92 TOS=0x00 PREC=0x00 TTL=64 ID=11102 DF PROTO=TCP SPT=58707 DPT=22 WINDOW=2429 RES=0x00 ACK PSH URGP=0
We can create a new chain which will contain all the log related rules
# iptables -N LOGGER

# iptables -I INPUT 1 -j LOGGER

So here we are creating a refrence where all the INPUT chain traffic will take the refrence of LOGGER chain for additional rules.
# iptables -I LOGGER -m multiport --dport 80,443,22,23 -j LOG
Here we are creating a rule for LOGGER chain to log all the traffic on ports 80,443,22 and 23

No comments: