Iptables

From Dikapedia
Jump to: navigation, search

iptables/ip6tables -- administration tool for IPv4/IPv6 packet filtering and NAT


AWS Specific:
In normal circumstances we do not use iptables to block traffic in AWS. We rely on the security groups and Network ACLs for this purpose. iptables on an instance is normally used for NAT instances or instance-based VPN, i.e. OpenSwan, OpenVPN, StrongSwan or Sophos UTM.


You can sometimes use iptables to block traffic on an instance. For example, using fail2ban to protect websites from attackers, while allowing legitimate traffic to pass uses iptables.


Iptables


The Linux kernel comes with a packet filtering framework named netfilter. It enables you to allow, drop and modify traffic leaving in and out of a system. Iptables builds upon this functionality to provide a powerful firewall which you can configure by adding rules.

How does iptables work?

  • Iptables is a cmd line interface to the packet filtering functionality in netfilter.
  • Iptables’ packet filtering mechanism is divided into three kinds of structures:
    - Tables; allows you to process packets in specific ways. Default table is the filter table.
    - Chains; attached to tables, these allow you to inspect traffic at various points, such as when they just arrived on the network interface or just before they’re handed over to a process.
    - Targets; decides the fate of a packet such as allowing or rejecting it.


Iptables diagram.png

Tables

In modern Linux distro there are four tables:

  • Filter table - default, most widely used table. Used to make decisions about whether a packet should be allowed to reach its destination.
  • Mangle table - allows you to alter packet headers in various ways, such as changing TTL values. (Time to live)
  • Nat table - allows you to route packets to different hosts on NAT (network address translation) networks by changing the source and destination addresses of packets. Often used to allow access to services that can’t be accessed directly, because they’re on a NAT network.
  • Raw table - Iptables is a stateful firewall, which means that packets are inspected with respect to their “state”. Allows you to work with packets before the kernel starts tracking its state. Can also exempt certain packets from the state-tracking machinery.

(bonus: Security table - some kernels have this which is used by SELinux to implement policies based on SELinux security contexts)


Chains


The previous tables are composed of a few default chains. These chains allow you to filter packets at various points:

  • Prerouting chain: Rules in this chain apply to packets as they arrive on the network interface.
  • Input chain: apply to packets just before they’re given to a local process. This chain is present in the mangle and filter tables.
  • Output chain: apply to packets just after they’ve been produced by a process. This chain is present in the raw, mangle, nat and filter tables.
  • Forward chain: apply to any packets that are routed through the current host. This chain is only present in the mangle and filter tables.
  • Postrouting chain: apply to packets as they just leave the network interface. Present in nat and mangle tables.


Targets


So chains allow you to filter traffic by adding rules to them. Ie. add rule on the filter table’s INPUT chain to match traffic on port 22. This is where targets come in. They decide the fate of the packet.

Terminating targets - some targets decides the matched packet’s fate immediately and doesn’t match against any other rules. Common terminating targets:

  • ACCEPT: causes iptables to accept the packet
  • DROP: iptables drops the packet. (appears as if the system doesn’t even exist)
  • REJECT: iptables “rejects” the packet. Sends a “connection reset” packet in case of TCP, or “destination host unreachable” in cases of UDP or ICMP.

Non-terminating targets - keep matching other rules even if a match was found. Ie. the built-in LOG target. When a matching packet is received, it logs about it in the kernel logs, However iptables keeps matching it with the rest of the rules too. (not sure if I understand this yet)


How to use the iptables command



Must be root or run commands using sudo.


Listing Rules


Once you’ve blocked a couple IPs by appending rules, to see these rules, use the -L option. v option is for showing the info in a more detailed format (shows packets and bytes).

iptables -L
iptables -L --line-numbers 
iptables -L -v 

Iptables will try to be helpful by doing reverse DNS lookups on the IPs. This can make the listing process slow. To disable add ‘-n’ option:

iptables -L -n --line-numbers

Another good one: --list-rules

iptbables -S


Deleting Rules


To delete a specific rule, use the -D option. But first, it's a good idea to check all the available rules by runing $ iptables -L --line-numbers:

iptables -D INPUT 2

Can also delete rules through without using rule numbers:

iptables -D INPUT -s x.x.x.x/x -J REJECT

Delete rules by line number can get messy, so be sure to delete the higher numbers first so the order doesn’t change, and that way you won’t delete the wrong rule!

iptables -D INPUT 12
iptables -D INPUT 9

To delete (flush) ALL rules in a chain:

iptables -F
iptables -F INPUT


Blocking IP's


Most common use for firewall is to block IPs.

To block all incoming packets from an IP address:

