#!/bin/bash # Scriptname: network-discovery # Intention: Try to find some kind of network connection providing a link to # the internet. For this a list of wired interfaces is checked first. # Afterwards a list of wireless devices is checked whereas a list of # provided ESSIDs is prefered for the connection. # Optionally the script also tries to connect to whatever ESSID it can find # to get a connection (-> ESSID 'any' ). # Version: 0.1 (3.11.2007) # 0.2 (5.11.2007) # - added several sleeps # - implemented 5 retries to get the interface up with $IFCONFIG $IF up # - added a complete shutdown of all involved network interfaces at startup to get a clean start # 0.3 (13.11.2007) # - cut back the number of retries to 3 to shorten the waiting time # - added wrapper funktions 'error' and 'verbose' # - made output more compact # - added nice stuff for passing options to the script # - verbose (-v), usage (-h) and precheck_for_internet_connection (-p) switches # - availability check + global variables holding absolute paths for all needed external tools # - discovery of hidden ESSIDs now possible by setting the ESSID before the scan # - added hack for wpa support echo -ne "### network-discovery(v0.3) ###\n" ##################### # open improvements # ##################### # FIXME Log error/status messages via syslog --> logger # FIXME Trying DHCP on a network without DHCP takes an awfully long time until it aborts # FIXME Think of something better to test network connectivity # FIXME Add generic VPN support # FIXME Add generic wpa support # FIXME check if the tun module is loaded when using VPN # FIXME Add static configuration support # FIXME Check output of dhclient for what really happened # success + received ip: # DHCPACK from 192.168.0.2 # bound to 192.168.0.245 -- renewal in 1636 seconds. # no success: # No DHCPOFFERS received. # FIXME dhclient processes stay in background after trying to get an ip unsuccessfully (-> quick solution: $KILLALL at the end of the file) ################## # configuration # ################## # config for wired network interface IF_WIRED_LIST="eth0" # config for wireless network interface IF_WIRELESS_LIST="ath0" #IF_WIRELESS_ESSID_LIST="FAU-VPN HOME any" # adding 'any' to the list also tries to connect through other WLANs in range IF_WIRELESS_ESSID_LIST="FAU-VPN HOME GENTOO" # OpenVPN config for FAU-VPN FAU_VPN_PATH="/root/RRZE" #################### # global variables # #################### SCRIPTNAME=`basename $0 .sh` MIN_ARGS=0 # exit codes EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_ERROR=2 EXIT_BUG=10 # set correct delimiter IFS=" " # pre-initialization of option variables with defaults IS_CONNECTED=0 FLAG_VERBOSE=0 FLAG_PRECHECK=0 ############# # functions # ############# # error output function error { if [ $# -ge 1 ] then echo -ne "$*" >&2 fi } # verbose output controlled by $FLAG_VERBOSE function verbose { if [ $# -ge 1 ] then if (( $FLAG_VERBOSE )) then #echo "Got '$*'" echo -ne "$*" >&1 fi fi } # usage function usage { error "Usage: $SCRIPTNAME [-h] [-v]\n" if [ $# = 1 ] then exit $1 else exit $EXIT_FAILURE fi } # check if the specified file is there and executable function check_tool { if [ $# = 1 ] then verbose "Checking for '$1'..." if [ -x $1 ] then verbose "OK\n" else verbose "NOT FOUND\n" error "Needed external programm not found: ${1}\n" exit $EXIT_ERROR fi else exit $EXIT_BUG fi } # test routine for network/internet setup function check_network_connection { verbose "\052 Checking for a working internet connection..." $HOST -W1 google.com 1>/dev/null 2>&1 # FIXME should not end in a DDOS for google ;) EXIT_STATUS=$? if ( test $EXIT_STATUS = 1 ) then # no connectivity -> do nothing verbose "none found\n" fi if ( test $EXIT_STATUS = 0 ) then # YEEHA! - got a connection verbose "found\n" IS_CONNECTED=1 fi } ######## # init # ######## # test minimal number of arguments if (( $# < $MIN_ARGS )) then error "Too few arguments.\n" usage $EXIT_ERROR fi # parse arguments and set flags if necessary while getopts ':vph' OPTION do case $OPTION in v) # verbosity FLAG_VERBOSE=1 ;; h) # help usage $EXIT_SUCCESS ;; \?) # unknown option error "Unknown option \"-$OPTARG\".\n" usage $EXIT_ERROR ;; :) # missing argument for an option error "Option \"-$OPTARG\" is missing an argument.\n" usage $EXIT_ERROR ;; *) # this should not be reached (because AFAIK \? catches unknown options if ':' is specified) error "Option not implemented.\n" usage $EXIT_BUG ;; esac done shift `expr $OPTIND - 1` # notifications verbose "\052 Beeing verbose.\n" ######### # tools # ######### verbose "\052 Checking for needed external programs.\n" # list of used tools - these have to be installed of course ;) HOST="/usr/bin/host"; check_tool $HOST; CAT="/usr/bin/cat"; check_tool $CAT; IFCONFIG="/sbin/ifconfig"; check_tool $IFCONFIG; KILLALL="/usr/bin/killall"; check_tool $KILLALL; IWLIST="/sbin/iwlist"; check_tool $IWLIST; GREP="/bin/grep"; check_tool $GREP; AWK="/bin/awk"; check_tool $AWK; TR="/bin/tr"; check_tool $TR; DHCLIENT="/sbin/dhclient"; check_tool $DHCLIENT; OPENVPN="/usr/sbin/openvpn"; check_tool $OPENVPN; IWCONFIG="/sbin/iwconfig"; check_tool $IWCONFIG; ########## # script # ########## # do a pre-check if (( $FLAG_PRECHECK )) then verbose "\052 Prechecking.\n" check_network_connection; if (( $IS_CONNECTED )) then exit $EXIT_SUCCESS fi fi # FIXME # shutdown all network related stuff to have a clean starting point for reconfiguring verbose "\052 Shutting down all network interfaces/DHCP Clients/OpenVPN Clients that might be up/running.\n" for IF in $IF_WIRED_LIST do $IFCONFIG $IF down 1>/dev/null 2>&1 done for IF in $IF_WIRELESS_LIST do $IFCONFIG $IF down 1>/dev/null 2>&1 done $KILLALL dhclient 1>/dev/null 2>&1 $KILLALL openvpn 1>/dev/null 2>&1 $KILLALL wpa_supplicant 1>/dev/null 2>&1 ###### WIRED INTERFACES echo -ne "\n### WIRED INTERFACES ###\n" for IF_WIRED in $IF_WIRED_LIST do echo -ne "--> Trying wired interface ${IF_WIRED}..." # 1. check if interface exists verbose "\n\052 Checking if ${IF_WIRED} exists..." if [ ! -e /sys/class/net/${IF_WIRED} ] then # interface does not exist -> skip error "\nInterface ${IF_WIRED} not found- skipping\n" continue fi verbose "OK\n" # 2. check interface state (up/down) verbose "\052 Checking ${IF_WIRED}'s operation status..." IF_OPERSTATE=`$CAT /sys/class/net/${IF_WIRED}/operstate` verbose "${IF_OPERSTATE}\n" if [ "${IF_OPERSTATE}" = "down" ] then # interface is down verbose "Trying to bring ${IF_WIRED} up..." for i in 1 2 3 do verbose "#${i} " $IFCONFIG $IF_WIRED up 1>/dev/null 2>&1 sleep 1 IF_OPERSTATE=`$CAT /sys/class/net/${IF_WIRED}/operstate` if [ "${IF_OPERSTATE}" != "down" ] then break fi $IFCONFIG $IF_WIRED down 1>/dev/null 2>&1 done if [ "${IF_OPERSTATE}" = "down" ] then # trying to bring up the interface didn't work -> skip verbose "FAILED\n" error "Could not bring up interface ${IF_WIRED} - skipping\n" $IFCONFIG $IF_WIRED down continue else verbose "OK\n" fi fi # 3. check if the interface is actually connected to a network verbose "\052 Checking if ${IF_WIRED} is physically connected to a network..." IF_CARRIER=`$CAT /sys/class/net/${IF_WIRED}/carrier` EXIT_STATUS=$? if [ $EXIT_STATUS != 0 ] then # if the interface is down reading from /sys/class/net/${IF_WIRED}/carrier results in an error # but since we should have brought it up in step 2 this should not happen ;) verbose "FAILED\n" error "This is weird. Could not read /sys/class/net/${IF_WIRED}/carrier - skipping\n" continue fi verbose "${IF_CARRIER}\n" if [ $IF_CARRIER = 0 ] then # device is not connected to a network error "Interface ${IF_WIRED} is not connected to a network - skipping\n" $IFCONFIG ${IF_WIRED} down continue fi # 4. try to setup a working network connection verbose "\052 Trying to setup a working network connection for ${IF_WIRED}..." # try to setup the interface through DHCP verbose "DHCP-" $DHCLIENT $IF_WIRED 1>/dev/null 2>&1 EXIT_STATUS=$? if [ $EXIT_STATUS = 0 ] then verbose "OK\n" else verbose "FAILED\n" error "Error setting up ${IF_WIRED} through DHCP (exit code ${EXIT_STATUS}) - skipping\n" continue fi check_network_connection; if (( $IS_CONNECTED )) then echo -ne "OK\n" exit $EXIT_SUCCESS else # FIXME # if we get to this point there was no connection found so we shut down the tried interface again verbose "Shutting down interface ${IF_WIRED}..." $IFCONFIG ${IF_WIRED} down $KILLALL dhclient verbose "OK\n\n" fi done ###### WIRELESS INTERFACES echo -ne "\n### WIRELESS INTERFACES ###\n" for IF_WIRELESS in $IF_WIRELESS_LIST do echo -ne "--> Trying interface ${IF_WIRELESS}..." # 1. check if interface exists verbose "\n\052 Checking if ${IF_WIRELESS} exists..." if [ ! -e /sys/class/net/${IF_WIRELESS} ] then # interface does not exist -> skip error "\nInterface ${IF_WIRELESS} not found - skipping\n" continue fi verbose "OK\n" # 2. check interface state (up/down) verbose "\052 Checking ${IF_WIRELESS}'s operation status..." IF_OPERSTATE=`$CAT /sys/class/net/${IF_WIRELESS}/operstate` verbose "${IF_OPERSTATE}\n" if [ "${IF_OPERSTATE}" = "down" ] then # interface is down verbose "Trying to bring ${IF_WIRELESS} up..." for i in 1 2 3 do verbose "#${i} " $IFCONFIG $IF_WIRELESS up 1>/dev/null 2>&1 sleep 1 IF_OPERSTATE=`$CAT /sys/class/net/${IF_WIRELESS}/operstate` if [ "${IF_OPERSTATE}" != "down" ] then break fi $IFCONFIG ${IF_WIRELESS} down 1>/dev/null 2>&1 done IF_OPERSTATE=`$CAT /sys/class/net/${IF_WIRELESS}/operstate` if [ "${IF_OPERSTATE}" = "down" ] then # trying to bring up the interface didn't work -> skip verbose "FAILED\n" error "\nCould not bring up interface ${IF_WIRELESS} - skipping\n" $IFCONFIG $IF_WIRELESS down continue else verbose "OK\n" fi fi # 3. scan for desired ESSIDs in range verbose "\052 Scanning..." ESSID_LIST="" for IF_WIRELESS_ESSID in $IF_WIRELESS_ESSID_LIST do verbose "${IF_WIRELESS_ESSID} " if [ "${IF_WIRELESS_ESSID}" == "any" ] then # scan for all ESSIDs in range MATCHES=`${IWLIST} ${IF_WIRELESS} scan | ${GREP} ESSID | ${AWK} -F '"' '{print $2}' | ${TR} '\n' ' ' 2>/dev/null` # eleminate duplicates LIST="${MATCHES}" for i in $LIST do DUPLICATE_FOUND=0 for j in $ESSID_LIST do if [ "$i" = "$j" ] then DUPLICATE_FOUND=1 break fi done if [ $DUPLICATE_FOUND = 0 ] then if [ "${ESSID_LIST}" = "" ] then ESSID_LIST="${i}" else ESSID_LIST="${ESSID_LIST} ${i}" fi fi done else # configure interface for the given ESSID _before_ scan (-> also checks for hidden ESSIDs) $IWCONFIG $IF_WIRELESS essid $IF_WIRELESS_ESSID # $IWCONFIG $IF_WIRELESS essid $IF_WIRELESS_ESSID 1>/dev/null 2>&1 EXIT_STATUS=$? sleep 1 # interface configured, start scanning if [ $EXIT_STATUS = 0 ] then # scan only for the currently configured ESSID MATCHES=`${IWLIST} ${IF_WIRELESS} scan | ${GREP} ${IF_WIRELESS_ESSID} 2>/dev/null` # is the essid in range if [ "$MATCHES" ] then # desired WLAN in range found, add it to the list if [ "${ESSID_LIST}" = "" ] then ESSID_LIST="${IF_WIRELESS_ESSID}" else ESSID_LIST="${ESSID_LIST} ${IF_WIRELESS_ESSID}" fi fi else # error configuring interface error "\nError during interface setup (code ${EXIT_STATUS}) - skipping\n" continue 2 fi fi done if [ "${ESSID_LIST}" ] then # found valid WLANs verbose "OK\n" verbose "valid ESSIDs in range: ${ESSID_LIST}\n" else # no valid WLANs found -> try next interface verbose "FAILED\n" continue fi # 4. try to setup a working network connection with one of the found ESSIDs #FIXME $IFCONFIG $IF_WIRELESS down $IFCONFIG $IF_WIRELESS up sleep 1 verbose "\052 Trying to setup a working network connection for ${IF_WIRELESS}..." for ESSID in $ESSID_LIST do echo -ne "${ESSID}:" # configure interface for the given ESSID $IWCONFIG $IF_WIRELESS essid $ESSID #$IWCONFIG $IF_WIRELESS essid $ESSID 1>/dev/null 2>&1 EXIT_STATUS=$? sleep 1 if (( $EXIT_STATUS > 0 )) then error "Error during interface setup (code ${EXIT_STATUS}) - skipping\n" continue 2 fi # FIXME # connect through WLAN with WPA2 encryption if [ "$ESSID" = "GENTOO" ] then wpa_supplicant -B -Dwext -iath0 -c/root/wpa_GENTOO.conf fi # try to setup the interface through DHCP echo -ne "DHCP-" $DHCLIENT $IF_WIRELESS 1>/dev/null 2>&1 EXIT_STATUS=$? if [ $EXIT_STATUS = 0 ] then verbose "OK\n" else verbose "FAILED\n" error "Error setting up ${IF_WIRELESS} through DHCP (exit code ${EXIT_STATUS}) - skipping\n" continue fi # FIXME # connect through FAU's OpenVPN tunnel if [ "$ESSID" = "FAU-VPN" ] then verbose "\052 Connecting through FAU's OpenVPN tunnel..." PWD=`pwd` cd $FAU_VPN_PATH $OPENVPN --config RRZE-full-tunnel.ovpn --auth-user-pass secret --daemon FAU-VPN 1>/dev/null 2>&1 EXIT_STATUS=$? cd $PWD if [ $EXIT_STATUS = 0 ] then verbose "OK\n" else error "Error during OpenVPN setup (code ${EXIT_STATUS}) - skipping\n" continue 2 fi fi check_network_connection; if (( $IS_CONNECTED )) then echo -ne "OK\n" exit $EXIT_SUCCESS else # FIXME # if we get to this point there was no connection found so we shut down the tried interface again verbose "Shutting down interface ${IF_WIRED}..." $IFCONFIG ${IF_WIRED} down $KILLALL dhclient verbose "OK\n\n" fi echo -ne "\n" done done # unsuccessful exit $KILLALL dhclient # FIXME echo -ne "\nGiving up.\n" exit $EXIT_FAILURE