Category: iptables

Linux iptables – creating a firewall script

By peter, September 13, 2009

Linux firewalls use iptables. The best way of creating a firewall with iptables is to write a scripts.

The first thing you need to do in your script is to write a routine that deletes out any previous firewall rules (flushing) and then blocks everything. Once you have blocked everything, you can start building your firewall to filter and allow connections as needed.

Creating a script
Create a script called firewall.sh. Change permissions on the file so that it is executable with the chmod command as follows:

chmod 777 firewall.sh

Save the file in /usr/local/sbin directory. If you do this you will be able to run the script from anywhere within the directory structure by typing “firewall.sh”

Declaring your network cards

In order for your firewall script to be more readable you could declare your network cards at the top of the script as follows:

EXT=eth0
INT=eth2
DMZ=eth1

From now on you use $EXT when referring to eth0 and $INT when referring to eth1, and so on.

Flushing all your rules

The next thing is to flush the Filter table. You will also need to flush any NAT tables. This can be accomplished with the “iptables -F” command. Type the following into your script. The -F serves to flush the tables.

iptables -t nat -F
iptables -t mangle -F
iptables -t filter -F

Logging
One of the important things needed on a firewall is a logging system. To set up logging on your firewall you need to add the following right a the bottom of your firewall.

iptables -A INPUT -j LOG –log-prefix “Denied INPUT:”
iptables -A OUTPUT -j LOG –log-prefix “Denied OUTPUT:”
iptables -A FORWARD -j LOG –log-prefix “Denied FORWARD:”

Enabling logging for your firewall will enable trouble shooting.
By default, on some distros, the firewall logging is captured in the /var/log/messages file. SuSE logs firewall errors in another location, “/var/messages/firewall”

Setting up a default policy to block all
The default policy for the INPUT, OUTPUT and FORWARD filters table should be DROP/DENY all packets. After you have flushed all the tables you can set the firewall to “drop all” by default. Once you have set the firewall to drop all by default you can go about opening the ports you need.

Below the section for flushing your firewall you can add the following to “drop” all in each of the filter tables:

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

Anything that doesn’t match any of the policies that follow, will be subject to the default policy, which in this case is “DROP”. In this case because we haven’t created any policies yet, everything will be dropped.

Your firewall.sh file should look like the following:
——————————————————————————————-
#!/bin/bash
EXT=eth0
INT=eth2
DMZ=eth1
# flush
iptables -t nat -F
iptables -t mangle -F
iptables -t filter -F
# Default policy set to DROP all
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
# Logging rules – always at the END of the script
iptables -A INPUT -j LOG –log-prefix “Denied INPUT: ”
iptables -A OUTPUT -j LOG –log-prefix “Denied OUTPUT: ”
iptables -A FORWARD -j LOG –log-prefix “Denied FORWARD: “

——————————————————————————————-

INPUT and OUTPUT

We want to be able to ping another computer from our firewall server, we also want to be able to receive a reply from the computer we ping.

You can accomplish this with OUTPUT and INPUT Policies
If your firewall server offers services other than a firewall or if you are putting a firewall on a “standalone” server, you will need to filter connections coming in to the service/s your server offers as well as filter connection originating from the server’s service/s. This is usually the case as you would normally have “ssh” setup on the firewall server for administration purposes. You might want to allow pings to and from the server. Another example of this would be if your server acted as a proxy server, web server or mail server in addition to being a firewall.
For connections originating from the server’s service you will need to use the “OUTPUT” policy to filter outbound connections.

For connections to the server’s services you will need to use the “INPUT” policy.

In other words, the INPUT and OUTPUT policies only effects the “loca” computer, and not any connections that pass through the “local” computer/firewall (for this you need a FORWARD policy).

OUTPUT Policy

To allow outbound connections from your computer you need to add a rule similar to the following:

iptables -A OUTPUT -p tcp –dport 22 -j ACCEPT

The above rule will allow the protocol TCP, port 22 outbound. The following rule will allow ping traffic out:

iptables -A OUTPUT -o $EXT -p icmp –icmp-type ping -j ACCEPT

Have a look at the rules above, notice that you can specify the following:

1. A protocol with the -p option

2. A protocol type as with the icmp protocol, –icmp-type

3. Destination port with the –dport option

INPUT Policy

To allow inbound traffic you will need to add an INPUT rule. To allow TCP on port 22 inbound you would type the following:

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

To allow inbound icmp protocol for ping/pong you will need to type the following:

iptables -A INPUT -i $EXT -p icmp –icmp-type pong -j ACCEPT