iptables -t filter -A INPUT -s [IPaddress] -j REJECT
  • The -t switch specifies the table in which our rule would go into - in our case, it’s the filter table.
  • The -A switch tells iptables to “append” it to the list of existing rules in the INPUT chain. However if this is the first time you’re working with iptables, there won’t be any other rules, this will just be the first one.
  • The -s switch simply sets the source IP.
  • The -j switch tells iptables to “reject” traffic by using the REJECT target. If you want iptables to not respond at all, you can use the DROP target.

Filter table is used by default, so you can actually just leave “filter” out of the command. INPUT for incoming traffic. OUTPUT for outgoing traffic.

iptables -A INPUT -s [ipaddress] -j REJECT

If you want to block IP ranges by using CIDR notation. I.e. ranging from 59.145.175.0 to 59.145.175.255 use:

iptables -A INPUT -s 59.145.175.0/24 -j REJECT

It is a good idea use the DROP target for all other traffic after defining -dport rules. This will prevent an unauthorized connection from accessing the server via other open ports. Tthe connection outside the specfied port will be dropped. To achieve this:

sudo iptables -A INPUT -j DROP


If you want to block outbound traffic to an IP, you should use the OUTPUT chain + -d flag to specify the destination IP:

iptables -A OUTPUT -d [ipaddress] -j DROP


Blocking Invalid TCP Packets with the TCP Module


The ‘tcp’ module has a ‘--tcp-flags’ switch, used to check individual TCP flags. ‘--tcp-flags takes two arguments:

  • A “mask” - selects the flags that should be checked
  • A set of “compared flags” - selects the flags that should be set in the packet.

I.e. You want to block “Christmas tree packets”. You need to check “all” the flags, but only FIN, PSH and URG will be set.

iptables -A INPUT -p tcp -m tcp --tcp-flags ALL FIN,PSH,URG -j DROP

There are other types of invalid packets you could reject too. I.e. a packet with SYN and FIN set is invalid. In this case you need to only check for these flags and verify if they’re set:

iptables -A INPUT -p tcp -m tcp --tcp-flags SYN,FIN SYN,FIN -j DROP

Another kind of invalid packet: I.e. a “new” connection that doesn’t begin with a SYN. Here you simply need to check the FIN,RST,ACK and SYN flags; however only SYN should be set. Then you can negate this condition. Finally you can use conntrack to verify if the connection is new:

iptables -A INPUT -p tcp -m conntrack --ctstate NEW -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -j DROP

NEW: this state represents the very first packet of a connection.


Enabling Connections on HTTP, SSH, and HTTPS

Examples:

iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

My Way:

iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT


Inserting and Replacing Rules


-I’ for insert

If you need to block IP addresses coming from ‘172.10.20.0/24’ EXCEPT for IP address ‘172.10.20.10’, you would need to add a rule where you ACCEPT ‘172.10.20.10’ on a line first BEFORE adding rule to DROP ‘172.10.20.0/24’.
(notice INPUT 1 for line 1)

iptables -I INPUT 1 -s 172.10.20.10 -j ACCEPT 
iptables -I INPUT 2 -s 172.10.20.0/24 -j DROP

Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 ACCEPT all -- 172.10.20.10 0.0.0.0/0
2 DROP all -- 172.10.20.0/24 0.0.0.0/0
3 DROP all -- 221.192.0.0/20 0.0.0.0/0
4 DROP all -- 91.197.232.104/29 0.0.0.0/0

-R’ for replace Perhaps you whitelisted the wrong IP, to replace

iptables -R INPUT 1 172.10.20.11 -J ACCEPT (notice the line number)


Filtering Packets Based on Source IP


To accept packets from a specific, 192.168.1.3:

sudo iptables -A INPUT -s 192.168.1.3 -j ACCEPT    # where -s is source IP

To reject packets from a specific IP, replace target ACCEPT to DROP:

sudo iptables -A INPUT -s 192.168.1.3 -j DROP      

To drop packets from a range of IP addresses, use the -m flag (module) and iprange module. Then specify the IP address range with the -src-range flag. *Note, use a hyphe ‘-’ in to separate the range of IP addresses:

sudo iptables -A INPUT -m iprange --src-range 192.168.1.100-192.168.1.200 -j DROP


Protocols and Modules


Say you want to block all incoming TCP traffic. Use ‘-p’ to specify protocol (not a likely example, just an example)

iptables -A INPUT -p tcp -j DROP

(more useful example) Say you need to block SSH access for an IP range. You have to specify the protocol like above, -p tcp, to match all TCP traffic. Then to check the destination port you should first load the tcp module with -m. Next check if the traffic is intended to the SSH destination port using --dport.
(not sure I understand the -m part)

