Tags

ipfw shell

Powered by

blOg
maRkdown
awK
shEll

07/12/2019

[ ipfw shell ]

201912070800 ipfw shell

ipfw: modern FreeBSD

C'est pas moi qui le dit:

$ man ipfw
...
RULE BODY
...
 The rule body has the following format:
       [proto from src to dst] [options]
 The first part (proto from src to dst) is for backward compatibility with
 earlier versions of FreeBSD.  In modern FreeBSD any match pattern
 (including MAC headers, IP protocols, addresses and ports) can be
 specified in the options section.

Mes recherches de fichiers de règles basées sur la syntaxe [options] ne m'ayant pas donné satisfaction, j'ai décidé de dégainer mon $EDITOR. Mais avant de parler code, parlons contexte et objectifs:

Configuration

Je n'utilise pas le fichier /etc/rc.conf, je lui préfère le répertoire /etc/rc.conf.d. Mon script de règles sera donc /etc/rc.conf.d/rc.firewall et mes variables seront réparties dans des fichiers placés dans /etc/rc.conf.d/ipfw/.

Version initiale

Je commence par ces quelques lignes:

$ cat -n /etc/rc.conf.d/rc.firewall
 1  set -e
 2
 3  . /etc/rc.subr
 4  load_rc_config ipfw
 5
 6  set -u
 7
 8  [ $# -eq 1 ] && [ $1 = "-d" ] && firewall_debug=YES
 9
10  fwcmd=/sbin/ipfw
11  case ${firewall_quiet:-} in
12          [Yy][Ee][Ss]) fwcmd="$fwcmd -q";;
13  esac
14
15  case ${firewall_debug:-NO} in
16          [Yy][Ee][Ss]) fwcmd="echo $fwcmd";;
17                     *) firewall_debug='NO';;
18  esac
19
20  $fwcmd -f flush

On peut déjà utiliser le script:

$ /bin/sh /etc/rc.conf.d/rc.firewall -d
/sbin/ipfw -f flush

Version minimale

$ cat -n /etc/rc.conf.d/rc.firewall
 1	set -e
 2	
 3	set_31() {
 4		[ ${firewall_debug} = 'NO' -a $($fwcmd set 31 list | wc -l) -gt 1 ] && return
 5	
 6		$add set 31 check-state
 7		$add set 31 pass { dst-port 22 or src-port 22 }
 8	}
 9	
10	. /etc/rc.subr
11	load_rc_config ipfw
12	
13	set -u
14	
15	[ $# -eq 1 ] && [ $1 = "-d" ] && firewall_debug=YES
16	
17	fwcmd=/sbin/ipfw
18	case ${firewall_quiet:-} in
19	        [Yy][Ee][Ss]) fwcmd="$fwcmd -q";;
20	esac
21	
22	case ${firewall_debug:-NO} in
23	        [Yy][Ee][Ss]) fwcmd="echo $fwcmd";;
24	                   *) firewall_debug='NO';;
25	esac
26	
27	add="$fwcmd add"
28	
29	set_31
30	$fwcmd -f flush
31	
32	$add pass via lo0
33	$add pass out keep-state

Concernant l'utilisation du set 31:

$ man ipfw
...
         Set 31 is special in that it cannot be disabled, and rules in set
         31 are not deleted by the ipfw flush command (but you can delete
         them with the ipfw delete set 31 command).  Set 31 is also used
         for the default rule.

Il ne faut *SURTOUT PAS* que le trafic "ssh" fasse l'objet de règles dynamiques car elles sont supprimées lors d'un /sbin/ipfw -f flush.

Je peux maintenant me connecter sur la machine distante et y faire des sudo service ipfw restart ou des /sbin/ipfw -f flush sans perdre la connexion.

SSH restreint

Je ne suis pas du genre à laisser mon port ssh ouvert aux 4 vents mais je peux aussi avoir des gros doigts. Comme mon set 31 n'est défini qu'une et une seule fois, je peux faire un maximum de tests et je n'hésite pas à jouer avec le mode trace (/bin/sh /etc/rc.conf.d/rc.firewall -d).

 3	set_31() {
 4		[ ${firewall_debug} = 'NO' -a $($fwcmd set 31 list | wc -l) -gt 1 ] && return
 5	
 6		$add set 31 check-state
 7		if [ -z "${firewall_ssh6:-}" -a -z "${firewall_ssh4:-}" ]; then
 8			$add set 31 pass { dst-port 22 or src-port 22 }
 9		else
10			$add set 31 pass src-port 22 out
11			[ -n "${firewall_ssh6:-}" ] && $add set 31 pass dst-port 22 in src-ip6 ${firewall_ssh6} || :
12			[ -n "${firewall_ssh4:-}" ] && $add set 31 pass dst-port 22 in src-ip  ${firewall_ssh4} || :
13		fi
14	}
...
40	$add pass { proto ipv6-icmp or proto icmp }
41	$add deny log in

Au final

$ sudo ipfw -d -S show
00100    0       0 set 31 check-state :default
00200 3780 1509406 set 31 allow src-port 22 out
00300 3675  341057 set 31 allow dst-port 22 in src-ip6 2001:db8::/64
00400    0       0 set 31 allow dst-port 22 in src-ip 192.168.99.0/24
00500 1169   97093 set 0 allow out keep-state :default
00600    0       0 set 0 allow via lo0
00700   60    4332 set 0 allow { proto ipv6-icmp or proto icmp }
00800    2     656 set 0 deny log in
65535    0       0 set 31 deny ip from any to any

Il reste à voir les tables, le nat et 2/3 trucs auxquels je n'ai pas encore pensé.

Commentaires: https://github.com/bsdsx/blog_posts/issues/1


Lien vers ce billet