It makes sense that if you want a computer to ping and be pinged you then you will need to allow both ping and pong inbound and outbound.
—————————————————————————————————
#!/bin/bash
EXT=eth0
INT=eth2
DMZ=eth1
# flush
iptables -t nat -F
iptables -t mangle -F
iptables -t filter -F
# Default policy set to DROP all
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
# Allow us to ping other machines
iptables -A OUTPUT -o $EXT -p icmp –icmp-type ping -j ACCEPT
iptables -A INPUT -i $EXT -p icmp –icmp-type pong -j ACCEPT
# Allow other machine to ping us
iptables -A INPUT -i $EXT -p icmp –icmp-type ping -j ACCEPT
iptables -A OUTPUT -o $EXT -p icmp –icmp-type pong -j ACCEPT
# Logging rules – always at the END of the script
iptables -A INPUT -j LOG –log-prefix “Denied INPUT: ”
iptables -A OUTPUT -j LOG –log-prefix “Denied OUTPUT: ”
iptables -A FORWARD -j LOG –log-prefix “Denied FORWARD: “

————————————————————————————————

In the above example you could leave off the icmp type and just allow all icmp traffic inbound and out bound as follows:

iptables -A INPUT -i $EXT -p icmp -j ACCEPT
iptables -A OUTPUT -o $EXT -p icmp -j ACCEPT

Without specifying the icmp type the firewall will allow all icmp types, this means that the above rules will allow pings and pongs in and out on the external network card

TIP – You will need to allow �loopback� connections with a rule similar to the following:

iptables -A OUTPUT -o lo -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT

These rule will allow service on the computer to communicate via loopback if needed. These rule should be place near the top of the script under the “block all” policy. Some service will not work correctly if this is not enabled.

ESTABLISHED and RELATED rules

Some services will listen on one port and offer a service on another port, sometimes these ports are random. You don’t want these ports to be open all the time as this would constitute a security risk. ESTABLISHED and RELATED rules will allow you to open these ports for the duration of the connection. In other words, allow the connection on another port that is normally closed, if the requested port is part of or related to another already established connection.
You can also use the ESTABLISHED and RELATED rule to allow the reply from a ping, this is because the reply (pong) is related to the ping. This means you can get rid of the “pong accept” rule if you use the ESTABLISHED and RELATED rule. The syntax for this is as follows:

iptables -A INPUT -m state -i $EXT –state ESTABLISHED,RELATED -j ACCEPT

Notice that you can specify the following:

1. The state with the –state option
2. The interface with the -i option

You will need one for each filter. (INPUT and OUTPUT) his should be added to your firewall script.
Your firewall script should now look like the following:

—————————————————————————————————
#!/bin/bash
EXT=eth0
INT=eth2
DMZ=eth1
# flush
iptables -t nat -F
iptables -t mangle -F
iptables -t filter -F
# Default policy set to DROP all
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
#Loopback accept rule
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
# Allow us to ping other machines
iptables -A OUTPUT -o $EXT -p icmp –icmp-type ping -j ACCEPT
#iptables -A INPUT -i $EXT -p icmp –icmp-type pong -j ACCEPT
# Allow other machine to ping us
iptables -A INPUT -i $EXT -p icmp –icmp-type ping -j ACCEPT
#iptables -A OUTPUT -o $EXT -p icmp –icmp-type pong -j ACCEPT
# Allow reply packets to established and/or related connections
iptables -A INPUT -m state –state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m state –state ESTABLISHED,RELATED -j ACCEPT
# Logging rules – always at the END of the script
iptables -A INPUT -j LOG –log-prefix “Denied INPUT: ”
iptables -A OUTPUT -j LOG –log-prefix “Denied OUTPUT: ”
iptables -A FORWARD -j LOG –log-prefix “Denied FORWARD: “

————————————————————————————————-

Suppose you want to configure your firewall for the following:
a) You want to be able to ssh (port 22 TCP) from a remote trusted computer.
Hint, use -s in the rule.
b) You want users on your computer to be able to use the Internet for web (port 80 TCP), ftp (port 21 TCP ) and DNS lookup (port 53 TCP and UDP).
Your firewall script should now look like the following:

