chiark / gitweb /
local.m4: New address range for untrusted VPN hosts.
[firewall] / prologue.m4
1 ### -*-sh-*-
2 ###
3 ### Failsafe prologue for firewall scripts
4 ###
5 ### (c) 2008 Mark Wooding
6 ###
7
8 ###----- Licensing notice ---------------------------------------------------
9 ###
10 ### This program is free software; you can redistribute it and/or modify
11 ### it under the terms of the GNU General Public License as published by
12 ### the Free Software Foundation; either version 2 of the License, or
13 ### (at your option) any later version.
14 ###
15 ### This program is distributed in the hope that it will be useful,
16 ### but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ### GNU General Public License for more details.
19 ###
20 ### You should have received a copy of the GNU General Public License
21 ### along with this program; if not, write to the Free Software Foundation,
22 ### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 m4_divert(10)m4_dnl
25 ###--------------------------------------------------------------------------
26 ### Failsafe prologue.
27
28 revert () {
29   escape=$1 badness=$2
30   ## Report a firewall script failure and retreat to a safe place.
31
32   echo "$2!  Retreating to safe version..."
33   if [ -f /var/run/firewall.save ] && [ -f /var/run/firewall6.save ]; then
34     echo "Trying to loading saved firewall state..."
35     if iptables-restore </var/run/firewall.save &&
36        ip6tables-restore </var/run/firewall6.save; then
37       echo "Previous firewall state restored."
38       return
39     else
40       echo "Failed!  Falling back to plan B."
41     fi
42   fi
43   if ! "$1" revert; then
44     echo >&2 "Safe firewall failed.  You're screwed.  Good luck."
45     exit 1
46   fi
47   echo >&2 "Phew!  Fallback to safe version successful."
48   exit 1
49 }
50
51 finished () {
52   echo "Done."
53   exit 0
54 }
55
56 try () {
57   old=$1 new=$2
58   ## Install the NEW firewall rules.  If it fails, revert to the OLD ones.
59   ## Updating firewall rules can fail spectacularly, so be careful.  Leave a
60   ## timebomb in the form of NEW.errors: if this isn't removed in 10 seconds
61   ## after the NEW rules complete successfully, then revert.  Write errors to
62   ## NEW.errors.
63
64   ## Make sure we have an escape route.
65   iptables-save >/var/run/firewall.save.new
66   ip6tables-save >/var/run/firewall6.save.new
67   mv /var/run/firewall.save.new /var/run/firewall.save
68   mv /var/run/firewall6.save.new /var/run/firewall6.save
69
70   ## Clear the air and make the errors file.
71   rm -f "$new.errors" "$new.timebomb" "$new.grabbed"
72   exec >"$new.errors" 2>&1
73
74   ## Now try to install the new firewall.
75   "$new" install || revert "$old" "Failed"
76
77   ## Set up the time bomb.  Leave the errors file there if we failed.
78   (sleep 10
79    if [ -f "$new.errors" ]; then
80      mv "$new.errors" "$new.timebomb"
81      revert "$old" "Time bomb"
82    fi)&
83 }
84
85 catch () {
86   new=$1
87   ## Report successful installation of the script.
88
89   if mv "$new.errors" "$new.grabbed" 2>/dev/null; then
90     rc=0
91     echo "Installed OK."
92   else
93     mv "$new.timebomb" "$new.grabbed"
94     echo "Timebomb went off."
95     rc=1
96   fi
97   cat "$new.grabbed" >&2
98   rm -f "$new.grabbed"
99   return $rc
100 }
101
102 exit_after_clearing=:
103 export FWCOOKIE=magical
104 case "$#,${1-update}" in
105   1,start | 1,restart | 1,reload | 1,force-reload)
106     echo -n "Starting up firewall... "
107     "$firewall_script" install || revert "$firewall_failsafe" "Failed"
108     finished
109     ;;
110   1,stop)
111     echo -n "Shutting down firewall... "
112     exit_after_clearing=finished
113     ;;
114   1,replace | 1,test)
115     echo -n "Running new firewall... "
116     if ! (try "$firewall_script" "$0"); then
117       echo "FAILED."
118       cat "$0.errors" >&2
119       exit
120     fi
121     echo "done."
122     echo "Can you hear me?"
123     (trap 'exit 127' TERM
124      while :; do
125        if [ -f "$0.timebomb" ]; then
126          kill $$
127          echo "Timebomb went off!"
128          cat "$0.timebomb"
129          exit 1
130        fi
131        sleep 1
132      done)&
133     read answer
134     kill $!
135     catch "$0"
136     case "$1,$answer" in
137       replace,y* | replace,Y*)
138         install -m755 "$0" "$firewall_script"
139         echo "Cool.  Firewall script replaced."
140         exit 0
141         ;;
142       test,y* | test,Y*)
143         echo "Cool.  Everything seems good."
144         exit 0
145         ;;
146       *)
147         revert "$firewall_script" "Bogus"
148         ;;
149     esac
150     ;;
151   1,remote-prepare)
152     try "$firewall_script" "$0"
153     exit 0
154     ;;
155   1,remote-commit)
156     catch "$0"
157     install -m755 "$0" "$firewall_script"
158     exit 0
159     ;;
160   1,install | 1,revert)
161     ;;
162   *)
163     cat >&2 <<EOF
164 Usage:
165         $0 start|stop|reload|restart|force-reload
166         $0 replace|test|remote-prepare|remote-commit
167 EOF
168     exit 1
169     ;;
170 esac
171
172 m4_divert(-1)
173 ###----- That's all, folks --------------------------------------------------