cli: introduce test mode and refuse firewall restart on errors
[project/firewall4.git] / root / sbin / fw4
1 #!/bin/sh
2
3 set -o pipefail
4
5 MAIN=/usr/share/firewall4/main.uc
6 LOCK=/var/run/fw4.lock
7 STATE=/var/run/fw4.state
8 VERBOSE=
9
10 [ -e /dev/stdin ] && STDIN=/dev/stdin || STDIN=/proc/self/fd/0
11
12 [ -t 2 ] && export TTY=1
13
14 die() {
15 [ -n "$QUIET" ] || echo "$@" >&2
16 exit 1
17 }
18
19 start() {
20 {
21 flock -x 1000
22
23 case "$1" in
24 start)
25 [ -f $STATE ] && die "The fw4 firewall appears to be already loaded."
26 ;;
27 reload)
28 [ ! -f $STATE ] && die "The fw4 firewall does not appear to be loaded."
29
30 # Delete state to force reloading ubus state
31 rm -f $STATE
32 ;;
33 esac
34
35 ACTION=start \
36 utpl -S $MAIN | nft $VERBOSE -f $STDIN
37
38 ACTION=includes \
39 utpl -S $MAIN
40 } 1000>$LOCK
41 }
42
43 print() {
44 ACTION=print \
45 utpl -S $MAIN
46 }
47
48 stop() {
49 {
50 flock -x 1000
51
52 if nft list tables inet | grep -sq "table inet fw4"; then
53 nft delete table inet fw4
54 rm -f $STATE
55 else
56 return 1
57 fi
58 } 1000>$LOCK
59 }
60
61 flush() {
62 {
63 flock -x 1000
64
65 local dummy family table
66 nft list tables | while read dummy family table; do
67 nft delete table "$family" "$table"
68 done
69
70 rm -f $STATE
71 } 1000>$LOCK
72 }
73
74 reload_sets() {
75 ACTION=reload-sets \
76 flock -x $LOCK utpl -S $MAIN | nft $VERBOSE -f $STDIN
77 }
78
79 lookup() {
80 ACTION=$1 OBJECT=$2 DEVICE=$3 \
81 flock -x $LOCK utpl -S $MAIN
82 }
83
84 while [ -n "$1" ]; do
85 case "$1" in
86 -q)
87 export QUIET=1
88 shift
89 ;;
90 -v)
91 export VERBOSE=-e
92 shift
93 ;;
94 *)
95 break
96 ;;
97 esac
98 done
99
100 case "$1" in
101 start|reload)
102 start "$1"
103 ;;
104 stop)
105 stop || die "The fw4 firewall does not appear to be loaded, try fw4 flush to delete all rules."
106 ;;
107 flush)
108 flush
109 ;;
110 restart)
111 QUIET=1 print | nft ${VERBOSE} -c -f $STDIN || die "The rendered ruleset contains errors, not doing firewall restart."
112 stop || rm -f $STATE
113 start
114 ;;
115 check)
116 if [ -n "$QUIET" ]; then
117 exec 1>/dev/null
118 exec 2>/dev/null
119 fi
120
121 print | nft ${VERBOSE} -c -f $STDIN && echo "Ruleset passes nftables check."
122 ;;
123 print)
124 print
125 ;;
126 reload-sets)
127 reload_sets
128 ;;
129 network|device|zone)
130 lookup "$@"
131 ;;
132 *)
133 cat <<EOT
134 Usage:
135
136 $0 [-v] [-q] start|stop|flush|restart|reload
137
138 Start, stop, flush, restart or reload the firewall respectively.
139
140
141 $0 [-v] [-q] reload-sets
142
143 Reload the contents of all declared sets but do not touch the
144 ruleset.
145
146
147 $0 [-q] print
148
149 Print the rendered ruleset.
150
151
152 $0 [-q] check
153
154 Test the rendered ruleset using nftables' check mode without
155 applying it to the running system.
156
157
158 $0 [-q] network {net}
159
160 Print the name of the firewall zone covering the given network.
161
162 Exits with code 1 if the network is not found or if no zone is
163 covering it.
164
165
166 $0 [-q] device {dev}
167
168 Print the name of the firewall zone covering the given device.
169
170 Exits with code 1 if the device is not found or if no zone is
171 covering it.
172
173
174 $0 [-q] zone {zone} [dev]
175
176 Print all covered devices of the given zone, optionally restricted
177 to only the given device name.
178
179 Exits with code 1 if zone is not found or if a device is specified
180 and not covered by the given zone.
181
182 EOT
183 ;;
184 esac