Skip to content
Snippets Groups Projects
Commit 406c1770 authored by ale's avatar ale
Browse files

Refactor the firewall script

Make it more generic, dropping ai-specific bits here and
there. Provide a standard command-line interface including --help and
--version options. Move default filter setup to a standalone code
snippet.

Rename package to just 'firewall'. Bump version to 0.2 to highlight
the difference with the original ai-firewall codebase.
parent ccb6462d
No related branches found
No related tags found
No related merge requests found
add_user_port tcp 21
# This is the port range for PASV transfers.
add_user_port tcp 15000:19000
add_user_ports tcp 5222,5223,5269,5280
# STUN.
add_user_ports tcp 3478,5349
add_user_port udp 3478
add_user_ports tcp 25,110,143,465,587,993,995
# Create a chain with probe IP ranges.
create_chain MONITORING
add_rule -A MONITORING -s 131.114.114.0/24 -j ACCEPT
add_rule -A MONITORING -s 46.4.206.80/28 -j ACCEPT
add_rule -A MONITORING -j DROP
add_user_port tcp 3900 -j MONITORING
for proto in udp tcp ; do
add_user_ports ${proto} 655,656,657 -j RING0
done
# Standard HTTP/HTTPS ports.
add_user_ports tcp 80,443
# Block outgoing connections from the users' FastCGI runners
# (i.e. the PHP scripts) to only HTTP.
USERS_GROUP=2000
create_chain user-output-cgi
add_rule -A user-output-cgi -p tcp --syn --dport 80 -j ACCEPT
add_rule -A user-output-cgi -p tcp --syn --dport 443 -j ACCEPT
add_rule -A user-output-cgi -m log --log-prefix \"users-cgi: \" \
-m limit --limit 3/s -j LOG
add_rule -A user-output-cgi -j REJECT
add_rule -A OUTPUT -m owner --gid-owner ${USERS_GROUP} -j user-output-cgi
#!/bin/bash
# The following configuration variables can be overridden from the
# environment. Useful in combination with /etc/default or some
# equivalent mechanism.
FW_DIR="${FW_DIR:-/etc/firewall}"
DO_LOG="${DO_LOG:-1}"
LOG_RATE="${LOG_RATE:-5/min}"
# Directory containing the configuration snippets.
CONFIG_DIR="${CONFIG_DIR:-/etc/firewall}"
# List of tables to manage.
TABLES="filter nat mangle"
# Use a safe PATH.
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH
# Resolve a host with the given proto (ipv4 or ipv6).
resolve_addr() {
local addr="$1"
......@@ -20,17 +21,6 @@ resolve_addr() {
python -c "import socket ; print '\n'.join(x[4][0] for x in socket.getaddrinfo('${addr}', 0, socket.${af}, socket.SOCK_STREAM))" 2>/dev/null || true
}
# Resolve all hostnames in a file.
resolve_addrs_from_file() {
local filename="$1"
local proto="$2"
awk '{print $1}' < ${filename} \
| (while read name ; do \
test -n "${name}" && resolve_addr ${name}.investici.org ${proto} ; \
done)
return 0
}
# Add a rule valid for IPv4 and IPv6.
add_rule() {
add_rule4 "$*"
......@@ -39,14 +29,12 @@ add_rule() {
# Add an IPv4-only rule.
add_rule4() {
local args="$*"
echo "${args}" 1>&4
echo "$*" 1>&4
}
# Add an IPv6-only rule.
add_rule6() {
local args="$*"
echo "${args}" 1>&6
echo "$*" 1>&6
}
# Create a new iptables chain.
......@@ -67,7 +55,7 @@ add_to_chain() {
# Add a rule to the 'user-input' chain allowing traffic to a
# specific port/protocol.
add_user_port() {
allow_port() {
local proto="$1"
local port="$2"
shift 2
......@@ -80,7 +68,7 @@ add_user_port() {
# Add a rule to the 'user-input' chain allowing traffic to
# a set of multiple ports.
add_user_ports() {
allow_ports() {
local proto="$1"
local ports="$2"
shift 2
......@@ -108,126 +96,61 @@ generate() {
add_rule "*${table_name}"
# Initialize the table.
# Initialize the table with default policies.
case ${table_name} in
filter)
create_chain INPUT DROP
create_chain OUTPUT ACCEPT
create_chain FORWARD ACCEPT
;;
nat)
generate_nat
create_chain PREROUTING ACCEPT
create_chain OUTPUT ACCEPT
create_chain POSTROUTING ACCEPT
;;
filter)
generate_filter
mangle)
create_chain PREROUTING ACCEPT
create_chain INPUT ACCEPT
create_chain FORWARD ACCEPT
create_chain OUTPUT ACCEPT
create_chain POSTROUTING ACCEPT
;;
esac
# Load user-defined rulesets.
for file in ${conf_root}/*
do
test -f ${file} || continue
case $(basename "${file}") in
*~|.*)
;;
*)
if [ -d ${conf_root} ]; then
for file in $(run-parts --list ${conf_root}); do
. ${file}
;;
esac
done
fi
add_rule COMMIT
}
# Initialize the 'nat' table.
generate_nat() {
create_chain PREROUTING ACCEPT
create_chain OUTPUT ACCEPT
create_chain POSTROUTING ACCEPT
}
# Initialize the 'filter' table.
generate_filter() {
create_chain INPUT DROP
create_chain OUTPUT ACCEPT
create_chain FORWARD ACCEPT
# Set up a chain that will drop noisy unwanted traffic
# without even logging it.
create_chain drop-noise
add_rule -A drop-noise -p tcp --dport 113 -j REJECT
add_rule -A drop-noise -p tcp -m multiport --dports 139,445 -j DROP
add_rule -A drop-noise -p udp -m multiport --dports 137,138,500 -j DROP
# Be kind and allow old-style traceroutes.
add_rule -A drop-noise -p udp --dport 33434:33500 -j REJECT
# base-input chain.
create_chain base-input
# Enable everything from lo and ring0.
add_rule -A base-input -i lo -j ACCEPT
add_rule4 -A base-input -i ring0 -s 172.16.1.0/24 -j ACCEPT
# Some IPv6-specific ICMP setup.
add_rule6 -A base-input -m rt --rt-type 0 --rt-segsleft 0 -j DROP
for icmp6type in 133 134 135 136 ; do
add_rule6 -A base-input -p ipv6-icmp -m icmp6 \
--icmpv6-type ${icmp6type} -m hl --hl-eq 255 -j ACCEPT
done
# Standard conntrack stuff.
add_rule -A base-input -m state --state RELATED,ESTABLISHED -j ACCEPT
add_rule6 -A base-input -s fe80::/10 -p ipv6-icmp -m icmp6 \
--icmpv6-type 129 -j ACCEPT
add_rule -A base-input -m state --state INVALID -j DROP
# Enable 6to4 protocols.
add_rule -A base-input -p ipv6 -j ACCEPT
# Allow useful ICMPs (but rate-limit incoming echo requests).
add_rule4 -A base-input -p icmp -m icmp --icmp-type 8 -m limit \
--limit 3/s -j ACCEPT
for icmptype in 3 4 11 12 ; do
add_rule4 -A base-input -p icmp -m icmp \
--icmp-type ${icmptype} -j ACCEPT
done
for icmp6type in 1 2 3 4 128 ; do
add_rule6 -A base-input -p ipv6-icmp -m icmp6 \
--icmpv6-type ${icmp6type} -j ACCEPT
done
# IPv6 autodiscovery.
#add_rule6 -A base-input -s fe80::/10 -d fe80::/10 -p udp -m udp \
# --sport 547 --dport 546 -j ACCEPT
# user-input
create_chain user-input
# Always allow SSH access, just in case someone forgets to add it
# with a user-defined ruleset file.
add_user_port tcp 22
# Setup the INPUT chain.
# It is split into stages: base-input, user-input
add_rule -A INPUT -j base-input
add_rule -A INPUT -j drop-noise
add_rule -A INPUT -j user-input
# Logging.
if [ "${DO_LOG}" -eq 1 ]; then
create_chain log-deny
add_rule -A log-deny -j LOG --log-prefix 'deny: '
add_rule -A INPUT -j log-deny -m limit --limit "${LOG_RATE}" --limit-burst 5
fi
}
load() {
load_firewall() {
set -e
set -u
now=$(date)
tmpfiles=
v4rules=/dev/null
v6rules=/dev/null
if [ ${enable_ipv4} -eq 1 ]; then
v4rules=$(mktemp ${TMP:-/tmp}/ip4t.XXXXXX)
tmpfiles="${tmpfiles} ${v4rules}"
echo "# firewall(IPv4). Autogenerated on ${now}" > ${v4rules}
fi
if [ ${enable_ipv6} -eq 1 ]; then
v6rules=$(mktemp ${TMP:-/tmp}/ip6t.XXXXXX)
trap "rm -f ${v4rules} ${v6rules} 2>/dev/null; trap - EXIT; exit 0" EXIT
tmpfiles="${tmpfiles} ${v6rules}"
echo "# firewall(IPv6). Autogenerated on ${now}" > ${v6rules}
fi
trap "rm -f ${tmpfiles} 2>/dev/null; trap - EXIT; exit 0" EXIT
# Setup the various tables. Note that IPv6 only has the
# 'filter' table.
for table in ${TABLES} ; do
table_dir=${FW_DIR}/${table}.d
table_dir=${CONFIG_DIR}/${table}.d
case "$table" in
filter)
run_with_fds ${v4rules} ${v6rules} \
......@@ -241,29 +164,58 @@ load() {
done
if [ ${dry_run} -eq 1 ]; then
echo "/sbin/iptables-restore <${v4rules}"
cat ${v4rules}
echo "/sbin/ip6tables-restore <${v6rules}"
cat ${v6rules}
[ ${enable_ipv4} -eq 0 ] || cat ${v4rules}
[ ${enable_ipv6} -eq 0 ] || cat ${v6rules}
else
/sbin/iptables-restore <${v4rules}
/sbin/ip6tables-restore <${v6rules}
[ ${enable_ipv4} -eq 0 ] || iptables-restore <${v4rules}
[ ${enable_ipv6} -eq 0 ] || ip6tables-restore <${v6rules}
fi
}
usage() {
cat <<EOF
Usage: $0 [<OPTIONS>]
Known options:
-4 Generate only the IPv4 configuration.
-6 Generate only the IPv6 configuration.
-n, --dry-run Do not apply iptables config, just output the results.
-h, --help Print this help message.
EOF
}
dry_run=0
if [ "$1" = "-n" ]; then
dry_run=1
shift
fi
enable_ipv4=1
enable_ipv6=1
while [ $# -gt 0 ]; do
case "$1" in
start|load|reload)
load
-4)
enable_ipv6=0
;;
-6)
enable_ipv4=0
;;
-n|--dry-run)
dry_run=1
;;
-h|--help)
usage
exit 0
;;
--version)
echo "firewall v0.2"
exit 0
;;
*)
echo "Usage: $0 {start|reload}" 1>&2
echo "Unknown argument '$1'" >&2
usage >&2
exit 2
;;
esac
shift
done
load_firewall
exit 0
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment