Firewall

Un firewall est un logiciel permettant de filtrer les paquets réseau. Le logiciel le plus utiliser sur les systèmes GNU/Linux est iptables. Il permet de configurer des filtres en espace kernel grâce aux modules Netfilter.

La chose la plus importante avec un firewall est de filtrer les paquets en entrée. Pour attaquer un serveur, un pirate doit établir une connexion avec celui-ci. Filtrer les paquets venant de l'extérieur est une bonne manière d'éviter bon nombre de problèmes.

iptables utilise 2 chaînes nommées INPUT and OUTPUT. INPUT contient les règles pour filtrer les paquets venant de l'extérieur et OUTPUT contient les règles permettant de filtrer les paquets voulant se diriger vers l'extérieur de la machine.

Note : Toutes les fonctions ici sont utilisées dans une script shell et dépendent d'autres éléments. Regardez le script final pour voir comment les utiliser.

Une bonne pratique pour un firewall est de jeter tous les paquets par défaut. Avec iptables ceci est relativement simple à faire :

deny_everything() {
    print_debug "Denying all connections"
 
    iptables -t filter -P INPUT   DROP
    iptables -t filter -P FORWARD DROP
    iptables -t filter -P OUTPUT  DROP
 
    end_debug $?
}

iptables est peut-être déjà configuré lorsque l'on souhaite le reconfigurer. Il peut donc être intéressant de vider les tables afin de redémarrer une configuration de 0 :

cleanup_tables() {
    print_debug "Cleaning up tables"
 
    iptables -t filter -F
    iptables -t filter -X
 
    end_debug $?
}

Si vous utiliser un serveur déjà en production il se peut qu'il est déjà accepté des connexions, les conserver comme actives peut être pratique. Ainsi, vous ne serez pas déconnecté si vous êtes connecté via SSH.

dont_break_connections() {
    print_debug "Keeping active connections"
 
    iptables -A INPUT  -m state --state RELATED,ESTABLISHED -j ACCEPT
    iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
 
    end_debug $?
}

La chose suivante à prendre en compte est d'autoriser la boucle locale sinon cela risque de poser des problèmes avec certains logiciels.

allow_loopback() {
    print_debug "Allowing loopback"
 
    iptables -t filter -A INPUT  -i lo -j ACCEPT
    iptables -t filter -A OUTPUT -o lo -j ACCEPT
 
    end_debug $?
}

Accepter des connexions sur un port avec iptables est simple. La syntaxe est plutôt claire. Il faut tout d'abord spécifier la chaîne à utiliser, INPUT ou OUTPUT, avec l'option -A, ensuite on donne le protocole de la couche transport (voir modèle OSI) à utiliser, en général soit TCP soit UDP, avec l'option -p et enfin on donne le numéro du port à ouvrir avec –dport. Cela nous donne donc une ligne de la forme :

iptables -t filter -A INPUT  -p tcp --dport 80 -j ACCEPT
iptables -t filter -A OUTPUT -p tcp --dport 80 -j ACCEPT

Maintenant vous devriez pouvoir comprendre ce script. Il utilise des fonctions pour configurer iptables.

### BEGIN INIT INFO
# Provides:          firewall
# Required-Start:    $local_fs $network
# Required-Stop:     $local_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Configure iptables (IPv4)
# Description:       Setup basic rules for iptables (IPv4)
### END INIT INFO
 
#!/bin/bash
 
. /lib/lsb/init-functions
 
# In debug mode there will be more outputs
# 0 to disable
# 1 to enable
DEBUG=0
 
