Annotation of badi/public_scripts/switchgate/switchgate, revision 1.8
1.1 adi 1: #!/bin/bash
2:
1.8 ! adi 3: # switchhgate 0.0.5
1.7 adi 4: # (c) 2005-2010 under GPL by Adrian Zaugg
1.1 adi 5:
6: # switchgate pings a set of hosts to determine the state of the internet connectivity. If
7: # the connection is down, it can change the default gateway to an alternative gateway.
8:
9: ## Settings
10: #
11:
12: # Where the config files reside
13: CONFIG_PATH="/etc/switchgate"
14:
15: # Path where to find dhcp information file from switchgate-helper,
16: # the dhclient-exit-hook helper program
17: DHCP_TMP_DIR=/tmp/switchgate
18:
1.2 adi 19: # eMail address to send alert messages, if not operating on the
20: # standard default gateway
1.7 adi 21: ALERT_EMAIL="adi@ente.limmat.ch"
1.2 adi 22:
1.1 adi 23: # Host set to ping. A file containing IP addresses, each on a single line.
24: # Do not include any local hosts, list only hosts located behind your gateways.
25: HOSTSET_FILE="$CONFIG_PATH/hostset"
26:
27: # The file defining fixed and dynamic gateway preference
28: GATEWAYS_FILE="$CONFIG_PATH/gateways"
29:
30: # path to fping
1.7 adi 31: PING=/usr/bin/fping
1.1 adi 32:
33: # answer of fping to reachable hosts
34: ALIVE_ANSWER="is alive"
35:
36: # set to an empty string to avoid debug output
37: # to "low" for a few output and to anything else
38: # for verbose output
1.6 adi 39: DEBUG=
1.1 adi 40:
41:
42: # -------- Do not edit below this line --------
43:
44: PINGARGS="-A -p25 -t100"
45:
46:
47: ## Function declarations
48: #
49:
50: # Read gateways from file
51: function readgwlist {
52: if [ -f "$GATEWAYS_FILE" ]; then
53: # Ordered list of all gateways in file. Highest preference has entry with index 0, which
54: # is your standard default gateway.
55: # dhcp[.ethX] means dhcp supplied gateways in file $CONFIG_PATH/dhcp.ethX
56: number_of_gws=0
57: if [ -n "$DEBUG" -a "$DEBUG" != "low" ]; then
58: echo "Reading config file $GATEWAYS_FILE..."
59: fi
60:
61: allgates=`grep -ve "^[ ]*[\#]\+.*$" "$GATEWAYS_FILE" | xargs`
1.8 ! adi 62: alldhcpgates=""
1.1 adi 63: for gate in $allgates; do
1.8 ! adi 64: if [[ $(echo "$gate" | grep -c -e "^[[:space:]]*dhcp\..*$") -eq 1 && \
! 65: -f "$DHCP_TMP_DIR/$gate" ]]; then
1.1 adi 66: # Read dhcp supplied gate for a specific interface
1.8 ! adi 67: alldhcpgates="$alldhcpgates `grep -e "^[^\#].*$" "$DHCP_TMP_DIR/$gate" | xargs`"
! 68: elif [[ $(echo "$gate" | grep -c -e "^[[:space:]]*dhcp[[:space:]]*$") -eq 1 ]]; then
1.1 adi 69: # Read all dhcp files
1.8 ! adi 70: for dhcpfile in $(echo -n $(ls -1 $DHCP_TMP_DIR/dhcp* 2>/dev/null)); do
1.1 adi 71: alldhcpgates="$alldhcpgates `grep -e "^[^\#].*$" "$dhcpfile" | xargs`"
72: done
73: else
74: # it's a fixed gateway
75: addgw="$gate"
76: debug_msg="fixed"
77: addgateway
78: fi
79:
80: for dhcpgate in $alldhcpgates; do
81: addgw="$dhcpgate"
82: debug_msg="$gate"
83: addgateway
84: done
85: unset alldhcpgates
86: done
87: fi
1.3 adi 88:
1.1 adi 89: if [ "$number_of_gws" -eq 0 ]; then
90: echo "No gateways configured. Please edit $GATEWAYS_FILE."
91: exit 1
92: elif [[ "$number_of_gws" -eq 1 && ! -z $DEBUG ]]; then
93: echo "Only 1 gateway configured. No fallback switching possible."
94: else
95: if [[ -n "$DEBUG" && "$DEBUG" != "low" ]]; then
96: echo "... $number_of_gws gateway(s) found."
97: fi
98: fi
99: }
100:
101: # add a gateway to the array of all gateways to possibly switch to
102: function addgateway {
103: addgw=$(echo "$addgw" | tr -d ' ')
104: # check no duplicate addition is performed
105: if [ $(echo "${GW[*]}" | grep -c "$addgw") -eq 0 ]; then
106: GW[$number_of_gws]=$addgw
107: if [[ -n "$DEBUG" && "$DEBUG" != "low" ]]; then
108: echo -e "\tGateway $number_of_gws: $addgw ($debug_msg)"
109: fi
110: let "number_of_gws += 1"
111: fi
112: unset addgw
113: }
114:
115: # If one host of the HOSTSET_FILE responds, the conncetion is considered up.
116: function checkconnection {
117: UP=""
118: if [ `$PING $PINGARGS < "$HOSTSET_FILE" 2> /dev/null | grep -c "$ALIVE_ANSWER"` -gt 0 ]; then
119: UP=true
120: fi
121: if [ -n "$DEBUG" ]; then
122: if [ -n "$UP" ]; then
123: echo "The connection is up."
1.3 adi 124: else
1.1 adi 125: echo "The connection is down."
126: fi
127: fi
128: }
129:
130: # Is a certain gateway reachable?
131: function checkgw {
132: if [ `$PING $PINGARGS "$NEWGW" 2> /dev/null | grep -c "$ALIVE_ANSWER"` -gt 0 ]; then
133: if [ -n "$DEBUG" ]; then
134: echo "$NEWGW is reachable."
135: fi
136: else
1.3 adi 137: if [ -n "$DEBUG" ]; then
1.1 adi 138: echo "$NEWGW is not reachable."
139: fi
140: NEWGW=""
141: fi
142: }
143:
144: function getcurrentgw {
145: iproute_default_gw_txt="$(ip route show scope global)"
146: if [ `echo $iproute_default_gw_txt | grep -c default` -gt 1 ]; then
147: echo "No support for multiple default gateways. Exiting."
148: exit 1
149: else
150: iproute_default_gw_txt="$(echo "$iproute_default_gw_txt" | grep "default via")"
1.3 adi 151: fi
1.1 adi 152: if [ -z "$iproute_default_gw_txt" ]; then
153: # no default gateway currently set, set to the highest index, to land on GW0
154: CURRENTGW_ID=0
155: CURRENTGW=${GW[$CURRENTGW_ID]}
1.6 adi 156: CURRENTGW_DEV="unknown"
1.1 adi 157: echo "No default gateway currently set. Setting it now to $CURRENTGW."
158: ip route add default via $CURRENTGW
159: else
1.3 adi 160: CURRENTGW=`echo $iproute_default_gw_txt | sed "s/^default via \(\([0-9]\+\.\?\)\{4\}\).*\$/\1/"`
1.6 adi 161: CURRENTGW_DEV=`echo $iproute_default_gw_txt | sed "s/^default via .* dev \(eth[0-9]\+\).*\$/\1/"`
1.1 adi 162: fi
163:
164: # get index of current gateway
165: index=-1
166: for NEWGW in ${GW[*]}; do
167: let "index += 1"
168: if [ "$CURRENTGW" = "$NEWGW" ]; then
169: CURRENTGW_ID=$index
170: break
171: fi
172: done
173: if [ -z "$CURRENTGW_ID" ]; then
174: echo "The current gateway ($CURRENTGW) is not in the list of available gateways."
175: echo "Please edit $GATEWAYS_FILE to correct."
176: exit 1
177: fi
178: if [ "$DEBUG" = "low" ]; then
179: echo "Default gateway detected: $CURRENTGW ($CURRENTGW_ID) on dev $CURRENTGW_DEV"
180: fi
181: }
182:
183: # Set NEWGW and NEWGW_ID to the next gateway from GW[]
184: function getnextgw {
185: if [ -z "$NEWGW_ID" ]; then
186: if [ -z "$CURRENTGW_ID" ]; then
187: getcurrentgw
188: NEWGW_ID=$CURRENTGW_ID
189: else
190: NEWGW_ID=-1
191: fi
192: fi
193: NEWGW_ID=$[ $NEWGW_ID + 1 ]
194: if [ "$NEWGW_ID" -ge "${#GW[*]}" ]; then
195: NEWGW_ID=0
196: fi
197: NEWGW=${GW[$NEWGW_ID]}
198: }
199:
200: # Set $NEWGW to the next working gateway
201: function getnewgw {
202: getnextgw
203: # Check wheter all gateways are already tested and failed
1.6 adi 204: if [ "$NEWGW_ID" -eq "$CURRENTGW_ID" ]; then
1.1 adi 205: if [ -n "$DEBUG" ]; then
206: echo "All gateways tried."
207: fi
208: NEWGW=""
209: NEWGW_ID=""
210: else
211: if [ -n "$DEBUG" ]; then
212: echo -n "Trying $NEWGW..."
213: fi
214: savegw=$NEWGW
215: checkgw
216: if [ -z "$NEWGW" ]; then
217: if [ -n "$DEBUG" ]; then
218: echo "No luck. Trying next..."
219: fi
220: NEWGW=$savegw
221: getnewgw
222: else
223: if [ -n "$DEBUG" ]; then
224: echo "Successfully found a new gateway, it's $NEWGW."
225: fi
226: fi
227: fi
228: }
229:
230: function switchgw {
231: getnewgw
232: if [ -n "$NEWGW" ]; then
233: if [ "$DEBUG" = "low" ]; then
234: echo -n "Switching default gateway now to $NEWGW ($NEWGW_ID)..."
1.3 adi 235: fi
236:
1.1 adi 237: iproute_msg="$(ip route change default via $NEWGW 2>&1 )"
238: iproute_exit=$?
239:
240: # generate some traffic to take effect
241: sleep 1
242: GARBAGE=`$PING -q -c 5 -t100 -p50 -A -f $HOSTSET_FILE 2> /dev/null`
243: sleep 1
1.3 adi 244:
1.1 adi 245: if [ "$DEBUG" = "low" ]; then
246: echo "done."
247: fi
248:
249: checkconnection
250: if [ -z "$UP" ]; then
251: if [ "$DEBUG" = "low" ]; then
252: echo -n "$NEWGW ($NEWGW_ID) is not working, switching back to $CURRENTGW ($CURRENTGW_ID)..."
253: fi
254: ip route change default via $CURRENTGW
255: if [ "$DEBUG" = "low" ]; then
256: echo "done."
257: fi
258: switchgw
259: elif [ "$iproute_exit" -eq 0 ]; then
260: CURRENTGW=$NEWGW
261: CURRENTGW_ID=$NEWGW_ID
262: else
263: echo "Failure from iproute: $iproute_msg"
264: echo "However, the connection is working. Continue as if nothing."
265: fi
266: else
267: if [ "$DEBUG" = "low" ]; then
268: echo "Not switching."
269: fi
270: fi
271: }
272:
273:
274: ## MAIN
275: #
276:
1.6 adi 277: # Parse writeable dir request (hidden feature)
278: if [ "$1" = "-C" ]; then
279: echo "$DHCP_TMP_DIR"
280: exit 0
281: fi
282:
283: # Parse debug switch (another hidden feature)
284: if [ "$1" = "-d" ]; then
285: if [ "$2" != "low" ]; then
286: echo "Debug mode on."
287: DEBUG="choke"
288: else
289: #echo "Info mode on."
290: DEBUG="low"
291: fi
292: fi
1.1 adi 293:
1.3 adi 294: # Check fping existence
295: if [ ! -x "$PING" ]; then
296: echo -e "Error: Ping program not executable or not found at $PING.\nPlease configure the full path in $0."
297: exit 1
298: fi
299:
1.1 adi 300: # Get all gateways, we can forward traffic
301: readgwlist
302:
1.6 adi 303: # Parse query for current gw (yet another hidden feature)
304: if [ "$1" = "-q" ]; then
305: DEBUG=
306: getcurrentgw
307: echo "$CURRENTGW"
308: exit 0
309: fi
1.1 adi 310:
311: # get current gw
312: getcurrentgw
313:
314: # check wether host set file is around
315: if [ ! -e $HOSTSET_FILE ]; then
316: echo "No host list found! File $HOSTSET_FILE not found."
317: exit 1
318: fi
319:
320: # check connection
321: checkconnection
322:
323: # If the connection is down, change to the nextgw
324: if [ -z "$UP" ]; then
325: # Some more information of down reason: Diagnose wheter the current gateway is alive
326: NEWGW=$CURRENTGW
327: checkgw
328: if [ -z "$NEWGW" ]; then
329: echo "Gateway $CURRENTGW is down."
1.3 adi 330: else
1.1 adi 331: echo "No connection through gateway $CURRENTGW."
332: fi
1.3 adi 333:
1.1 adi 334: NEWGW_ID=$CURRENTGW_ID
335: switchgw
1.3 adi 336:
1.1 adi 337: else
338: # If the current gateway is not the standard default gateway, try if the connection
339: # through the standard default gateway is back
340: if [ "$CURRENTGW_ID" != 0 ]; then
341: if [ "$DEBUG" = "low" ]; then
342: echo "Not operating on standard default gateway (${GW[0]}). Trying to change."
343: fi
344: NEWGW_ID=""
345: switchgw
346: else
347: # normal operation
348: if [[ -n "$DEBUG" && "$DEBUG" != "low" ]]; then
349: echo "Normal operation on standard default gateway $CURRENTGW ($CURRENTGW_ID)."
350: fi
351: fi
352: fi
353:
1.2 adi 354: # send an eMail if the connection is down or limited
355: if [ -z "$UP" ]; then
1.6 adi 356: if [ -z "$NEWGW" ]; then
357: EMAIL_BODY="Switchgate on $(hostname -f) reports: No connection!\n\nTime:\t\t$(date)\nGateway:\t$CURRENTGW ($CURRENTGW_ID)"
358: EMAIL_SUBJECT="Attention: $(hostname -f) has no connection!"
359: echo -e "$EMAIL_BODY" | mail -s "$EMAIL_SUBJECT" "$ALERT_EMAIL"
360: if [[ -n "$DEBUG" && "$DEBUG" != "low" ]]; then
361: echo "Alert message sent to $ALERT_EMAIL."
362: fi
1.2 adi 363: fi
364: elif [ "$CURRENTGW_ID" != 0 ]; then
1.4 adi 365: EMAIL_BODY="Switchgate on $(hostname -f) reports: Not operating on standard default gateway!\n\nTime:\t\t$(date)\nGateway:\t$CURRENTGW ($CURRENTGW_ID)"
366: EMAIL_SUBJECT="Attention: $(hostname -f) not operating on standard default gateway!"
1.2 adi 367: echo -e "$EMAIL_BODY" | mail -s "$EMAIL_SUBJECT" "$ALERT_EMAIL"
368: if [[ -n "$DEBUG" && "$DEBUG" != "low" ]]; then
369: echo "Alert message sent to $ALERT_EMAIL."
370: fi
371: fi
372:
1.7 adi 373: if [ "$DEBUG" = "low" -o "$DEBUG" = "choke" ]; then
374: if [ -n "$UP" ]; then
375: echo
376: echo "Current Default Gateway: $CURRENTGW ($CURRENTGW_ID)"
377: echo
378: else
379: echo
380: echo "No connection."
381: echo
382: fi
1.1 adi 383: fi
384: exit 0
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>