Fedora iptables firewall script

Around twenty years ago I used dial-up internet on Fedora, and iptables rules to control my firewall, and set up internet connection sharing (using NAT) to the rest of the equipment on my LAN.

There wasn't a convenient firewall rules configurator back then, and some might argue there still isn't a great one right now.  Some are horrendously complicated, and you can make a mistake without noticing it.  This (further below) is the basics of the script I used, and could be modified to still be useful today (by changing device names, addresses, and file locations in the script, and updating any rule names that may have changed in the meantime).  It was predictable, and could easily be shared with someone to get their opinion on things (that's hard to do with a GUI-based firewall configurator).

Later this script became unneccesary, as the computer wasn't directly connected to the internet, it connected through a modem/router which had NAT and a firewall in it (those are two separate things).  Though people face this problem again when they connect a PC to a mobile phone network through USB, it can be a direct connection.  Most systems now have a basic firewall, and some means of controlling it, but some people prefer are more hands-on solution, or don't trust a configurator to do it for them.

Consider it a concept to be adapted to your needs, rather than a ready-to-go solution.  It's relatively simple, can be simplified further by removing the un-needed parts (there's a simplified example even further down the page, but read the fuller example and explanations, first).

Any time I wanted to change some rules, I'd edit the script and run it.  It'd set the rules, and save them.  It saved them to where the system loaded its iptables rules when it booted up, so it automatically loads my rules.