————————————————————————————————
#!/bin/bash
EXT=eth0
INT=eth2
DMZ=eth1
# flush
iptables -t nat -F
iptables -t mangle -F
iptables -t filter -F
# Default policy set to DROP all
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
#Loopback accept rule
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
# Allow us to ping other machines
iptables -A OUTPUT -o $EXT -p icmp –icmp-type ping -j ACCEPT
#iptables -A INPUT -i $EXT -p icmp –icmp-type pong -j ACCEPT
# Allow other machine to ping us
iptables -A INPUT -i $EXT -p icmp –icmp-type ping -j ACCEPT
#iptables -A OUTPUT -o $EXT -p icmp –icmp-type pong -j ACCEPT
# Allow reply packets to established and/or related connections
iptables -A INPUT -m state –state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m state –state ESTABLISHED,RELATED -j ACCEPT
#Allow external users to ssh to this server
# Probably should specify source addresses of trusted hosts
iptables -A INPUT -i $EXT -s 192.168.19.43 -p tcp –dport 22 -j ACCEPT
# Allow this server to access external services
# Connect to remote servers on ssh
# Access web and ftp sites for software downloads and updates
# Do DNS lookups
iptables -A OUTPUT -o $EXT -p tcp -m multiport –dports 22,80,53 -j ACCEPT
iptables -A OUTPUT -o $EXT -p udp -m multiport –dports 53 -j ACCEPT
# Logging rules – always at the END of the script
iptables -A INPUT -j LOG –log-prefix “Denied INPUT: ”
iptables -A OUTPUT -j LOG –log-prefix “Denied OUTPUT: ”
iptables -A FORWARD -j LOG –log-prefix “Denied FORWARD: “

—————————————————————————————————–

POSTROUTING NAT and FORWARD

Your LAN users will need to connect to the Internet. Since you have only 1 �Public� IP address you will need to make it appear that your LAN users are connection to the Internet with the Public IP address. This is called “MASQUERADING”.

Setting up a POSTROUTING NAT Policy on your firewall will accomplish this. In the firewall rule we use “SNAT” (source NAT). You will also need to include a FORWARD policy.

We will assume that your server has 3 network card.
If you have more than one network card you will need to enable IP forwarding. This will allow you to move packets between your two network cards. Put in the following at the top of your firewall script.

echo “1″ > /proc/sys/net/ipv4/ip_forward

Alternatively you can make this permanent by editing the /etc/sysctl.conf file and make sure there is a line that reads:

net.ipv6.conf.all.forwarding = 1

For the purposes of this example we will be adding “echo “1″ /proc/sys/net/ipv4/ip_forward” to the firewall script

POSTROUTING NAT (Masquerade)

You would like all LAN Internet browsers to appear as if they are browsing from one “Public” IP address. POSTROUTING, or SNAT, changes the source address of the connection to a different IP address. There is two ways of doing this:
1. MASQUERADE – Using the “MASQUERADE” option will change the source IP address of the connection to the IP address of the interface mentioned in the rule “-o eth0″. See examples below.
2. SNAT – Using “SNAT” requires you to specify an IP address to be used as the source IP address of the connection.
So to allow POSTROUTING NAT or masquerading you need to add one of the following to your firewall:

iptables -t nat -A POSTROUTING -o $EXT -s 192.168.0.0/24 -j MASQUERADE

OR

iptables -t nat -A POSTROUTING -o $EXT -s 192.168.0.0/24 -j SNAT –to 196.36.36.199

The first option allows masquerading using the IP address of the Output device. The second option specifies the IP Address to use.
This is a “POSTROUTING” rule because you need to decide on the route the connection needs to take before you masquerade the computer on the LAN behind your public IP address. For example you want to browse to a web site, so you use a DNS server to resolve the domain name to an IP Address. Once the IP address of the remote server has been established and it’s been determined that your connection needs to pass through your default gateway your firewall masquerades your computer behind your public IP address. Packets from your computer to the remote server will have their source IP addresses changed to reflect your networks public IP address.
Although you don’t need to specify the “-s 192.168.0.0/24″ (source on on lan), it is better to put this in for security reasons.

FORWARD policy
In order for your users to be able to connect to the Internet (another computer the other side of the firewall) you will need to add a FORWARD rule to your firewall. You can lso specify the port, protocol and interface you wish to allow.

iptables -A FORWARD -i $INT -o $EXT -p tcp –dport 110 -j ACCEPT

In the example above you are allowing traffic coming in on $INT connecting through to, and out on $EXT, using port 110 with protocol tcp. “-i” = incoming interface and “-o” = outbound interface.

To allow pings, you will need to specify the icmp protocol as follows:

iptables -A FORWARD -i $INT -o $EXT -p icmp -j ACCEPT

You can also specify multiple ports with one rule as follows:

iptables -A FORWARD -i $INT -o $EXT -s 192.168.0.0/24 -p tcp -m multiport –dports 80,53,22 -j ACCEPT

ESTABLISHED and RELATED again
You will also need to add an ESTABLISHED and RELATED rule for the FORWARD policy as follows:

iptables -A FORWARD -m state –state ESTABLISHED,RELATED -j ACCEPT

Your firewall should now look something like the following:
—————————————————————————————————–
#!/bin/bash
EXT=eth0
INT=eth2
DMZ=eth1
echo “1″ > /proc/sys/net/ipv4/ip_forward
# flush
iptables -t nat -F
iptables -t mangle -F
iptables -t filter -F
# Default policy set to DROP all
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
#Loopback accept rule
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
# Allow us to ping other machines
iptables -A OUTPUT -o $EXT -p icmp –icmp-type ping -j ACCEPT
#iptables -A INPUT -i $EXT -p icmp –icmp-type pong -j ACCEPT
# Allow other machine to ping us
iptables -A INPUT -i $EXT -p icmp –icmp-type ping -j ACCEPT
#iptables -A OUTPUT -o $EXT -p icmp –icmp-type pong -j ACCEPT
# Allow reply packets to established and/or related connections
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
#Allow external users to ssh to this server
# Probably should specify source addresses of trusted hosts
iptables -A INPUT -i $EXT -s 192.168.19.43 -p tcp –dport 22 -j ACCEPT
# Allow this server to access external services
# Connect to remote servers on ssh
# Access web and ftp sites for software downloads and updates
# Do DNS lookups
iptables -A OUTPUT -o $EXT -p tcp -m multiport –dports 22,80,53 -j ACCEPT
iptables -A OUTPUT -o $EXT -p udp -m multiport –dports 53 -j ACCEPT
# Allow our users to ping external sites
iptables -A FORWARD -i $INT -o $EXT -s 192.168.0.0/24 -p icmp –icmp-type ping -j
ACCEPT
# Masquerade outbound connections
iptables -t nat -A POSTROUTING -o $EXT -s 192.168.0.0/24 -j MASQUERADE
# Allow internal users access to Internet services
iptables -A FORWARD -i $INT -o $EXT -s 192.168.0.0/24 -p tcp -m multiport –dports 80,53,22 -j ACCEPT
iptables -A FORWARD -i $INT -o $EXT -s 192.168.0.0/24 -p udp -m multiport –dports 53 -j ACCEPT
# Allow trusted LAN users to access services on firewall
iptables -A INPUT -i $INT -s 192.168.0.100 -p tcp –dport 22 -j ACCEPT
# Logging rules – always at the END of the script
iptables -A INPUT -j LOG –log-prefix “Denied INPUT: ”
iptables -A OUTPUT -j LOG –log-prefix “Denied OUTPUT: ”
iptables -A FORWARD -j LOG –log-prefix “Denied FORWARD: ”
——————————————————————————————————
PREROUTING NAT and FORWARD
PREROUTING NAT

You should keep the servers you want to make available to the Internet in the DMZ. This allows you to make the servers in the DMZ available to the outside work while protecting your LAN. Normally you would put your mail sever and web server in the DMZ. LAN users will also need access to the DMZ to collect their mail, administer the DMZ servers etc.

If your company’s mail server is in the DMZ it will have a private IP address. On the other hand, if you were to do a dig on your domain name you would see that all zone records point to your public IP address, the IP address of the external network card of your firewall. This means any connection to your DMZ servers will stop at your firewall unless you can direct requests for those services to the appropriate server in the DMZ. To accomplish this we use PREROUTING NAT. In the firewall rule we use “DNAT” (destination NAT)


iptables -t nat -A PREROUTING -i $EXT -p tcp -m multiport –dports 110,80 -j DNAT –to 192.168.10.3

This is called PREROUTING because routing decisions take place after the destination IP address in the protocol header has been changed to the IP address of the server in the DMZ.
Doing PREROUTING NAT for LAN users is not necessary if you have the necessary routing tables in place. But if you were to use PREROUTING NAT for LAN users you would replace “-i $EXT” to “-i $INT”.
Notice that you can specify multiple ports in the rule by using the -m multiport option. You can also specify a different port for the DMZ server by putting a colon after the DMZ IP address, as per the following example:

iptables -t nat -A PREROUTING -i $EXT -p tcp –dport 80 -j DNAT –to 92.168.10.3:8080

