Skip to content

Instantly share code, notes, and snippets.

@hdoverobinson
Created July 27, 2017 05:42
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save hdoverobinson/f029c83171d75aad6a104d05802e7c18 to your computer and use it in GitHub Desktop.
Save hdoverobinson/f029c83171d75aad6a104d05802e7c18 to your computer and use it in GitHub Desktop.
Out-of-band management with DTMF tones on SIMCom cellular modem
#!/bin/bash
###AUTHOR###
#Harry Dove-Robinson 7/27/2017
#harry@doverobinson.me
#https://gist.github.com/hdoverobinson
#https://github.com/hdoverobinson
###USAGE###
#This is a script used for out-of-band management by way of DTMF tones over voice calls to a SIMCom cellular modem.
#The script utilizes the DTMF parsing capabilities of SIMCom firmware and uses the tones as triggers for script actions.
#Only phone calls from numbers defined in the variables PHONE1 and PHONE2 will be answered. The country code must be included.
#The DTMF interface is protected by Google Authenticator. The current TOTP code must be entered after the tone at the start of the call.
#After authentication, the user can then enter the number of the desired script action and the action will run in the system shell.
#Currently, three script actions are defined by the variables MENU1, MENU2, and MENU3. The user should define their own actions.
#The MODEM variable should be set to the character device file of the SIMCom modem. The STTY variable sets the modem at 9600 baud.
#The TOTP variable should point to the first line of the user's .google_authenticator file.
#The user should familiarize themselves with the tone sequences used in this script:
#SUCCESS: 1,2,3
#FAILURE: #,#,#
#GOODBYE: 3,2,1
#This line is used in the crontab to run the script in the background at startup:
#@reboot /usr/bin/screen -dmS dtmf-oobm /bin/bash -c "while true; do dtmf-oobm.sh; sleep 5s; done"
#The script is currently used on a Raspberry Pi 3 with a SIMCom SIM800 GSM module from ITead.
export MODEM=/dev/gsm0
export STTY="406:0:8bd:8a30:3:1c:7f:8:4:2:64:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0"
export TOTP=`/usr/bin/head -1 /root/.google_authenticator`
export PHONE1="XXXXXXXXXXX"
export PHONE2="XXXXXXXXXXX"
export MENU1="/sbin/reboot"
export MENU2="CHANGEME"
export MENU3="CHANGEME"
set -x
#initialize modem and serial port
initialize ()
{
stty -F $MODEM $STTY
echo -e "ATH\n" > $MODEM
sleep .5s
echo -e "AT&F\n" > $MODEM
sleep .5s
echo -e "AT&W\n" > $MODEM
sleep .5s
echo -e "ATZ\n" > $MODEM
sleep .5s
echo -e "AT+CLIP=1\n" > $MODEM
sleep .5s
echo -e "AT+DDET=1\n" > $MODEM
sleep .5s
echo -e "ATS0=0\n" > $MODEM
sleep .5s
}
#answer if caller matches and wait 5s for call to start
answer ()
{
cat $MODEM | grep -q -e "+CLCC: 1,1,4,0,0,\""$PHONE1\"",129,\"\"" -e "+CLCC: 1,1,4,0,0,\""$PHONE2\"",129,\"\"" && echo -e "ATA\n" > $MODEM
sleep 5s
}
#play tone and start 10s timeout to input code
codecheck ()
{
GOOGLEAUTH=$(oathtool --base32 --totp $TOTP -d 6)
echo -e "AT+VTS=1\n" > $MODEM && timeout 10s awk -W interactive '/DTMF/{gsub(/[\n\r]/," ");printf $2}' $MODEM | grep -q $GOOGLEAUTH
}
#play SUCCESS tone
returnsuccess ()
{
echo "SUCCESS" && echo -e 'AT+VTS="1,2,3"\n' > $MODEM
}
#play FAILURE tone
returnfailure ()
{
echo "FAILURE" && echo -e 'AT+VTS="#,#,#"\n' > $MODEM
}
#play GOODBYE tone and hang up
goodbye ()
{
echo "GOODBYE" && echo -e 'AT+VTS="3,2,1"\n' > $MODEM && sleep 2s && echo -e "ATH0\n" > $MODEM
}
#wait for tone and run corresponding script
menu ()
{
MENUPARSE=$(timeout 10s awk -W interactive '/DTMF/{gsub(/[\n\r]/," ");printf $2}' $MODEM)
if [ $MENUPARSE == "1" ]
then
echo -e 'AT+VTS="1,1,1"\n' > $MODEM && goodbye && exec $MENU1 &
elif [ $MENUPARSE == "2" ]
then
echo -e 'AT+VTS="2,2,2"\n' > $MODEM && goodbye && exec $MENU2 &
elif [ $MENUPARSE == "3" ]
then
echo -e 'AT+VTS="3,3,3"\n' > $MODEM && goodbye && exec $MENU3 &
else
goodbye
fi
}
###START###
initialize
answer
#allow at least 10 seconds for user to enter code
if [ $(date +%S) -ge "50" ]
then
sleep 10s
codecheck && returnsuccess && menu || returnfailure
elif [ $(date +%S) -ge "20" ] && [ $(date +%S) -le "30" ]
then
sleep 10s
codecheck && returnsuccess && menu || returnfailure
else
codecheck && returnsuccess && menu || returnfailure
fi
sleep 2s
goodbye
exit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment