Server Fault is a question and answer site for system and network administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have a centos machine and wish to only allow outbound connections to port 587 to certain remote machines, and drop packets trying to connect to all other hosts.

I only want to allow access on port 587 if they are going to access gmail's SMTP servers (all IPs behind Is there a way I can implement this?

share|improve this question
up vote 7 down vote accepted

You can use the -d switch to iptables rules which makes the rule work for just the address supplied and then block everything else e.g.

iptables -I OUTPUT -p tcp --dport 587 -j DROP
iptables -I OUTPUT -d -p tcp -m tcp --dport 587 -j ACCEPT

should do what you want. This initially inserts a DROP all outgoing connections on port 587 rule into the beginning of the OUTPUT chain. It then inserts an allow rule for port 587 into the beginning of the OUTPUT chain. This has the effect of allowing connections to and blocking everything else on port 587 e.g.

iptables -L OUTPUT -n
Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     tcp  --        tcp dpt:587
ACCEPT     tcp  --        tcp dpt:587
DROP       tcp  --             tcp dpt:587

Note that resolves to two ip addresses which is why there are two ACCEPT rules above. The name is only resolved once when the rule is added to the kernel so if the addresses are changed then connections to gmail will be blocked too and you would need to reload the rules.

share|improve this answer
To paraphrase Beyonce, you oughta put a script on that. No reason that a little 'host' action can't be wrapped in a shell script and automatically update the IPs that is using. – Magellan Jan 15 '12 at 16:53
That sounds like a plan – Iain Jan 15 '12 at 16:56
im wondering why u use forward instead of output (iptables -I OUTPUT -p tcp --dport 587 -j DROP) – WantIt Jan 16 '12 at 0:58
i mean, they use FORWARD instead of OUPUT – WantIt Jan 16 '12 at 0:58
You use FORWARD if the machine is acting as a router. OUTPUT if it's the server originating the connection. OP made no mention of routing traffic, so OUTPUT is a reasonable assumption. – Magellan Jan 16 '12 at 4:04

You need to allow gmail before you deny access. Otherwise you don't get to the allow rule.

Google may use any address in their ASN for Gmail servers, you you will want to allow all the blocks. You may want to look at using an ipset to handle the blocks involved. You may also find their SPF record provides a decent list of network blocks for your requirements. If you reject, rather than drop outgoing requests your users may not notice a few missing blocks.

A tool like Shorewall will allow you to implement your policies more easily. In your case I would have an outgoing REJECT policy and only allow desired traffic out. In that case you wouldn't need a specific rule to prevent access to the the submission port. Shorewall also enables easy configuration of logging for your firewall.

share|improve this answer

I'd suggest automating this whole thing so that you don't have to continue to worry about it.

The iptables -I OUTPUT -p tcp --dport 587 -j DROP should be included in your basic system configuration, which probably lives in /etc/sysconfig/iptables on your machine.

Drop this script into an editor and save it someplace, then mark it executable with chmod. As an example, I placed it in /opt/sysadminscripts/


IPLIST=$(host | grep 'has address' | awk '{print $4}')

for x in $IPLIST
        $(iptables -L -nv | grep "$x" >> /dev/null)
        if [[ "$?" -ne '0' ]]; then
                $(iptables -I OUTPUT  -p tcp -m tcp -d "$x" --dport 587 -j ACCEPT)

Then add an entry in your system crontab similar to this:

*/10 * * * * root /opt/sysadminscripts/

Make sure that the line is NOT the last line in your /etc/crontab. If the line doesn't have a terminating line feed, it won't run. (I recommend keeping a comment as the last line of /etc/crontab.)

share|improve this answer
im wondering why you use output instead of forward (iptables -I OUTPUT -p tcp --dport 587 -j DROP) any idea? – WantIt Jan 16 '12 at 0:58
I just snagged Iain's code and wrapped it in a script, but the answer I provided to your other comments fits this as well. – Magellan Jan 16 '12 at 4:05

You need to have rules like:

iptables -A FORWARD -p tcp -d --dport 587 -j ACCEPT
iptables -A FORWARD -p tcp --dport 587 -j DROP

The problem is that you need to find the possible IPs for It is not recommended to use the name in iptables. This is because iptables will not recognize the IP-name mapping changes. You may need to continuously check for the IP change and update your rules accordingly.

You need to pick the right chain FORWARD in the above example depending on which traffic you want to control.

share|improve this answer
WHY FORWARD? not otput? – WantIt Jan 16 '12 at 0:59
As I answered in your other comment, it depends on what you're using the CentOS install for. This excerpt from the Netfilter/IPTables man page: ...INPUT (for packets destined to local sockets), FORWARD (for packets being routed through the box), and OUTPUT (for locally-generated packets). – Magellan Jan 17 '12 at 18:15

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.