iptables -A INPUT -p tcp -m tcp --dport 22 -s 172.10.20.0/ -j DROP

Say you want to block SSH(22) AND VNC(5901). While you cannot specify multiports with the tcp module, you can do so with the ‘multiport’ module. So it would be like,

iptables -A INPUT -p tcp -m multiport --dport 22,5901 - s 172.10.20.0/24 -j DROP

Say you want to block ICMP address mask requests (type 17). (? what is that?). Module -m would be -m icmp, and then add the mask request type --icmp-type 17.

iptables -A INPUT -p icmp --icmp-type 17 -j DROP


The Connection Tracking Module


(v. important module)

If you block an IP on the INPUT chain, you will not be able to access the services hosted on those IPs either! Why? Are the rules in the INPUT chain affecting the traffic on the OUTPUT chain?

  • No. The packets from your system DO reach the server of that IP, but the packets coming from that system to yours is getting rejected.


‘Conntrack’ or connection tracking module will allow us to tell iptables to not touch packets that are part of an existing connection. Connections tracked by this module will be in one of the following states:

  • NEW: this state represents the very first packet of a connection.
  • ESTABLISHED: This state is used for packets that are part of an existing connection. For a connection to be in this state it should have received a replace for the other host.
  • RELATED: used for connections that are related to another ESTABLISHED connection. I.e. FTP data connection - they’re “related” to the already “established” control connection.
  • INVALID: This state means that the packet doesn’t have a proper state. This may be due to several reasons like the system running OOM or due to some types or ICMP traffic.
  • UNTRACKED: Any packets exempted from a connection tracking in the raw table with the NOTRACK target end up in this state.
  • DNAT: This is a virtual state used to represent packets whose destination address was changed by rules in the nat table.
  • SNAT: Like DNAT, this state represents packets whose source address was changed.


You should place this rule at the very top. (if it isn’t the first rule, use -I to insert at the top). --ctstate sets the state

iptables -A INPUT -m conntrack --ctstate RELATED, ESTABLISHED -j ACCEPT

It’s generally a good idea to drop any packets in INVALID state. You can place it just below the position where you placed the above rule.

iptables -A INPUT -m conntrack -ctstate INVALID -j DROP


Changing the Default Policy


-P’ change default policy

Say you don’t want any local programs to receive inbound connections. Once you’ve set iptables to accept packets from RELATED and ESTABLISHED connections, you can switch the INPUT chain policy to DROP:

iptables -P INPUT DROP

Keep in mind! You should first accept packets from established and related connections before using this rule. If you don’t you will find that you cannot use any internet based applications because the responses coming in through the INPUT chain will be dropped.


Selecting Interfaces


Things can get slow when there are a lot of rules because iptables matches packets to every rule in a chain. So it is useful to exempt certain kinds of traffic.

-i’ specifies the input interface.

iptables -A INPUT -i lo -j ACCEPT

An example for this would be Nginx/PHP-FPM stack; Nginx communicates with PHP over localhost so it uses ‘lo’ loopback interface. (useless to filter this traffic so you can allow it).

-o’ specifies the output interface on the OUTPUT chain. Example: Want to block an advertiser when you’re on WiFi. The advertiser uses the IP 121.1.238.0/29 and the WiFi interface is wlan0. (?)

iptables -A OUTPUT -o wlan0 -d 121.18.238.0/29 -j DROP


Limiting Packets: The Limit Module


-m limit’ module places a limit to the number of packets passing through.
Analogy: you have 5 tokens, every time a packet arrives you must throw out one token. If you’re out of tokens you cannot accept anymore packets. BUT you can add a token every 10 min. So after 50 min you will have accepted 5 more packets.
This is useful for suppressing log messages.

I.e. suppose you want to ratelimit ICMP packets (remember what ICMP was?):

iptables -A INPUT -p icmp -m limit --limit 1/sec --limit-burst 1 -j ACCEPT
  • Limit-burst’ is the number of tokens
  • Limit’ is the rate at which you can refill your tokens.

As long as traffic is within the limits, packets will be accepted.

As soon as the flow of packets exceed this limit, the traffic passes through this rule and on to other rules. Thus, you should set a default policy of DROP on the INPUT chain for this to work. (? not sure if I understand this 100%)

Unfortunately, the limit module cannot handle a dynamic, per IP restriction. This is where the recent module comes in…. (see next section)


Per-IP packet limits: the recent module


Say you’ve been facing some brute force attacks on your SSH server. Usually, attackers try to make any connections to speed up their attack. So you can place a per-IP restriction like so:

iptables -A INPUT -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -m recent --set --name SSHLIMIT --rsource
iptables -A INPUT -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -m recent --set --name SSHLIMIT --update --seconds 180 --hitcount 5 --name SSH --rsource -j DROP

--name is for the limit module so we can keep track of it.
The first line adds the source IP to the list that the recent module maintains.
If the IP is already on the list, then the entry for this IP is updated.
In the next line, we check whether the counter has hit the value of 5 in 180 seconds. If that If that’s the case, we drop the packet. Thus, allows 4 new SSH connections from an IP in 3 minutes.

Some recent kernels also have a ‘--mask’ parameter which allows you to put restrictions on IP ranges.I.e. If you want to do restrict an entire /24, you can run:

iptables … -m recent … --mask 255.255.255.0


The Owner Module


On a home computer, it’s often useful to block traffic on a per user basis. The owner module can help with this.

I.e. Say you use a shared computer at your home. You’d like to block a particular website which has the IP x.x.x.x for your child. Assume that your child uses an account with the username “baby”. So the iptables rule will be:

iptables -A OUTPUT -d x.x.x.x -m owner --uid-owner baby -j DROP

You can also use a numeric user ID or a range (such as 1000-10006) for the argument. Similarly you cannot match packets of a group by using the --gid-owner packet.

The owner module is valid only in the OUTPUT and POSTROUTING chains.


Custom Chains


Sometimes you may need to do complex processing on the same packet over and over. I.e. say you want to allow SSH access for just a couple of IP ranges. So far we’ve seen:

iptables -A INPUT -p tcp -m tcp --dport 22 -s x.x.0.0/16 -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 22 -s x.y.0.0/16 -j ACCEPT
iptables -A INPUT -p tcp -m tcp --dport 22 -j DROP

Unfortunately, this is a bit unwieldy and inefficient.

Instead you can organize these rules to be ‘custom chains’.

First you need to make a custom chain, we’ll name ours ‘ssh-rules’

iptables -N ssh-rules

Then, you can add the rules for the IPs in the new chain. Since custom chains don’t have a default policy, make sure you end up doing something to the packet. Here, we’ve added a last line that drops everything else. There’s also a RETURN target, which allows you to return to the parent chain and match the other rules there.

iptables -A ssh-rules -s x.x.0.0/16 -j ACCEPT
iptables -A ssh-rules -s x.y.0.0/16 -j ACCEPT
iptables -A ssh-rules -j DROP

Now you should put a rule in the INPUT chain that refers to it:

Iptables -A INPUT -p tcp -m tcp --dport 22 -j ssh-rules

Pro of using custom chain: you can entirely manage this chain through a script and you don’t have to worry about interfering with the rest of the chain.

If you want to delete this chain, you should first delete any rules that reference to it.To remove chain:

iptables -X ssh-rules


Logging Packets: the LOG target


It logs the nature of the packet matched in the kernel logs (/var/log/messages, /var/log/syslog)

Easy to use. I.e. say you want to log invalid TCP packets before dropping them. You should first log the packet, and then drop it:

iptables -A INPUT -p tcp -m tcp --tcp-flags SYN, SYN FIN, FIN -j LOG
iptables -A INPUT -p tcp -m tcp --tcp-flags SYN, SYN FIN, FIN -j DROP

The LOG target also takes a --log-prefix option. You can use this so tat you can search the log easily later.

iptables -A INPUT -p tcp -m --tcp-flags SYN, SYN FIN, FIN -j LOG --log-prefix=iptables:


Preserving Iptables rules across reboots


IPtables is not persistent. They’re lost when you reboot your system.

There are many ways to doing it. Please see the articles below and test it on your system to see which one works for you.

In RHEL/CENTOS there’s a package named ‘iptables-services.'

sudo yum install iptables-services

In Debian/Ubuntu, you can install the ‘iptables-persistent’ package that does the same thing

sudo apt install iptables-persistent.

Both of these packages run the iptables-save/restore commands to save iptables configuration to a file.

To save iptables rules:

/sbin/iptables-save
iptables-save

# Or Try the below command saves the rules to the file system, and iptables restart will not affect them.
service iptables save


These commands dump rules from all chains and filters into standard output. You can redirect it to a file like so:

iptables-save > iptables.rules

Now you can edit this file comfortably with a text editor. When you’re done you can apply these rules with:

iptables-restore < iptables.rules


If your distribution doesn’t have a similar package, you can simply write a service file that loads iptables rules from a while when it starts up, and saves it when it stops.


Check out link for more instructions:

[+] https://www.thomas-krenn.com/en/wiki/Saving_Iptables_Firewall_Rules_Permanently

[+] https://support.plesk.com/hc/en-us/articles/213404549-Firewall-rules-disappeared-after-restarting-iptables

[+] An In-Depth Guide to iptables, the Linux firewall


Real World Examples (Cases from work)