| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- #!/bin/bash
- #
- # Copyright (c) 2019 Clementine Computing LLC.
- #
- # This file is part of PopuFare.
- #
- # PopuFare is free software: you can redistribute it and/or modify
- # it under the terms of the GNU Affero General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # PopuFare is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU Affero General Public License for more details.
- #
- # You should have received a copy of the GNU Affero General Public License
- # along with PopuFare. If not, see <https://www.gnu.org/licenses/>.
- #
- export BASEDIR="/home/bus"
- . $BASEDIR/bin/common_values.sh
- # Do this once at boot time, but do it again after a tunnel abort request...
- #
- generate_ssh_targets
- ssh_fail_counter=0
- debug_print()
- {
- echo $@
- }
- # This function goes and looks at the version dropfiles for packages, gathering their package names
- # and versions to report when we check in with the server to log that we connected, and at what firmware and
- # config revision.
- #
- output_versions()
- {
- for file in `ls $CHECKSUM_AND_VERSION_PATH/*.version`; do
- echo -n " `echo $file | sed -r 's/^.*\/(.*)\.version$/\1/'`=`cat $file`";
- done
- }
- # This function extracts a field from the network ID dropfile by name (also used by the checkin process)
- #
- output_net_ids_field()
- {
- field="$1"
- cat $NETWORK_ID_DROPFILE | grep "$field" | cut -d'=' -f2 | xargs -n1 echo -n
- }
- # This function attempts to check in with the version server and report hardware and network serial numbers
- # so that us sysadmin types can see each time a unit attached to the network, which unit it was, and what software
- # it was running at the time.
- #
- perform_post_connect_checkin()
- {
- if [ -f $SERIAL_NUM_FILE ]; then
- busunitnum="`cat $SERIAL_NUM_FILE 2> /dev/null`"
- fi
- equipnum="`cat $EQUIP_NUM_FILE 2> /dev/null || echo 0`"
- version="`output_versions`"
- imei="`output_net_ids_field IMEI`"
- imsi="`output_net_ids_field IMSI`"
- mac="`output_net_ids_field ETH0`"
- # Send these gathered data to the update daemon. The leading '#' tells the server that this is a
- # checkin, not an update request.
- #
- echo -e "#$busunitnum\t$equipnum\t$mac\t$imei\t$imsi\t$version" | nc -q1 localhost $UPDATE_DAEMON_PORT
- }
- # This function generates the server->client port forwards to allow a sysadmin to log into any unit that is on
- # the network by equipment number, serial number, or bus number. The three parameters are:
- #
- # 1: The path to the file containing the identifying number
- # 2: The base port number on the remote server to add the identifying number to to get the server-side port that will
- # forward to port 22 (sshd) on the client side.
- # 3: An optional parameter which if present is taken as a set of command line flags to cut to apply to the contents
- # of the file specified by $1 to extract the numeric component (for instance, serial numbers may be in the form XYZ-1234
- # in which case it's really the 1234 part we're after...
- #
- generate_reverse_phonehome_component()
- {
- file="$1"
- base="$2"
- cut_cmdline="$3"
- # Make sure the candidate dropfile exists
- #
- if [ -f "$file" ]; then
- if [ -n "$cut_cmdline" ]; then
- # Grab the desired substring
- #
- num="`cat $file | cut $cut_cmdline`"
- else
- # Grab its contents
- #
- num="`cat $file`";
- fi
- # Make sure those contents are indeed numeric...
- #
- if (echo "$num" | egrep -q '^[0-9]+$'); then
- # Make sure that number is within an acceptable range so as not to overflow
- #
- if [ "$num" -gt "0" -a "$num" -le "$REVERSE_PHONE_HOME_MAX_TOKEN" ]; then
- echo -n " -R$((base + num)):localhost:22";
- fi
- fi
- fi
- }
- # This function calls the above component function for each identifying number we want to do a port forward based on...
- #
- generate_reverse_phonehome_string()
- {
- # If the reverse phone home feature is disabled, return without printing any commandline args
- #
- if [ "$REVERSE_PHONE_HOME" -eq "0" ]; then return; fi
- generate_reverse_phonehome_component $EQUIP_NUM_FILE $REVERSE_PHONE_HOME_EQNUM_BASE
- generate_reverse_phonehome_component $SERIAL_NUM_FILE $REVERSE_PHONE_HOME_SERIALNUM_BASE "-d- -f3"
- }
- # This function performs teardown on a dead ssh connection, and increments the ssh connect failure counter. If
- # that counter has reached its maximum value, we force pppd down and try a clean redial. Otherwise, we just sleep and
- # try again.
- #
- clean_up_after_tunnel_teardown()
- {
- # If the tunnel was intentionally aborted for the purpose of switching servers
- #
- if [ -f $TUNNEL_ABORT_DROPFILE ]; then
- debug_print "SSH tunnel aborted, removing dropfiles..."
- #Remove the dropfiles...
- /bin/rm -f $TUNNEL_DROPFILE $SSH_TUNNEL_PIDFILE
- #Generate new ssh target from server config dropfiles
- generate_ssh_targets
- /bin/rm -f $TUNNEL_ABORT_DROPFILE
- #Reset the failure counter
- ssh_fail_counter=0
- #Sleep until it is time to try again
- /bin/sleep $SLEEP_AFTER_TUNNEL_ABORT
-
- fi
- }
- while true; do
- #If we've just been asked to abort the SSH tunnel
- if [ -f $TUNNEL_ABORT_DROPFILE ]; then
- #Generate new ssh target from server config dropfiles
- generate_ssh_targets
- /bin/rm -f $TUNNEL_ABORT_DROPFILE
- # Reset the failure counter
- #
- ssh_fail_counter=0
- fi
- # If we have no active tunnel already...
- #
- if [ ! -f $TUNNEL_DROPFILE ]; then
- debug_print "Attempting to establish SSH tunnel... (Attempt number $((ssh_fail_counter + 1)))"
- s=`generate_reverse_phonehome_string`
- debug_print ">> ssh $SSH_OPTIONS -i $SSH_IDENTITY $SSH_FORWARDS $s -p $SSH_PORT $SSH_TARGET "
- # Attempt to create our tunnel... (incliding (if REVERSE_PHONE_HOME != 0) reverse phone home support
- #
- ssh $SSH_OPTIONS -i $SSH_IDENTITY $SSH_FORWARDS `generate_reverse_phonehome_string` -p $SSH_PORT $SSH_TARGET &
- # Remember its PID
- #
- echo "$!" > $SSH_TUNNEL_PIDFILE
- # Wait a few seconds to allow SSH negotiations
- #
- /bin/sleep $SLEEP_BEFORE_TUNNEL_TEST
- debug_print -n "Testing our new tunnel..."
- # Test to see if our tunnel is really up...
- #
- if [ "`nc localhost $HELLO_DAEMON_PORT < /dev/null`" = $HELLO_DAEMON_MESSAGE ]; then
- debug_print " It works."
- ssh_fail_counter=0
- debug_print "Checking in with server to report net IDs and package versions... "
- perform_post_connect_checkin
- debug_print "Touching dropfile and waiting for SSH to terminate..."
- # Touch our dropfile indicating the tunnel is up...
- #
- /bin/touch $TUNNEL_DROPFILE
- # and wait for the the SSH client process to end
- #
- wait `cat $SSH_TUNNEL_PIDFILE`
- # Clean Up...
- #
- clean_up_after_tunnel_teardown
- else
- debug_print " No luck..."
- debug_print "Issuing kill to SSH client...."
- # Kill the defunct and/or too slow to use SSH client
- #
- /bin/kill `cat $SSH_TUNNEL_PIDFILE`
- # Wait for the process to terminate
- #
- wait `cat $SSH_TUNNEL_PIDFILE`
- # Clean Up...
- #
- clean_up_after_tunnel_teardown
- fi
- else
- # This means we _think_ we have an SSH tunnel, but it's not one we set up...
- #
- debug_print -n "We seem to already have a pre-existing tunnel... Monitoring it."
- # Loop and periodically test this tunnel... When this condition fails, we're done...
- #
- while [ "`nc localhost $HELLO_DAEMON_PORT < /dev/null`" = $HELLO_DAEMON_MESSAGE ]; do
- # Sleep for a while before testing this tunnel again...
- #
- /bin/sleep $SLEEP_MONITORING_TUNNEL
- done
- # Clean Up...
- #
- clean_up_after_tunnel_teardown
- fi
- done
|