# Print message only in debug mode
# Usage: print_debug ${message} ${return_code}
# ${return_code} is optional
print_debug() {
    [ ${DEBUG} -eq 0 ] && return 0
    [ $# -ne 1 ]       && return 1
 
    log_action_begin_msg ${1}
}
 
end_debug() {
    [ ${DEBUG} -eq 0 ] && return 0
    [ $# -ne 1 ]       && return 1
 
    log_action_end_msg ${1}
}
 
deny_everything() {
    print_debug "Denying connections"
 
    iptables -t filter -P INPUT   DROP
    iptables -t filter -P FORWARD DROP
    iptables -t filter -P OUTPUT  DROP
 
    end_debug $?
}
 
accept_everything() {
    print_debug "Accepting all connections"
 
    iptables -t filter -P INPUT   ACCEPT
    iptables -t filter -P FORWARD ACCEPT
    iptables -t filter -P OUTPUT  ACCEPT
 
    end_debug $?
}
 
cleanup_tables() {
    print_debug "Cleaning up tables"
 
    iptables -t filter -F
    iptables -t filter -X
 
    end_debug $?
}
 
dont_break_connections() {
    print_debug "Keeping active connections"
 
    iptables -A INPUT  -m state --state RELATED,ESTABLISHED -j ACCEPT
    iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
 
    end_debug $?
}
 
allow_loopback() {
    print_debug "Allowing loopback"
 
    iptables -t filter -A INPUT  -i lo -j ACCEPT
    iptables -t filter -A OUTPUT -o lo -j ACCEPT
 
    end_debug $?
}
 
deny_spoofing() {
    print_debug "Denying spoofing"
 
    iptables -N SPOOFED
    iptables -A SPOOFED -s 127.0.0.0/8    -j DROP
    iptables -A SPOOFED -s 169.254.0.0/12 -j DROP
    iptables -A SPOOFED -s 172.16.0.0/12  -j DROP
    iptables -A SPOOFED -s 192.168.0.0/16 -j DROP
    iptables -A SPOOFED -s 10.0.0.0/8     -j DROP
 
    end_debug $?
}
 
misc_config() {
    print_debug "Misc configurations"
 
    echo 1 > /proc/sys/net/ipv4/tcp_syncookies
    echo 0 > /proc/sys/net/ipv4/ip_forward 
    echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts 
    echo 1 >/proc/sys/net/ipv4/conf/all/log_martians 
    echo 1 > /proc/sys/net/ipv4/ip_always_defrag
    echo 1 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses
    echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
    echo 0 > /proc/sys/net/ipv4/conf/all/send_redirects
    echo 0 > /proc/sys/net/ipv4/conf/all/accept_source_route
 
    end_debug $?
}
 
open_input_port() {
    [ $# -ne 2 ] && exit 1
 
    print_debug "Opening input port ${2} in ${1}"
 
    iptables -t filter -A INPUT -p "${1}" --dport "${2}" -j ACCEPT
 
    end_debug $?
}
 
open_output_port() {
    [ $# -ne 2 ] && exit 1
 
    print_debug "Opening output port ${2} in ${1}"
 
    iptables -t filter -A OUTPUT -p "${1}" --dport "${2}" -j ACCEPT
 
    end_debug $?
}
 
allow_input_protocol() {
    [ $# -ne 1 ] && exit 1
 
    print_debug "Allowing input protocol ${1}"
 
    iptables -t filter -A INPUT -p "${1}" -j ACCEPT
 
    end_debug $?
}
 
allow_output_protocol() {
    [ $# -ne 1 ] && exit 1
 
    print_debug "Allowing output protocol ${1}"
 
    iptables -t filter -A OUTPUT -p "${1}" -j ACCEPT
 
    end_debug $?
}
 
allow_6in4_protocol() {
    [ $# -ne 1 ] && exit 1
 
    print_debug "Allowing IPv6 in IPv4 protocol"
 
    iptables -t filter -A INPUT  -s ${1} -p 41 -j ACCEPT
    iptables -t filter -A OUTPUT -p 41 -j ACCEPT
 
    end_debug $?
}
 
case ${1} in
  start)
    # Stop fail to ban before configuring firewall
    /etc/init.d/fail2ban stop
    log_action_begin_msg "Firewall (IPv4) configuration"
 
    deny_everything
    cleanup_tables
    dont_break_connections
 
    # Loopback
    allow_loopback
 
    # IPv6 in IPv4
    allow_6in4_protocol "216.66.84.42"
 
    # SSH
    open_input_port  tcp 22
    open_output_port tcp 22
 
    # DNS, FTP, HTTP, NTP
    open_output_port tcp  21
    open_output_port tcp  80
    open_output_port tcp  53
    open_output_port tcp 443
    open_output_port udp  53
    open_output_port udp 123
 
    # ICMP
    allow_input_protocol  icmp
    allow_output_protocol icmp
 
    # HTTP
    open_input_port tcp   80
    open_input_port tcp  443
 
    # MySQL
    open_input_port  tcp 3306
    open_output_port tcp 3306
 
    # POP, IMAP
    open_input_port  tcp  25
    open_input_port  tcp 110
    open_input_port  tcp 995
    open_input_port  tcp 143
    open_input_port  tcp 993
    open_output_port tcp  25
    open_output_port tcp 110
    open_output_port tcp 995
    open_output_port tcp 143
    open_output_port tcp 993
 
    # Mumble
    open_input_port  tcp 64738
    open_input_port  udp 64738
    open_output_port tcp 64738
    open_output_port udp 64738
 
    # Bazaar
    open_input_port  tcp 4155
    open_output_port tcp 4155
 
    # Keys server
    open_input_port  tcp 11371
    open_output_port tcp 11371
 
    # OpenVPN
    open_input_port  tcp 1194
    open_output_port tcp 1194
 
    # Transmission
    open_input_port  tcp  9091
    open_input_port  tcp 51413
    open_output_port tcp  9091
    open_output_port tcp 51413
 
    # Irssi
    open_input_port  tcp 6667
    open_input_port  udp 6667
    open_output_port tcp 6667
    open_output_port udp 6667
 
    # Minecraft
    for i in 25565 25566; do
        open_input_port  tcp ${i}
        open_input_port  udp ${i}
        open_output_port tcp ${i}
        open_output_port udp ${i}
    done
 
    # Steam
    for i in 7707 7708 7717 20560 28852; do
        open_input_port  udp ${i}
        open_output_port udp ${i}
    done
 
    for i in 8075 20560 28852; do
        open_input_port  tcp ${i}
        open_output_port tcp ${i}
    done
 
    for i in 27011 27900; do
        open_input_port  tcp ${i}
        open_input_port  udp ${i}
        open_output_port tcp ${i}
        open_output_port udp ${i}
    done
 
    deny_spoofing
    misc_config
 
    # Starting fail2ban again
    /etc/init.d/fail2ban start
    log_action_end_msg 0
  ;;
 
  stop)
    log_action_begin_msg "Remove firewall (IPv4) configuration"
 
    accept_everything
    cleanup_tables
 
    log_action_end_msg 0
  ;;
 
  *)
    echo "Usage: /etc/init.d/firewall {start|stop}"
    exit 1
  ;;
esac
 
exit 0

Ce script peut être placé dans /etc/init.d/ et doit avoir les droits d'exécution pour être exécuté par root. Il est aussi recommandé de d'utiliser ce script lors du démarrage du système.

update-rc.d firewall defaults

L'utilisation manuel s'effectue par “start” pour démarrer le firewall, et par “stop” pour accepter toutes les connexions et vider toutes les règles.