FORWARD Policy again
For the above to work, make sure you have the appropriate forward policies in place for
connections originating on the internal and external interfaces.
Your firewall should now look something like the following:
——————————————————————————————————-
#!/bin/bash
EXT=eth0
INT=eth2
DMZ=eth1
echo “1″ > /proc/sys/net/ipv4/ip_forward
# flush
iptables -t nat -F
iptables -t mangle -F
iptables -t filter -F
# Default policy set to DROP all
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
#Loopback accept rule
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
# Allow us to ping other machines
iptables -A OUTPUT -o $EXT -p icmp –icmp-type ping -j ACCEPT
#iptables -A INPUT -i $EXT -p icmp –icmp-type pong -j ACCEPT
# Allow other machine to ping us
iptables -A INPUT -i $EXT -p icmp –icmp-type ping -j ACCEPT
#iptables -A OUTPUT -o $EXT -p icmp –icmp-type pong -j ACCEPT
# Allow reply packets to established and/or related connections
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
#Allow external users to ssh to this server
# Probably should specify source addresses of trusted hosts
iptables -A INPUT -i $EXT -s 192.168.19.43 -p tcp –dport 22 -j ACCEPT
# Allow this server to access external services
# Connect to remote servers on ssh
# Access web and ftp sites for software downloads and updates
# Do DNS lookups
iptables -A OUTPUT -o $EXT -p tcp -m multiport –dports 22,80,53 -j ACCEPT
iptables -A OUTPUT -o $EXT -p udp -m multiport –dports 53 -j ACCEPT
# Allow our users to ping external sites
iptables -A FORWARD -i $INT -o $EXT -s 192.168.0.0/24 -p icmp –icmp-type ping -j ACCEPT
# Masquerade outbound connections
iptables -t nat -A POSTROUTING -o $EXT -s 192.168.0.0/24 -j MASQUERADE
# Allow internal users access to Internet services
iptables -A FORWARD -s $INT -o $EXT -s 192.168.0.0/24 -p tcp -m multiport –dports 80,53 -j ACCEPT
iptables -A FORWARD -s $INT -o $EXT -s 192.168.0.0/24 -p udp -m multiport –dports 53 -j ACCEPT
# Allow trusted LAN users to access services on firewall
iptables -A INPUT -i $INT -s 192.168.0.100 -p tcp –dport 22 -j ACCEPT
# Allow external users access to DMZ servers
iptables -A FORWARD -i $EXT -o $DMZ -d 192.168.10.3 -p tcp -m multiport –dports 110,80 -j ACCEPT
iptables -t nat -A PREROUTING -i $EXT -p tcp -m multiport –dports 110,80 -j DNAT –to 192.168.10.3
# Allow LAN users access to DMZ servers, no need for using PREROUTING NAT.
iptables -A FORWARD -i $LAN -o $DMZ -p tcp -m multiport –dports 110,80 -j ACCEPT
# Logging rules – always at the END of the script
iptables -A INPUT -j LOG –log-prefix “Denied INPUT: ”
iptables -A OUTPUT -j LOG –log-prefix “Denied OUTPUT: ”
iptables -A FORWARD -j LOG –log-prefix “Denied FORWARD: ”
—————————————————————————————————–

Additional useful information

Forcing users to use a firewall.

Proxy users could take out the proxy server settings from their Internet explorer, and as long as they know the DNS servers they need to use, could connect to the Internet directly, thus by passing the proxy security. One way to overcome this is to use PREROUTING NAT to redirect any requests for port 80 to port 3128 on the proxy server. You will need to set your squid proxy server to “transparent”. OR, you could just not allow port 80 in your forward policy

opening certain ports
Certain services need to have certain ports open on the firewall the following are some

examples:
Proxy server – depending on the ports you have configured your proxy server with, you’ll need to have these opened on the firewall in order for users to connect to the Proxy server. Standard ports are TCP 3128 or 8080.
Samba server – For file sharing some users might need access to port 137 and 138 UDP and port 139 and 445 TCP. Depending on where the Samba server is and whether the firewall server is a Samba server it’s self you will need to allow access to these protocols and ports through your firewall.
Web access - Ports used by web servers are generally 80, 8080 and 443 for secure web sites. FTP usually uses port 21.
Mail servers - Depending on the type of mail server, you might need to open port 110 and 25
VPN – You need to open your firewall for the ports and protocols you need for vpn. Generally you will need to open protocol 47 (p47), TCP 1723 for PPTP. For L2TP/ipsec you need to open Protocol 50 (P50), UDP 4500 and 5000.
VNC and Remote Desktop – VNC usually uses 5901 or 5910. Remote Desktop uses 3389.

Closing certain ports
Once you have configured your firewall you will need to make sure that certain ports in particular are closed. An example of this is the port your Proxy server uses. While this port needs to be open for the LAN users and the server it’s self, if it is situated on the same computer as your firewall, it MUST be closed to “outside” traffic. The reason for this is that dubious individuals will try and use your proxy server to access the Internet to send Spam etc. If this happens it will appear that the malicious activity is coming from your network and you WILL get black listed.

OfficeFolders theme by Themocracy