Annotation of badi/public_scripts/switchgate/switchgate, revision 1.5
1.1 adi 1: #!/bin/bash
2:
3: # switchhgate 0.0.3
4: # (c) 2005 under GPL by Adrian Zaugg
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
21: ALERT_EMAIL="adi@ente.limmat.ch"
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.3 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.5 ! adi 39: DEBUG=low
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:
1.5 ! adi 50: # parse commandline switches
! 51: function parse_commandline {
! 52:
! 53: # check rest
! 54: while [ "$#" -gt 0 ]; do
! 55:
! 56: case "$1" in
! 57:
! 58: -d|--debug)
! 59: # debug switch (another hidden feature)
! 60: shift
! 61: if [ "$1" != "low" ]; then
! 62: DEBUG="choke"
! 63: echo "Debug mode on."
! 64: else
! 65: #echo "Info mode on."
! 66: DEBUG="low"
! 67: shift
! 68: fi
! 69: ;;
! 70:
! 71: -C)
! 72: # Parse writeable dir request (hidden feature)
! 73: echo "$DHCP_TMP_DIR"
! 74: exit 0
! 75: ;;
! 76:
! 77: -q|--query)
! 78: # Parse query for current gw (yet another hidden feature)
! 79: shift
! 80: parse_commandline "$@"
! 81: getcurrentgw
! 82: echo "$CURRENTGW"
! 83: exit 0
! 84: ;;
! 85:
! 86: -s|--set)
! 87: # Set gateway to number n (yet another hidden feature)
! 88: shift
! 89: set_to_gw="$1"
! 90: shift
! 91: parse_commandline "$@"
! 92: set_gw
! 93: exit 0
! 94: ;;
! 95:
! 96: *)
! 97: echo "Invalid argument \"$1\"."
! 98: exit 1
! 99: ;;
! 100:
! 101: esac
! 102: done
! 103: }
! 104:
1.1 adi 105: # Read gateways from file
106: function readgwlist {
107: if [ -f "$GATEWAYS_FILE" ]; then
108: # Ordered list of all gateways in file. Highest preference has entry with index 0, which
109: # is your standard default gateway.
110: # dhcp[.ethX] means dhcp supplied gateways in file $CONFIG_PATH/dhcp.ethX
111: number_of_gws=0
112: if [ -n "$DEBUG" -a "$DEBUG" != "low" ]; then
113: echo "Reading config file $GATEWAYS_FILE..."
114: fi
115:
116: allgates=`grep -ve "^[ ]*[\#]\+.*$" "$GATEWAYS_FILE" | xargs`
117: for gate in $allgates; do
118: if [[ $(echo "$gate" | grep -c -e "^[:space:]*dhcp\..*$") -eq 1 && \
119: -f "$CONFIG_PATH/$gate" ]]; then
120: # Read dhcp supplied gate for a specific interface
121: alldhcpgates=`grep -e "^[^\#].*$" "$CONFIG_PATH/$gate" | xargs`
122: elif [[ $(echo "$gate" | grep -c -e "^[:space:]*dhcp[:space:]*$") -eq 1 ]]; then
123: # Read all dhcp files
124: alldhcpgates=""
125: for dhcpfile in $(echo -n $(ls -1 $DHCP_TMP_DIR/dhcp* 2>/dev/null)); do
126: alldhcpgates="$alldhcpgates `grep -e "^[^\#].*$" "$dhcpfile" | xargs`"
127: done
128: else
129: # it's a fixed gateway
130: addgw="$gate"
131: debug_msg="fixed"
132: addgateway
133: fi
134:
135: for dhcpgate in $alldhcpgates; do
136: addgw="$dhcpgate"
137: debug_msg="$gate"
138: addgateway
139: done
140: unset alldhcpgates
141: done
142: fi
1.3 adi 143:
1.1 adi 144: if [ "$number_of_gws" -eq 0 ]; then
145: echo "No gateways configured. Please edit $GATEWAYS_FILE."
146: exit 1
147: elif [[ "$number_of_gws" -eq 1 && ! -z $DEBUG ]]; then
148: echo "Only 1 gateway configured. No fallback switching possible."
149: else
150: if [[ -n "$DEBUG" && "$DEBUG" != "low" ]]; then
151: echo "... $number_of_gws gateway(s) found."
152: fi
153: fi
154: }
155:
156: # add a gateway to the array of all gateways to possibly switch to
157: function addgateway {
158: addgw=$(echo "$addgw" | tr -d ' ')
159: # check no duplicate addition is performed
160: if [ $(echo "${GW[*]}" | grep -c "$addgw") -eq 0 ]; then
161: GW[$number_of_gws]=$addgw
162: if [[ -n "$DEBUG" && "$DEBUG" != "low" ]]; then
163: echo -e "\tGateway $number_of_gws: $addgw ($debug_msg)"
164: fi
165: let "number_of_gws += 1"
166: fi
167: unset addgw
168: }
169:
170: # If one host of the HOSTSET_FILE responds, the conncetion is considered up.
171: function checkconnection {
172: UP=""
173: if [ `$PING $PINGARGS < "$HOSTSET_FILE" 2> /dev/null | grep -c "$ALIVE_ANSWER"` -gt 0 ]; then
174: UP=true
175: fi
176: if [ -n "$DEBUG" ]; then
177: if [ -n "$UP" ]; then
178: echo "The connection is up."
1.3 adi 179: else
1.1 adi 180: echo "The connection is down."
181: fi
182: fi
183: }
184:
185: # Is a certain gateway reachable?
186: function checkgw {
187: if [ `$PING $PINGARGS "$NEWGW" 2> /dev/null | grep -c "$ALIVE_ANSWER"` -gt 0 ]; then
188: if [ -n "$DEBUG" ]; then
189: echo "$NEWGW is reachable."
190: fi
191: else
1.3 adi 192: if [ -n "$DEBUG" ]; then
1.1 adi 193: echo "$NEWGW is not reachable."
194: fi
195: NEWGW=""
196: fi
197: }
198:
1.5 ! adi 199: # Get the current default gateway (or set it, if there was none set)
1.1 adi 200: function getcurrentgw {
201: iproute_default_gw_txt="$(ip route show scope global)"
202: if [ `echo $iproute_default_gw_txt | grep -c default` -gt 1 ]; then
203: echo "No support for multiple default gateways. Exiting."
204: exit 1
205: else
206: iproute_default_gw_txt="$(echo "$iproute_default_gw_txt" | grep "default via")"
1.3 adi 207: fi
1.1 adi 208: if [ -z "$iproute_default_gw_txt" ]; then
209: # no default gateway currently set, set to the highest index, to land on GW0
210: CURRENTGW_ID=0
211: CURRENTGW=${GW[$CURRENTGW_ID]}
212: echo "No default gateway currently set. Setting it now to $CURRENTGW."
213: ip route add default via $CURRENTGW
1.5 ! adi 214: if [ $? -eq 2 ]; then
! 215: echo "Not able to switch default gateway. Is your interface up?"
! 216: exit 1
! 217: fi
1.1 adi 218: else
1.3 adi 219: CURRENTGW=`echo $iproute_default_gw_txt | sed "s/^default via \(\([0-9]\+\.\?\)\{4\}\).*\$/\1/"`
1.1 adi 220: fi
1.5 ! adi 221: CURRENTGW_DEV=`echo $iproute_default_gw_txt | sed "s/^default via .* dev \(eth[0-9]\+\).*\$/\1/"`
1.1 adi 222:
223: # get index of current gateway
224: index=-1
225: for NEWGW in ${GW[*]}; do
226: let "index += 1"
227: if [ "$CURRENTGW" = "$NEWGW" ]; then
228: CURRENTGW_ID=$index
229: break
230: fi
231: done
232: if [ -z "$CURRENTGW_ID" ]; then
233: echo "The current gateway ($CURRENTGW) is not in the list of available gateways."
234: echo "Please edit $GATEWAYS_FILE to correct."
235: exit 1
236: fi
237: if [ "$DEBUG" = "low" ]; then
238: echo "Default gateway detected: $CURRENTGW ($CURRENTGW_ID) on dev $CURRENTGW_DEV"
239: fi
240: }
241:
242: # Set NEWGW and NEWGW_ID to the next gateway from GW[]
243: function getnextgw {
244: if [ -z "$NEWGW_ID" ]; then
245: if [ -z "$CURRENTGW_ID" ]; then
246: getcurrentgw
247: NEWGW_ID=$CURRENTGW_ID
248: else
249: NEWGW_ID=-1
250: fi
251: fi
252: NEWGW_ID=$[ $NEWGW_ID + 1 ]
253: if [ "$NEWGW_ID" -ge "${#GW[*]}" ]; then
254: NEWGW_ID=0
255: fi
256: NEWGW=${GW[$NEWGW_ID]}
257: }
258:
259: # Set $NEWGW to the next working gateway
260: function getnewgw {
261: getnextgw
262: # Check wheter all gateways are already tested and failed
1.5 ! adi 263: if [[ "$NEWGW_ID" -eq "$CURRENTGW_ID" && -z $set_to_gw ]]; then
1.1 adi 264: if [ -n "$DEBUG" ]; then
265: echo "All gateways tried."
266: fi
267: NEWGW=""
268: NEWGW_ID=""
269: else
270: if [ -n "$DEBUG" ]; then
271: echo -n "Trying $NEWGW..."
272: fi
273: savegw=$NEWGW
274: checkgw
275: if [ -z "$NEWGW" ]; then
276: if [ -n "$DEBUG" ]; then
277: echo "No luck. Trying next..."
278: fi
279: NEWGW=$savegw
280: getnewgw
281: else
282: if [ -n "$DEBUG" ]; then
283: echo "Successfully found a new gateway, it's $NEWGW."
284: fi
285: fi
286: fi
287: }
288:
1.5 ! adi 289: # Switch the gateway to a desired gateway
! 290: function set_gw {
! 291:
! 292: # get name of gateway
! 293: if [[ ! "$set_to_gw" =~ ^[0-9]{1,}$ ]]; then
! 294: echo "Only positive numbers allowed. Invalid value \"$set_to_gw\"."
! 295: exit 1
! 296: fi
! 297:
! 298: NEWGW=${GW[$set_to_gw]}
! 299: if [ -z "$NEWGW" ]; then
! 300: echo "The gateway number $set_to_gw is not in the list of available gateways."
! 301: echo "Valid gateways are:"
! 302: for ((gw=0; gw<${#GW[*]}; gw++)); do
! 303: echo -e "\t$gw (${GW[$gw]})"
! 304: done
! 305: exit 1
! 306: fi
! 307: if [ -n "$DEBUG" -a "$DEBUG" != "low" ]; then
! 308: echo "Default gateway desired: $NEWGW ($set_to_gw)"
! 309: fi
! 310:
! 311: getcurrentgw
! 312: NEWGW_ID=$[ $set_to_gw - 1 ]
! 313: switchgw
! 314: }
! 315:
1.1 adi 316: function switchgw {
317: getnewgw
318: if [ -n "$NEWGW" ]; then
319: if [ "$DEBUG" = "low" ]; then
320: echo -n "Switching default gateway now to $NEWGW ($NEWGW_ID)..."
1.3 adi 321: fi
322:
1.1 adi 323: iproute_msg="$(ip route change default via $NEWGW 2>&1 )"
324: iproute_exit=$?
325:
326: # generate some traffic to take effect
327: sleep 1
328: GARBAGE=`$PING -q -c 5 -t100 -p50 -A -f $HOSTSET_FILE 2> /dev/null`
329: sleep 1
1.3 adi 330:
1.1 adi 331: if [ "$DEBUG" = "low" ]; then
332: echo "done."
333: fi
334:
335: checkconnection
336: if [ -z "$UP" ]; then
337: if [ "$DEBUG" = "low" ]; then
338: echo -n "$NEWGW ($NEWGW_ID) is not working, switching back to $CURRENTGW ($CURRENTGW_ID)..."
339: fi
340: ip route change default via $CURRENTGW
341: if [ "$DEBUG" = "low" ]; then
342: echo "done."
343: fi
344: switchgw
345: elif [ "$iproute_exit" -eq 0 ]; then
346: CURRENTGW=$NEWGW
347: CURRENTGW_ID=$NEWGW_ID
348: else
349: echo "Failure from iproute: $iproute_msg"
350: echo "However, the connection is working. Continue as if nothing."
351: fi
352: else
353: if [ "$DEBUG" = "low" ]; then
354: echo "Not switching."
355: fi
356: fi
357: }
358:
359:
360: ## MAIN
361: #
362:
363:
1.3 adi 364: # Check fping existence
365: if [ ! -x "$PING" ]; then
366: echo -e "Error: Ping program not executable or not found at $PING.\nPlease configure the full path in $0."
367: exit 1
368: fi
369:
1.1 adi 370: # Get all gateways, we can forward traffic
371: readgwlist
372:
1.5 ! adi 373: # parse commandline switches
! 374: parse_commandline "$@"
1.1 adi 375:
376: # get current gw
377: getcurrentgw
378:
379: # check wether host set file is around
380: if [ ! -e $HOSTSET_FILE ]; then
381: echo "No host list found! File $HOSTSET_FILE not found."
382: exit 1
383: fi
384:
385: # check connection
386: checkconnection
387:
388: # If the connection is down, change to the nextgw
389: if [ -z "$UP" ]; then
390: # Some more information of down reason: Diagnose wheter the current gateway is alive
391: NEWGW=$CURRENTGW
392: checkgw
393: if [ -z "$NEWGW" ]; then
394: echo "Gateway $CURRENTGW is down."
1.3 adi 395: else
1.1 adi 396: echo "No connection through gateway $CURRENTGW."
397: fi
1.3 adi 398:
1.1 adi 399: NEWGW_ID=$CURRENTGW_ID
400: switchgw
1.3 adi 401:
1.1 adi 402: else
403: # If the current gateway is not the standard default gateway, try if the connection
404: # through the standard default gateway is back
405: if [ "$CURRENTGW_ID" != 0 ]; then
406: if [ "$DEBUG" = "low" ]; then
407: echo "Not operating on standard default gateway (${GW[0]}). Trying to change."
408: fi
409: NEWGW_ID=""
410: switchgw
411: else
412: # normal operation
413: if [[ -n "$DEBUG" && "$DEBUG" != "low" ]]; then
414: echo "Normal operation on standard default gateway $CURRENTGW ($CURRENTGW_ID)."
415: fi
416: fi
417: fi
418:
1.2 adi 419: # send an eMail if the connection is down or limited
420: if [ -z "$UP" ]; then
1.4 adi 421: EMAIL_BODY="Switchgate on $(hostname -f) reports: No connection!\n\nTime:\t\t$(date)\nGateway:\t$CURRENTGW ($CURRENTGW_ID)"
1.2 adi 422: EMAIL_SUBJECT="Attention: $(hostname -f) has no connection!"
423: echo -e "$EMAIL_BODY" | mail -s "$EMAIL_SUBJECT" "$ALERT_EMAIL"
424: if [[ -n "$DEBUG" && "$DEBUG" != "low" ]]; then
425: echo "Alert message sent to $ALERT_EMAIL."
426: fi
427: elif [ "$CURRENTGW_ID" != 0 ]; then
1.4 adi 428: EMAIL_BODY="Switchgate on $(hostname -f) reports: Not operating on standard default gateway!\n\nTime:\t\t$(date)\nGateway:\t$CURRENTGW ($CURRENTGW_ID)"
429: EMAIL_SUBJECT="Attention: $(hostname -f) not operating on standard default gateway!"
1.2 adi 430: echo -e "$EMAIL_BODY" | mail -s "$EMAIL_SUBJECT" "$ALERT_EMAIL"
431: if [[ -n "$DEBUG" && "$DEBUG" != "low" ]]; then
432: echo "Alert message sent to $ALERT_EMAIL."
433: fi
434: fi
435:
1.1 adi 436: if [ "$DEBUG" = "low" ]; then
437: echo
438: echo "Default Gateway: $CURRENTGW ($CURRENTGW_ID)"
439: echo
440: fi
441: exit 0
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>