No matter how careful you are when you set up firewall rules and tables, it's likely that you'll run into a persistent problem that restarting iptables or rebooting doesn't fix. Here are some of the most frequent firewall troubles, along with hints to solve the problem quickly and efficiently.
You may have clone everything right in setting up an iptables-based dual-homed network firewall, even down to copying someone else's working /etc/sysconfig/iptables file and rebooting. This common problem doesn't seem logical and many people are just left wondering what's wrong.
Assuming there are no other networking issues at work, check to make sure that kernel support for IPv4 packet forwardng is enabled. You can check the status with the command
# sysctl -a | grep ip_forward net.ipv4.ip_forward = 0
which is the same as this:
# cat /proc/sys/net/ipv4/ip_forward 0
To enable packet forwarding, open /etc/sysctl.conf in a text editor and make this change:
# Controls IP packet forwarding net.ipv4.ip_forward = 1
Save the file, exit the text editor, and force sysctl to re-read /etc/sysctl and boot with the proper changes:
# sysctl -p net.ipv4.ip_forward = 1 net.ipv4.conf.default.rp_filter = 1 kernel.sysrq = 0 kernel.core_uses_pid = 1
Try rebooting your firewall again. This allows packets to be forwarded in the kernel and traverse network interfaces. Even though iptables may be set up correctly, this can keep it all from working on a network firewall or multihome/router-based system.
This change will persist until you turn off packet forwarding (=0) through the same mechanism.
If you set up iptables on a stand-alone workstation to allow SSH access but you cannot get in, something is obviously wrong, but what? Your problem may exist at one of several levels. You need to narrow the problem down to look at one part of the system at a time.
Fixing this is a process of elimination. First, turn off iptables:
# /etc/init.d/iptables stop Flushing firewall rules: [ OK ] Setting chains to policy ACCEPT: mangle nat filter [ OK ] Unloading iptables modules: [ OK ]
Try logging in now. If you can get in, you've probably got a bad rule or a conflict in one of the "filter" table's chains. Check RH- Firewall-1- INPUT rules carefully and fix anything that's wrong.
If this doesn't work and you're running TCP wrappers as well, do you have an ALL:ALL entry in /etc/hosts.deny? Even if you have an appropriate entry in /etc/hosts.allow, a typo in the allow entry will let the deny file's ALL:ALL override the allow setting. Comment out the ALL:ALL and try again to test for this type of problem.
Still not working? It's probably not the firewall. Did you set up the SysV init scripts for sshd to be persistent (in your default run level) across reboots? Check to see if it's running and configured to "be up" in your default run level:
# /etc/init.d/sshd status sshd (pid 3619) is running... [root@localhost root]# chkconfig --list sshd sshd 0:off 1:off 2:on 3:on 4:on 5:on 6:off
Make the necessary changes and reboot the SSH daemon. You should also issue the command netstat -ant|grep:22 to ensure that sshd binds to the proper port and IP. The default settings are stored in /etc/sshd/sshd_config and you can make changes there:
... #Port 22 #Protocol 2,1 #ListenAddress 0.0.0.0 #ListenAddress :: ...
If all of these solutions still leave you hanging, watch your log files as you attempt to SSH in from another machine. The log messages should give you an idea of the problem:
# tail -f /var/log/messages
If you start iptables and get an error like this
# /etc/init.d/iptables start ipchains and iptables can not be used together. [WARNING]
your iptables rules or firewall won't work properly. In this case, someone has either manually loaded the older and now outdated ipchains kernel module or configured the system to load it automatically. This older netfilter module, not fully supported under Fedora Core, can be checked with the following command:
# lsmod | grep ^ip ipchains 49516 0 (unused)
You need to remove ipchains from the kernel with this command:
# rmmod ipchains
Now, iptables should start without problems:
To save dealing with this problem in the future, make sure that iptables is set to load automatically and ipchains is not:
# chkconfig --list | grep ^ip iptables 0:off 1:off 2:on 3:on 4:on 5:on 6:off
No ipchains init script is configured. Good. Verify that ipchains is not being loaded in /etc/modules.conf or in your rc.local boot-time files:
# grep ipch /etc/modules.conf /etc/rc.d/rc.local /etc/rc.d/rc.local:insmod ipchains
If you see output like this, ipchains is starting automatically. Edit the offending file, remove reference to ipchains, reboot, and run these tests again. You should see no reference to ipchains anywhere in the output and iptables should now start fine.
You've added a rule to allow SSH connections into your workstation, but it won't connect. You've checked TCP wrappers files for typing errors, you've checked your "filter" table settings, and you've performed the sacred Dance of Firewall Strength, but nothing seems to work. All you get is this:
ssh: connect to address 10.1.1.1 port 22: No route to host
Everything else is working fine. What gives?
Remember that iptables is an Access Control List, and on ACLs, order matters. On a Red Hat or Fedora Core system, you might think you're covered if you just issue this command:
# iptables -A RH-Firewall-1-INPUT -p tcp --dport 22 -j ACCEPT
It's the right command, but it might not work because order matters. If you're appending a rule (with a -A) to an existing chain from the command line, be sure to list out the existing rules with the -line-numbers option:
# iptables -L --line-numbers Chain INPUT (policy ACCEPT) num target prot opt source destination 1 RH-Firewall-1-INPUT all -- anywhere anywhere ... Chain RH-Firewall-1-INPUT (2 references) num target prot opt source destination 1 ACCEPT all -- anywhere anywhere 2 ACCEPT icmp -- anywhere anywhere icmp any 3 ACCEPT ipv6-crypt-- anywhere anywhere 4 ACCEPT ipv6-auth-- anywhere anywhere 5 ACCEPT all -- anywhere anywhere state RELATED, ESTABLISHED 6 ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:http 7 REJECT icmp -- !pc anywhere icmp any reject-with icmp-port-unreachable 8 REJECT all -- anywhere anywhere reject-with icmp-host-prohibited 9 ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
Numerically insert (with the -I switch) your new "allow ssh" rule in the proper location (before the #7 or 8 REJECT), rather than append them. Be sure to use the chain name and the rule number location that you wish to insert to via the following syntax:
#iptables -I RH-Firewal1-1-INPUT 7 -p tcp --dport 22 -j ACCEPT
Now the corrected chain listing should look like this:
# iptables -L --line-numbers Chain INPUT (policy ACCEPT) num target prot opt source destination 1 RH-Firewall-1-INPUT all -- anywhere anywhere ... Chain RH-Firewall-1-INPUT (2 references) num target prot opt source destination 1 ACCEPT all -- anywhere anywhere 2 ACCEPT icmp -- anywhere anywhere icmp any 3 ACCEPT ipv6-crypt-- anywhere anywhere 4 ACCEPT ipv6-auth-- anywhere anywhere 5 ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED 6 ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:http 7 ACCEPT tcp -- anywhere anywhere tcp dpt:ssh 8 REJECT icmp -- !pc anywhere icmp any reject-with icmp-port-unreachable 9 REJECT all --anywhere anywhere reject-with icmp-host-prohibited
That should do it.