There is a sequence to things that has to be followed.  First you set default policies, one being to disallow all incoming connections, while allowing all outgoing connections (this was a home system, where I didn't need to block anything going out).  Then you start poking holes through to allow some things.  Remembering that, in most cases, the last rule that's set wins (they override prior ones).

A very basic set of firewall rules is drop all incoming connections by default, allow all outgoing connections by default, and only allow the incoming connections that are related to your outgoing connections.  And that's pretty much it for simple use of the internet.  There isn't much that you need to allow coming into your system.  So, when it comes to poking holes into your firewall there's often only one that you need to allow: your ISP's DHCP server giving you an address when you connect up, but that should be covered by the related rule, because your system will initiate the routine.  Likewise, your web browsing is covered by the related rule (it's in response to your browse request).  And your firewall should doing that related traffic rule by itself.  So all most people need to do is simply switch on their firewall, and choose an option that applies rules for a public or untrusted network.

If you see a firewall setting called home don't just pick it because your PC is at home.  It refers to a more relaxed set of rules for PCs connected together at home.  You need to consider how your network is set up.  Do you trust the connections between PCs and other networked devices in your home?  Do you have a modem/router between your network and the internet, and does it firewall you?  If you have just one PC at home directly connected to the internet, then you should pick a more stringent set of rules, like public, internet, or untrusted.  If you don't trust some devices on your network (such as remote-controlled smart devices, that are actually controlled by a server on the internet, then also pick stringent rules, and/or place them on an isolated network).

The tricky, and risky, thing to manage is peer-to-peer (whether that's filesharing, or gaming).  When someone is making a direct connection to you, or several of them.  Though most modern networked games seem to use a server in the middle, you each connect to it, not directly to each other.

And when you have servers on your PC.  If you're deliberately exposing them to the internet, you need to secure them against mis-use, and a firewall may help protect you against things you've forgotten to do.  But for any servers you have running that are not meant to be internet accessible, you should configure them to only listen to LAN connections, ignoring the rest of the world, and never rely on a firewall to protect them.

Related to that is never dropping your firewall to solve a networking problem.  Your firewall should always be up, and you should only ever poke small holes through it for specific things.  There's no such thing a safe time to do it, a few seconds is all it takes for someone to hack into you.

#!/bin/bash

## Turn off IP forwarding while altering configuration:
## (Put it back on again, at end, if needed.)

echo 0 > /proc/sys/net/ipv4/ip_forward

### Reset...  Flush any pre-existing rules:

iptables --flush INPUT
iptables --flush OUTPUT
iptables --flush FORWARD

iptables --flush
iptables --table nat --flush

iptables --delete-chain
iptables --table nat --delete-chain


### Begin general firewalling... 

## Set default (policy) rules:

iptables --policy INPUT DROP
iptables --policy OUTPUT ACCEPT
iptables --policy FORWARD ACCEPT


### Add specific firewalling rules...

## Drop non-internet networking addresses on the internet connection:

iptables --append INPUT --jump DROP --in-interface ppp+ --source 192.168.0.0/16
iptables --append INPUT --jump DROP --in-interface ppp+ --source 172.16.0.0/12
iptables --append INPUT --jump DROP --in-interface ppp+ --source 10.0.0.0/8
iptables --append INPUT --jump DROP --in-interface ppp+ --source 127.0.0.0/8
iptables --append INPUT --jump DROP --in-interface ppp+ --source 169.254.0.0/16
iptables --append INPUT --jump DROP --in-interface ppp+ --source 192.0.2.0/24
iptables --append INPUT --jump DROP --in-interface ppp+ --source 204.152.64.0/23
iptables --append INPUT --jump DROP --in-interface ppp+ --source 224.0.0.0/3


### Accept some things:


## Remove the single hashmarks below to allow internet access to an internal webserver:

#iptables --append INPUT --jump ACCEPT --protocol tcp --destination-port http
#iptables --append INPUT --jump ACCEPT --protocol tcp --destination-port https

## Redirect webserver visitors past my ISP's firewalling (they block port 80),
## by letting them in through port 8000 and redirecting it to port 80 on the local webserver:
## (Remove the single hashmark below to allow an internet access)
  
#iptables --table nat --append PREROUTING --protocol tcp --dport 8000 --jump REDIRECT --to-port 80


## Allow established and related outside commications to this system,
## in response to outgoing connections from this system,
## and allow outside communications to the firewall, except for ICMP packets:
## (Could be tightened up, adding conditions about specific ports.)

iptables --append INPUT --match state --state ESTABLISHED,RELATED --in-interface ppp+ --protocol \! icmp --jump ACCEPT


## Prevent unexpected connections initiated from the outside world:
## (Can interfere with some services which connect back, later on,
## such as file transfers or webcams on IM programs.)

iptables --append INPUT --match state --state NEW --in-interface ppp+ --jump DROP


## Allow all local communications to and from the firewall on ETH from the local network:

iptables --append INPUT --jump ACCEPT --protocol all --in-interface eth+ --source 192.168.0.0/16


### Internet connection sharing:

## Set up masquerading to allow internal machines access to outside network:
## (Remove the single hashmark below to allow it)

#iptables --table nat --append POSTROUTING --out-interface ppp+ --jump MASQUERADE


## Turn on IP forwarding, only needed for above internet connection sharing rule:
## (Remove the single hashmark below to allow it)

#echo 1 > /proc/sys/net/ipv4/ip_forward


### Save settings

## Save iptables rules to the default iptables rules file (used at boot-up):
## (Red Hat's own /etc/init.d/iptables script looks here.)

iptables-save > /etc/sysconfig/iptables

There are notes in the script, but for safety and predictable behaviour, IP forwarding (connection sharing) is disabled and any previous rules are flushed for a fresh start when the script is run.

A default rule is set to drop any incoming connections, and later rules will be set up to poke controlled holes through to allow certain incoming connections.  “Reject” could be used, instead, as a more proper way to reject errant connections.  With “drop” they're just ignored.

Default rules are set to allow all outgoing connections, and to allow connections that are being routed through (forwarded).  If you weren't doing NAT, and just creating firewall rules for a single box, get rid of the line accepting forward connections.

Rules were set to block connections from the outside world that had addresses belonging to local area networks.  This could be protection from misconfigurations within an ISP, or deliberate hacking attempts trying to pretend they were inside your LAN, not outside it.  But in this era of more ISPs using NAT because there aren't enough real IPv4 addresses to go around, you might be using one of those sets of addresses and need to allow them.  This does make it trickier to isolate a LAN from a WAN, you need to use a different addressing range than your internet connection.  If they're using the 10.0.0.0, then you might use the 192.168.0.0 range.

My interface to the outside world was a ppp0 device, and I used a ppp+ wildcard in the script.  My interface to my LAN was through eth0 and I used an eth+ wildcard in the script.  These would need customising to suit your own device names.  Which are probably two ethernet ports in this era.

You need two connections to do firewalling for a LAN or connection sharing, the PC is between them controlling traffic between one side and the other.  It can't do that with just a single connection to the rest of your network.

I had some rules to temporarily allow some connections through to my webserver (this was in the days of not having easy methods of sharing large files to someone).  I'd un-hash the rules and run the script to allow access, then afterwards re-hash the rules and run the script to block further access.

Later, my ISP blocked port 80, supposedly because of a rampant worm going around, but they also don't want people running servers.  So I had a rule redirecting connections from a non-standard port 8000 through to the standard port 80 on my webserver.  Again, this was a temporary rule I'd set up occasionally, and disable most of the time.

Then came some rules about allowing incoming connections that were in response to outgoing connections from my system (such as when doing FTP to an outside server, it's bi-directional).

Then was a belt-and-braces rule dropping unexpected incoming connection attempts (it's a bit of duplication from the default INPUT policy).

Next was a rule allowing all internal traffic from my LAN through its ethernet port(s).

Then came the internet connection sharing rules, using NAT as a router between the outside world and inside LAN (the NAT and ip_forward rules).

Finally, it saves the settings it's just applied to the default rules (this location may need changing for newer, or different, distros).

As mentioned at the start, this can be simplified down quite a bit, when you don't need all the options that I've used.  For example, a basic firewall on a single PC connected to the internet could be just this (my specific ppp+ input interface rules removed to apply to any and all input interfaces):

#!/bin/bash

### Reset...  Flush any pre-existing rules:

iptables --flush INPUT
iptables --flush OUTPUT
iptables --flush FORWARD

iptables --flush
iptables --table nat --flush

iptables --delete-chain
iptables --table nat --delete-chain


### Begin general firewalling... 

## Set default (policy) rules:

iptables --policy INPUT DROP
iptables --policy OUTPUT ACCEPT
iptables --policy FORWARD ACCEPT


### Add specific firewalling rules...

## Drop internet connection attempts using non-internet addresses:

iptables --append INPUT --jump DROP --source 192.168.0.0/16
iptables --append INPUT --jump DROP --source 172.16.0.0/12
iptables --append INPUT --jump DROP --source 10.0.0.0/8
iptables --append INPUT --jump DROP --source 127.0.0.0/8
iptables --append INPUT --jump DROP --source 169.254.0.0/16
iptables --append INPUT --jump DROP --source 192.0.2.0/24
iptables --append INPUT --jump DROP --source 204.152.64.0/23
iptables --append INPUT --jump DROP --source 224.0.0.0/3


### Accept some things:

## Allow established and related outside commications to this system,
## in response to outgoing connections from this system,
## and allow outside communications to the firewall, except for ICMP packets:

iptables --append INPUT --match state --state ESTABLISHED,RELATED --protocol \! icmp --jump ACCEPT


## Prevent unexpected connections initiated from the outside world:

iptables --append INPUT --match state --state NEW --jump DROP


### Save settings

## Save iptables rules to the default iptables rules file (used at boot-up):
## (Red Hat's own /etc/init.d/iptables script looks here.)

iptables-save > /etc/sysconfig/iptables