Skip to content

Instantly share code, notes, and snippets.

@thomasfr
Last active February 13, 2024 15:44
Star You must be signed in to star a gist
Save thomasfr/9712418 to your computer and use it in GitHub Desktop.
iptable rules to allow outgoing DNS lookups, outgoing icmp (ping) requests, outgoing connections to configured package servers, outgoing connections to all ips on port 22, all incoming connections to port 22, 80 and 443 and everything on localhost
#!/bin/bash
IPT="/sbin/iptables"
# Server IP
SERVER_IP="$(ip addr show eth0 | grep 'inet ' | cut -f2 | awk '{ print $2}')"
# Your DNS servers you use: cat /etc/resolv.conf
DNS_SERVER="8.8.4.4 8.8.8.8"
# Allow connections to this package servers
PACKAGE_SERVER="ftp.us.debian.org security.debian.org"
echo "flush iptable rules"
$IPT -F
$IPT -X
$IPT -t nat -F
$IPT -t nat -X
$IPT -t mangle -F
$IPT -t mangle -X
echo "Set default policy to 'DROP'"
$IPT -P INPUT DROP
$IPT -P FORWARD DROP
$IPT -P OUTPUT DROP
## This should be one of the first rules.
## so dns lookups are already allowed for your other rules
for ip in $DNS_SERVER
do
echo "Allowing DNS lookups (tcp, udp port 53) to server '$ip'"
$IPT -A OUTPUT -p udp -d $ip --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A INPUT -p udp -s $ip --sport 53 -m state --state ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -p tcp -d $ip --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A INPUT -p tcp -s $ip --sport 53 -m state --state ESTABLISHED -j ACCEPT
done
echo "allow all and everything on localhost"
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
for ip in $PACKAGE_SERVER
do
echo "Allow connection to '$ip' on port 21"
$IPT -A OUTPUT -p tcp -d "$ip" --dport 21 -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A INPUT -p tcp -s "$ip" --sport 21 -m state --state ESTABLISHED -j ACCEPT
echo "Allow connection to '$ip' on port 80"
$IPT -A OUTPUT -p tcp -d "$ip" --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A INPUT -p tcp -s "$ip" --sport 80 -m state --state ESTABLISHED -j ACCEPT
echo "Allow connection to '$ip' on port 443"
$IPT -A OUTPUT -p tcp -d "$ip" --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A INPUT -p tcp -s "$ip" --sport 443 -m state --state ESTABLISHED -j ACCEPT
done
#######################################################################################################
## Global iptable rules. Not IP specific
echo "Allowing new and established incoming connections to port 21, 80, 443"
$IPT -A INPUT -p tcp -m multiport --dports 21,80,443 -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A OUTPUT -p tcp -m multiport --sports 21,80,443 -m state --state ESTABLISHED -j ACCEPT
echo "Allow all outgoing connections to port 22"
$IPT -A OUTPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A INPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
echo "Allow outgoing icmp connections (pings,...)"
$IPT -A OUTPUT -p icmp -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
$IPT -A INPUT -p icmp -m state --state ESTABLISHED,RELATED -j ACCEPT
echo "Allow outgoing connections to port 123 (ntp syncs)"
$IPT -A OUTPUT -p udp --dport 123 -m state --state NEW,ESTABLISHED -j ACCEPT
$IPT -A INPUT -p udp --sport 123 -m state --state ESTABLISHED -j ACCEPT
# Log before dropping
$IPT -A INPUT -j LOG -m limit --limit 12/min --log-level 4 --log-prefix 'IP INPUT drop: '
$IPT -A INPUT -j DROP
$IPT -A OUTPUT -j LOG -m limit --limit 12/min --log-level 4 --log-prefix 'IP OUTPUT drop: '
$IPT -A OUTPUT -j DROP
exit 0
@mcsilver
Copy link

Thank you for this script! I am new to iptables and none of the tutorials summed up all a person's typical basic needs like you did here.

@Bellecour
Copy link

Carefull on line 60~62, little mismatch between port 21 and 22

@medhabansal
Copy link

Thanks a lot for this! :D

@AnPogrebnyak
Copy link

Thank you

@Tholep
Copy link

Tholep commented Aug 14, 2017

When I enter these rules:
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
the iptables -L -n shows that the following line for both INPUT and OUTPUT chain
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
This would actually mean that it accept all input and output. Therefore, following rules would not be ignored. If I removed those two commands, I can't perform DNS resolution and hence, no internet. Can you help to clarify this?

@sergey-serov
Copy link

Greetings!
Good script, Thank You!
Some remarks about "SERVER_IP" variable.
1). This is unused var.
2). The eth0 name is only one of possible names. It may be for example enp0s31f6.

@paulpas
Copy link

paulpas commented Mar 7, 2018

Line 69 should be
$IPT -A OUTPUT -p icmp -m state --state NEW -j ACCEPT

@springjools
Copy link

Why is forward policy drop?

@iamenderst
Copy link

Why is forward policy drop?

Assuming you're not a router. Besides, drop all and allow what you need.

@francogu
Copy link

as state in the documentation:

Please note that specifying any name to be resolved with a remote query such as DNS is a really bad idea

@KarthikNedunchezhiyan
Copy link

KarthikNedunchezhiyan commented Jul 22, 2020

why we are looping ips instead we can provide ips in comma-separated right? It reduces multiple command execution.

@Krishankantmani3
Copy link

can anyone suggest to me, how to allow only apt-get/apt command in my cloud server for outbound traffic?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment