From 613cd6bae8ede03ec41e1c13fe3ebfc51498e3dd Mon Sep 17 00:00:00 2001 From: Christian Zeitnitz Date: Wed, 19 May 2021 21:04:31 +0200 Subject: [PATCH 1/6] Add Huawei Hilink API Cleanup mobile data scripts --- config/client_config/huawei_hilink_api.sh | 482 ++++++++++++++++++++ config/client_config/info_huawei.sh | 58 +-- config/client_config/info_huawei_hilink.sh | 94 ++-- config/client_config/onoff_huawei_hilink.sh | 109 +---- 4 files changed, 582 insertions(+), 161 deletions(-) create mode 100644 config/client_config/huawei_hilink_api.sh diff --git a/config/client_config/huawei_hilink_api.sh b/config/client_config/huawei_hilink_api.sh new file mode 100644 index 00000000..c4402a6e --- /dev/null +++ b/config/client_config/huawei_hilink_api.sh @@ -0,0 +1,482 @@ +#!/bin/bash +# +# Huawei Hilink API +# ================= +# - communication with Hilink devices via HTTP +# - send a standard http request with a xml formatted string to the device (default IP 192.169.8.1) +# - Howto: +# o "source" this script in your own script from the command line +# o if host ip/name differs, set "host=192.168.178.1" before calling any function +# o if the device is locked by a password, set user="admin"; pw="1234secret" +# _login is called automaticallcall +# Password types 3 and 4 are supported +# o if the SIM is requiring a PIN, set "pin=1234" +# o connect device to network: _switchMobileData ON ( or 1 ) +# o disconnect device: _switchMobileData OFF ( or 0 ) +# o get informations about the device: _getDeviceInformation and _getStatus and _getNetProvider +# all functions return XML formatted data in $response. +# o Check if device is connected: "if _isConnected; then .... fi" +# o $response can be parsed by calling _valueFromResponse +# e.g "_valueFromResponse msisdn" to get the phone number after a call to _getDeviceInformation +# +# +# Usage of functions +# - call the function with parameters (if required) +# - return code: 0 - success; 1 - failed +# - $status: status information (OK, ERROR) +# - $response: xml response to be parsed for the required information +# +# +# required software: curl, base64, sha256sum, sed +# +# +# zbchristian 2021 +# + +# Initialization procedure +# ======================== +# +# host=$host_default # ip address of device +# user="admin" # user name if locked (default admin) +# pw="1234Secret" # password if locked +# pin="1234" # PIN of SIM +# _initHilinkAPI # initialize the API +# +# Termination +# =========== +# cleanup the API before quitting the shell +# _closeHilinkAPI (optional: add parameter "save" to save the session/token data for subsequent calls. Valid for a few minutes.) + +host_default="192.168.8.1" +save_file="/tmp/hilink_api_saved.dat" +save_age=60 +header_file="/tmp/hilink_login_hdr.txt" + +# initialize +function _initHilinkAPI() { + if [ -z "$host" ]; then host=$host_default; fi + if ! _hostReachable; then return 1; fi + if [ -f $save_file ]; then # found file with saved data + _getSavedData + age=$(( $(date +%s) - $(stat $save_file -c %Y) )) + if [[ $age -gt $save_age ]]; then + rm -f $save_file + _logout + _sessToken + fi + fi + if [ -z "$sessID" ] || [ -z "$token" ]; then _sessToken; fi + _login + return $? +} + +function _getSavedData() { + if [ -f $save_file ]; then # restore saved session data + dat=$(cat $save_file) + sessID=$(echo "$dat" | sed -nr 's/sessionid: ([a-z0-9]*)/\1/ip') + token=$(echo "$dat" | sed -nr 's/token: ([a-z0-9]*)/\1/ip') + tokenlist=( $(echo "$dat" | sed -nr 's/tokenlist: ([a-z0-9 ]*)/\1/ip') ) + fi +} + +# Cleanup +# parameter: "save" - will store sessionid and tokens in file +function _closeHilinkAPI() { + if [ -z "$host" ]; then host=$host_default; fi + if ! _hostReachable; then return 1; fi + rm -f $save_file + [ ! -z "$1" ] && opt="${1,,}" + if [ ! -z "$opt" ] && [ "$opt" = "save" ]; then + echo "sessionid: $sessID" > $save_file + echo "token: $token" >> $save_file + echo "tokenlist: ${tokenlist[@]}" >> $save_file + fi + _logout + tokenlist="" + sessID="" + token="" + return 0 +} + +# get status (connection status, DNS, ) +# parameter: none +function _getStatus() { + if _login; then + if _sendRequest "api/monitoring/status"; then + if [ ! -z "$1" ]; then _valueFromResponse "$1"; fi + fi + return $? + fi + return 1 +} + +function _isConnected() { + conn=$(_getStatus "connectionstatus") + status="NO" + if [ ! -z "$conn" ] && [ $conn -eq 901 ]; then + status="YES" + return 0 + fi + return 1 +} + +# get device information (device name, imei, imsi, msisdn-phone number, MAC, WAN IP ...) +# parameter: name of parameter to return +function _getDeviceInformation() { + if _login; then + if _sendRequest "api/device/information"; then + if [ ! -z "$1" ]; then _valueFromResponse "$1"; fi + fi + return $? + fi + return 1 +} + +# get net provider information +# parameter: name of parameter to return +function _getNetProvider() { + if _login; then + if _sendRequest "api/net/current-plmn"; then + if [ ! -z "$1" ]; then _valueFromResponse "$1"; fi + fi + return $? + fi + return 1 +} + +# get signal level +# parameter: name of parameter to return +function _getSignal() { + if _login; then + if _sendRequest "api/device/signal"; then + if [ ! -z "$1" ]; then _valueFromResponse "$1"; fi + fi + return $? + fi + return 1 +} + +function _getAllInformations() { + if _getDeviceInformation; then _keyValuePairs; fi + if _getSignal; then _keyValuePairs; fi + if _getNetProvider; then _keyValuePairs; fi +} + +# get status of mobile data connection +# parameter: none +function _getMobileDataStatus() { + if _login; then + if _sendRequest "api/dialup/mobile-dataswitch"; then + status=$(_valueFromResponse "dataswitch") + if [ $? -eq 0 ] && [ ! -z "$status" ]; then echo "$status"; fi + fi + return $? + fi + return 1 +} + + +# PIN of SIM can be passed either as $pin, or as parameter +# parameter: PIN number of SIM card +function _enableSIM() { +#SimState: +#255 - no SIM, +#256 - error CPIN, +#257 - ready, +#258 - PIN disabled, +#259 - check PIN, +#260 - PIN required, +#261 - PUK required + if [ ! -z "$1" ]; then pin="$1"; fi + if ! _login; then return 1; fi + if _sendRequest "api/pin/status"; then + simstate=`echo $response | sed -rn 's/.*([0-9]*)<\/simstate>.*/\1/pi'` + if [[ $simstate -eq 257 ]]; then status="SIM ready"; return 0; fi + if [[ $simstate -eq 260 ]]; then + status="PIN required" + if [ ! -z "$pin" ]; then _setPIN "$pin"; fi + return $? + fi + if [[ $simstate -eq 255 ]]; then status="NO SIM"; return 1; fi + fi + return 1 +} + +# obtain session and verification token - stored in vars $sessID and $token +# parameter: none +function _sessToken() { + tokenlist="" + token="" + sessID="" + response=$(curl -s http://$host/api/webserver/SesTokInfo -m 5 2> /dev/null) + if [ -z "$response" ]; then echo "No access to device at $host"; return 1; fi + status=$(echo "$response" | sed -nr 's/.*([0-9]*)<\/code>.*/\1/ip') + if [ -z "$status" ]; then + token=`echo $response | sed -r 's/.*(.*)<\/TokInfo>.*/\1/'` + sessID=`echo $response | sed -r 's/.*(.*)<\/SesInfo>.*/\1/'` + if [ ! -z "$sessID" ] && [ ! -z "$token" ]; then + sessID="SessionID=$sessID" + return 0 + fi + fi + return 1 +} + +# unlock device (if locked) with user name and password +# requires stored user="admin"; pw="1234secret";host=$host_default +# parameter: none +function _login() { + if _loginState; then return 0; fi # login not required, or already done + _sessToken + # get password type + if ! _sendRequest "api/user/state-login"; then return 1; fi + pwtype=$(echo "$response" | sed -rn 's/.*([0-9])<\/password_type>.*/\1/pi') + if [ -z "$pwtype" ];then pwtype=4; fi # fallback is type 4 + if [[ ! -z "$user" ]] && [[ ! -z "$pw" ]]; then + # password encoding + # type 3 : base64(pw) encoded + # type 4 : base64(sha256sum(user + base64(sha256sum(pw)) + token)) + pwtype3=$(echo -n "$pw" | base64 --wrap=0) + hashedpw=$(echo -n "$pw" | sha256sum -b | sed -nr 's/^([0-9a-z]*).*$/\1/ip' ) + hashedpw=$(echo -n "$hashedpw" | base64 --wrap=0) + pwtype4=$(echo -n "$user$hashedpw$token" | sha256sum -b | sed -nr 's/^([0-9a-z]*).*$/\1/ip' ) + encpw=$(echo -n "$pwtype4" | base64 --wrap=0) + if [ $pwtype -ne 4 ]; then encpw=$pwtype3; fi + xmldata="$user$encpw$pwtype" + xtraopts="--dump-header $header_file" + rm -f $header_file + _sendRequest "api/user/login" + if [ ! -z "$status" ] && [ "$status" = "OK" ]; then + # store the list of 30 tokens. Each token is valid for a single request + tokenlist=( $(cat $header_file | sed -rn 's/^__RequestVerificationToken:\s*([0-9a-z#]*).*$/\1/pi' | sed 's/#/ /g') ) + _getToken + sessID=$(cat $header_file | grep -ioP 'SessionID=([a-z0-9]*)') + if [ ! -z "$sessID" ] && [ ! -z "$token" ]; then + return 0 + fi + fi + fi + return 1 +} + +# logout of hilink device +# parameter: none +function _logout() { + if _loginState; then + xmldata="1" + if _sendRequest "api/user/logout"; then + tokenlist="" + sessID="" + token="" + login_enabled="" + fi + return $? + fi + return 1 +} + +# parameter: none +function _loginState() { + status="OK" + if [ -z "$login_enabled" ]; then _checkLoginEnabled; fi + if [ $login_enabled -eq 1 ]; then return 0; fi # login is disabled + _sendRequest "api/user/state-login" + state=`echo "$response" | sed -rn 's/.*(.*)<\/state>.*/\1/pi'` + if [ ! -z "$state" ] && [ $state -eq 0 ]; then # already logged in + return 0 + fi + return 1 +} + +function _checkLoginEnabled() { + if _sendRequest "api/user/hilink_login"; then + login_enabled=0 + state=$(echo $response | sed -rn 's/.*(.*)<\/hilink_login>.*/\1/pi') + if [ ! -z "$state" ] && [ $state -eq 0 ]; then # no login enabled + login_enabled=1 + fi + else + login_enabled="" + fi +} + +# switch mobile data on/off 1/0 +# if SIM is locked, $pin has to be set +# parameter: state - ON/OFF or 1/0 +function _switchMobileData() { + if [ -z "$1" ]; then return 1; fi + _login + mode="${1,,}" + [ "$mode" = "on" ] && mode=1 + [ "$mode" = "off" ] && mode=0 + if [[ $mode -ge 0 ]]; then + if _enableSIM "$pin"; then + xmldata="$mode" + _sendRequest "api/dialup/mobile-dataswitch" + return $? + fi + fi + return 1 +} + +# parameter: PIN of SIM card +function _setPIN() { + if [ -z "$1" ]; then return 1; fi + pin="$1" + xmldata="0$pin" + _sendRequest "api/pin/operate" + return $? +} + +# Send request to host at http://$host/$apiurl +# data in $xmldata and options in $xtraopts +# parameter: apiurl (e.g. "api/user/login") +function _sendRequest() { + status="ERROR" + if [ -z "$1" ]; then return 1; fi + apiurl="$1" + ret=1 + if [ -z "$sessID" ] || [ -z "$token" ]; then _sessToken; fi + if [ -z "$xmldata" ];then + response=$(curl -s http://$host/$apiurl -m 10 \ + -H "Cookie: $sessID") + else + response=$(curl -s -X POST http://$host/$apiurl -m 10 \ + -H "Content-Type: text/xml" \ + -H "Cookie: $sessID" \ + -H "__RequestVerificationToken: $token" \ + -d "$xmldata" $xtraopts 2> /dev/null) + _getToken + fi + if [ ! -z "$response" ];then + response=$(echo $response | tr -d '\012\015') # delete newline chars + status=$(echo "$response" | sed -nr 's/.*([0-9]*)<\/code>.*/\1/ip') # check for error code + if [ -z "$status" ]; then + status="OK" + response=$(echo "$response" | sed -nr 's/.*(.*)<\/response>.*/\1/ip') + [ -z "$response" ] && response="none" + ret=0 + else + status="ERROR $status" + fi + else + status="ERROR" + fi + if [[ "$status" =~ ERROR ]]; then _handleError; fi + xtraopts="" + xmldata="" + return $ret +} + +# handle the list of tokens available after login +# parameter: none +function _getToken() { + if [ ! -z "$tokenlist" ] && [ ${#tokenlist[@]} -gt 0 ]; then + token=${tokenlist[0]} # get first token in list + tokenlist=("${tokenlist[@]:1}") # remove used token from list + if [ ${#tokenlist[@]} -eq 0 ]; then + _logout # use the last token to logout + fi + else + _sessToken # old token has been used - need new session + fi +} + +# Analyse $status for error code +# return error text in $status +function _handleError() { + txt=$(_getErrorText) + if [ -z "$code" ]; then return 1; fi + ret=0 + case "$code" in + 101|108003|108007) + ret=1 + status="$txt" + ;; + 108001|108002|108006) + ret=1 + status="$txt" + ;; + 125001|125002|125003) + _sessToken + ret=0 + ;; + *) + ;; + esac + return "$ret" +} + +declare -A err_hilink_api +err_hilink_api[101]="Unable to get session ID/token" +err_hilink_api[108001]="Invalid username/password" +err_hilink_api[108002]=${errors[108001]} +err_hilink_api[108006]=${errors[108001]} +err_hilink_api[108003]="User already logged in - need to wait a bit" +err_hilink_api[108007]="Too many login attempts - need to wait a bit" +err_hilink_api[125001]="Invalid session/request token" +err_hilink_api[125002]=${errors[125001]} +err_hilink_api[125003]=${errors[125001]} + +# check error and return error text +# status passsed in $status, or $1 +function _getErrorText() { + err="$status" + code="0" + if [ ! -z "$1" ]; then err="$1"; fi + if [ -z "$err" ]; then return 1; fi + errortext="$err" + if [[ "$err" =~ ERROR\ *([0-9]*) ]] && [ ! -z "${BASH_REMATCH[1]}" ]; then + code=${BASH_REMATCH[1]} + if [ ! -z "$code" ] && [ ! -z "${err_hilink_api[$code]}" ]; then + errortext="${err_hilink_api[$code]}" + fi + fi + echo $errortext + return 0 +} + +function _hostReachable() { + avail=`timeout 0.5 ping -c 1 $host | sed -rn 's/.*time=.*/1/p'` + if [ -z "$avail" ]; then return 1; fi + return 0; +} + +# helper function to parse $response (xml format) for a value +# call another function first! +# parameter: tag-name +function _valueFromResponse() { + if [ -z "$response" ] || [ -z "$1" ]; then return 1; fi + par="$1" + value=$(echo $response | sed -rn 's/.*<'$par'>(.*)<\/'$par'>.*/\1/pi') + if [ -z "$value" ]; then return 1; fi + echo "$value" + return 0 +} + +# list all keys of the current xml response +function _keysFromResponse() { + if [ -z "$response" ]; then return 1; fi + echo $response | grep -oiP "(?<=<)[a-z_-]*(?=>)" + return 0 +} + +# return all key=value pairs of the current xml response +function _keyValuePairs() { + if [ -z "$response" ]; then return 1; fi + echo $response | sed -n 's/<\([^>]*\)>\(.*\)<\/\1>[^<]*/\1=\"\2\"\n/gpi' + return 0 +} + +host=$host_default +user="admin" +pw="" +token="" +tokenlist="" +sessID="" +xmldata="" +xtraopts="" +response="" +status="" +pwtype=-1 + diff --git a/config/client_config/info_huawei.sh b/config/client_config/info_huawei.sh index bcdf8e37..475767fe 100644 --- a/config/client_config/info_huawei.sh +++ b/config/client_config/info_huawei.sh @@ -12,43 +12,43 @@ # zbchristian 2020 # opt="device" -if [ ! -z $1 ]; then opt=${1,,}; fi +if [ ! -z "$1" ]; then opt=${1,,}; fi type="hilink" -if [ ! -z $2 ]; then type=${2,,}; fi +if [ ! -z "$2" ]; then type=${2,,}; fi -path=`dirname $0` -if [[ $type == "hilink" ]]; then +path=$(dirname "$0") +if [ "$type" = "hilink" ]; then connect="192.168.8.1" - if [ ! -z $3 ]; then connect=$3; fi + if [ ! -z "$3" ]; then connect=$3; fi script="$path/info_huawei_hilink.sh" else connect="/dev/ttyUSB2" - if [ ! -z $3 ]; then connect=$3; fi + if [ ! -z "$3" ]; then connect=$3; fi script="$path/info_huawei_modem.sh" fi -res=`$script $opt $connect` +res=$($script $opt $connect) # some results require special treatment case $opt in # manufacturer) -# if [[ $res == "none" ]]; then res="Huawei"; fi +# if [ "$res" = "none" ]; then res="Huawei"; fi # ;; # device) -# if [[ ! $res == "none" ]]; then res="Huawei $res"; +# if [ ! "$res" = "none" ]; then res="Huawei $res"; # else res="Huawei"; fi # ;; mode) - if [[ ! $res == "none" ]]; then - if [[ $type == "hilink" ]]; then - if [[ $res == "LTE" ]]; then res="4G" - elif [[ $res == "WCDMA" ]]; then res="3G"; + if [ ! "$res" = "none" ]; then + if [ "$type" = "hilink" ]; then + if [ "$res" = "LTE" ]; then res="4G" + elif [ "$res" = "WCDMA" ]]; then res="3G"; else res="2G"; fi else - if [[ $res == 7 ]]; then res="4G" - elif [[ $res < 7 ]] && [[ $res > 2 ]] ; then res="3G"; + if [ $res -eq 7 ]; then res="4G" + elif [ $res -lt 7 ] && [ $res -gt 2 ] ; then res="3G"; else res="2G"; fi fi fi @@ -56,45 +56,45 @@ case $opt in signal) # return signal strength/quality in % - if [[ $type == "hilink" ]]; then + if [ "$type" = "hilink" ]; then # signal request tries to get RSRQ value # try to get RSRQ (4G), EC/IO (3G) or RSSI (2G) value - if [[ $res == "none" ]]; then res=`$script "ecio"`; fi - if [[ ! $res == "none" ]]; then + if [ "$res" = "none" ]; then res=$($script "ecio"); fi + if [ ! "$res" = "none" ]; then # for rsrq and ecio assume: -3dB (100%) downto -20dB (0%) qual=${res//dB/} if [[ ! "$qual" =~ [-0-9\.]* ]]; then qual=-100; fi qual=$(bc <<< "scale=0;res=$qual-0.5;res/1") # just round to next integer - if [[ $qual -le -20 ]]; then qual=0; - elif [[ $qual -ge -3 ]]; then qual=100; + if [ $qual -le -20 ]; then qual=0; + elif [ $qual -ge -3 ]; then qual=100; else qual=$(bc <<< "scale=0;res=100.0/17.0*$qual+2000.0/17.0;res/1"); fi else # try rssi: >-70dBm (100%) downto -100dBm (0%) - res=`$script "rssi"`; - if [[ ! $res == "none" ]]; then - if [[ $res =~ [-0-9\.]* ]]; then res="-120 dBm"; fi + res=$($script "rssi"); + if [ ! "$res" = "none" ]; then + if [[ ! $res =~ [-0-9\.]* ]]; then res="-120 dBm"; fi qual=${res//dBm/} qual=$(bc <<< "scale=0;res=$qual+0.5;res/1") # just round to next integer - if [[ $qual -le -110 ]]; then qual=0; - elif [[ $qual -ge -70 ]]; then qual=100; + if [ $qual -le -110 ]; then qual=0; + elif [ $qual -ge -70 ]; then qual=100; else qual=$(bc <<< "scale=0;res=2.5*$qual+275;res/1"); fi fi fi else # modem returns RSSI as number 0-31 - 0 = -113dB (0%), 1 = -111dB, 31 = >=51dB (100%) qual=$(bc <<< "scale=0;res=$res*3.5+0.5;res/1") - if [[ $qual -gt 100 ]]; then res=100; fi + if [ $qual -gt 100 ]; then res=100; fi fi - if [[ ! "$res" == "none" ]]; then res="$res (${qual}%)"; fi + if [ ! "$res" = "none" ]; then res="$res (${qual}%)"; fi ;; - + operator) # check if operator/network is just a 5 digit number -> extract network name from table if [[ $res =~ ^[0-9]{5}$ ]]; then mcc=${res:0:3} mnc=${res:3:2} op=$(cat $path/mcc-mnc-table.csv | sed -rn 's/^'$mcc'\,[0-9]*\,'$mnc'\,(.*\,){4}(.*)$/\2/p') - if [[ ! -z $op ]]; then res="$op ($res)"; fi + if [ ! -z "$op" ]; then res="$op ($res)"; fi fi ;; diff --git a/config/client_config/info_huawei_hilink.sh b/config/client_config/info_huawei_hilink.sh index 0bae3ecf..d3b20541 100644 --- a/config/client_config/info_huawei_hilink.sh +++ b/config/client_config/info_huawei_hilink.sh @@ -1,49 +1,75 @@ #!/bin/bash -# Infosramtion about HUAWEI hilink (router) modem -# ----------------------------------------------- +# Information about HUAWEI hilink (router) modem +# ---------------------------------------------- # get info about the device and signal # parameter: $1 - see opts list below # $2 - host ip address for API calls (optional) # returns the value of the parameter, or "none" if not found or empty # +# All device informations are buffered for 5 secs to speed up subsequent calls +# # zbchristian 2020 -opts=("device" "imei" "imsi" "telnumber" "ipaddress" "mode" "signal" "rssi" "rsrq" "rsrp" "sinr" "ecio" "operator") - -# xml tags to extract information from -tags=("devicename" "imei" "imsi" "msisdn" "wanipaddress" "workmode" "rsrq" "rssi" "rsrq" "rsrp" "sinr" "ecio" "fullname") -iurl=( 0 0 0 0 0 0 1 1 1 1 1 1 2) -# api urls -urls=("api/device/information" "api/device/signal" "api/net/current-plmn") +if [ -z "$1" ]; then echo "none"; exit; fi host="192.168.8.1" -if [ ! -z $2 ]; then host=$2; fi -avail=`timeout 0.5 ping -c 1 $host | sed -rn 's/.*time=.*/1/p'` -if [[ -z $avail ]]; then echo "none"; exit; fi +status="no option given" +if [ ! -z "$2" ]; then host="$2"; fi -idx=-1 -opt=${opts[0]} -if [ ! -z $1 ]; then opt=$1; fi +opt="${1,,}" +result="none" +if [ "$opt" = "connected" ]; then + source /usr/local/sbin/huawei_hilink_api.sh + if ! _initHilinkAPI; then echo "none"; exit; fi + result=$(_getMobileDataStatus) + _closeHilinkAPI +else + info_file="/tmp/huawei_infos_$host.dat" + if [ -f "$info_file" ]; then + age=$(( $(date +%s) - $(stat $info_file -c %Y) )) + if [[ $age -gt 5 ]]; then rm -f $info_file; fi + fi -for i in "${!opts[@]}"; do - if [[ ${opts[$i]} == $opt ]]; then idx=$i; fi -done -if [[ $idx == -1 ]];then echo "none"; exit; fi + if [ -f "$info_file" ]; then + infos=$(cat $info_file) + else + source /usr/local/sbin/huawei_hilink_api.sh + if ! _initHilinkAPI; then echo "none"; exit; fi + infos=$(_getAllInformations) + _closeHilinkAPI + if [ ! -z "$infos" ]; then echo "$infos" > /tmp/huawei_infos_$host.dat; fi + fi -par=${tags[$idx]} -iu=${iurl[$idx]} - -url="http://$host/${urls[$iu]}" -# echo "Found option $opt at index $idx - tag $par url $url " - - -info="" -if [ ! -z $url ]; then info=`curl -s $url`; fi - -result=`echo $info | sed -rn 's/.*<'"$par"'>(.*)<\/'"$par"'>.*/\1/pi'` - -if [ -z "$result" ]; then result="none"; fi - -echo $result + case "$opt" in + device|devicename) + key="devicename" + ;; + ipaddress|wanipaddress) + key="wanipaddress" + ;; + mode) + key="workmode" + ;; + telnumber) + key="msisdn" + ;; + imei|imsi|rssi|rsrq|rsrp|sinr|ecio) + key="$opt" + ;; + signal) + key="rsrq" + ;; + operator|fullname) + key="fullname" + ;; + *) + key="" + ;; + esac + if [ -z "$key" ]; then result="none"; fi + result=$(echo "$infos" | sed -rn 's/'$key'=\"([^ \s]*)\"/\1/ip') + if [ -z "$result" ]; then result="none"; fi +fi +echo -n "$result" diff --git a/config/client_config/onoff_huawei_hilink.sh b/config/client_config/onoff_huawei_hilink.sh index 18b1a016..65587d01 100644 --- a/config/client_config/onoff_huawei_hilink.sh +++ b/config/client_config/onoff_huawei_hilink.sh @@ -8,89 +8,12 @@ # -h 192.168.8.1 - host ip address # -p 1234 - PIN of SIM card # -c 0/1 - connect - set datamode off/on -# required software: curl, base64 +# required software: curl, base64, sha256sum # -# TODO: implement login into API - currently the login has to be disabled! -# -# zbchristian 2020 +# zbchristian 2021 -# obtain session and verification token -function _SessToken() { - SesTok=`sudo curl -s http://$host/api/webserver/SesTokInfo -m 5 2> /dev/null` - if [ -z "$SesTok" ]; then exit; fi - - token=`echo $SesTok | sed -r 's/.*(.*)<\/TokInfo>.*/\1/'` - sesinfo=`echo $SesTok | sed -r 's/.*(.*)<\/SesInfo>.*/\1/'` -} - -function _login() { -# ----------------------- THIS DOES NOT WORK ------------------------------------------ -# login to web api - _SessToken - - if [[ ! -z $user ]] && [[ ! -z $pw ]]; then - # password encoding - # type 3 : base64(pw) encoded - # type 4 : base64(sha256sum(user + base64(sha256sum(pw)) + token)) - pwtype3=$(echo $pw | base64 --wrap=0) - hashedpw=$(echo -n "$pw" | sha256sum -b | cut -d " " -f1 | base64 --wrap=0) - pwtype4=$(echo -n "$user$hashedpw$token" | sha256sum -b | cut -d " " -f1 | base64 --wrap=0) - apiurl="api/user/login" - xmldata="$user$pwtype44" -# xmldata="$user$pwtype33" - xtraopts="--dump-header /tmp/hilink_login_hdr.txt" - _sendRequest - # get updated session cookie - sesinfo=$(grep "SessionID=" /tmp/hilink_login_hdr.txt | cut -d ':' -f2 | cut -d ';' -f1) - token=$(grep "__RequestVerificationTokenone" /tmp/hilink_login_hdr.txt | cut -d ':' -f2) -echo "Login Cookie $sesinfo" -echo "Login Token $token" - fi -# ------------------------------ DO NOT USE THE LOGIN CODE ---------------------------------- -} - -function _switchMobileData() { -# switch mobile data on/off - if [[ $datamode -ge 0 ]]; then - xmldata="$datamode" - apiurl="api/dialup/mobile-dataswitch" - _sendRequest - fi -} - -function _enableSIM() { -#SimState: -#255 - no SIM, -#256 - error CPIN, -#257 - ready, -#258 - PIN disabled, -#259 - check PIN, -#260 - PIN required, -#261 - PUK required - status=`curl -s http://$host/api/pin/status -m 10` - state=`echo $status | sed -rn 's/.*(.*)<\/simstate>.*/\1/pi'` - if [[ $state -eq 257 ]]; then echo "Hilink: SIM ready"|systemd-cat; return; fi - if [[ $state -eq 260 ]]; then echo "Hilink: Set PIN"|systemd-cat; _setPIN; fi -} - -function _setPIN() { - if [[ ! -z $pin ]]; then - xmldata="0$pin" - apiurl="api/pin/operate" - _sendRequest - fi -} - -function _sendRequest() { - result="" - if [[ -z $xmldata ]]; then return; fi - result=`curl -s http://$host/$apiurl -m 10 \ - -H "Content-Type: application/xml" \ - -H "Cookie: $sesinfo" \ - -H "__RequestVerificationToken: $token" \ - -d "$xmldata" $xtraopts 2> /dev/null` - xtraopts="" -} +# include the hilink API +source /usr/local/sbin/huawei_hilink_api.sh # handle options @@ -98,8 +21,8 @@ host="192.168.8.1" pin="" user="" pw="" -datamode=-1 -connect=-1 +datamode="" + while getopts ":c:h:l:m:p:" opt; do case $opt in h) if [[ $OPTARG =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then host="$OPTARG"; fi @@ -109,7 +32,7 @@ while getopts ":c:h:l:m:p:" opt; do l) if [[ $OPTARG =~ ^[0-9a-zA-Z]*:.*$ ]]; then user=$(echo "$OPTARG" | cut -d':' -f1); pw=$(echo "$OPTARG" | cut -d':' -f2); - fi + fi ;; c) if [[ $OPTARG == "1" ]]; then datamode=1; else datamode=0; fi ;; @@ -118,21 +41,11 @@ done echo "Hilink: switch device at $host to mode $datamode" | systemd-cat -# check if device is reachable -avail=`timeout 0.5 ping -c 1 $host | sed -rn 's/.*time=.*/1/p'` -if [[ -z $avail ]]; then - echo "Hilink: no link to host" | systemd-cat - exit -fi +status="usage: -c 1/0 to disconnect/disconnect" +if [ -z "$datamode" ] || [ ! _initHilinkAPI ]; then echo "Hilink: failed - return status: $status"; exit; fi -token="" -Sesinfo="" -xmldata="" -xtraopts="" -result="" +if ! _switchMobileData "$datamode"; then echo "Hilink: could not switch the data mode on/off . Error: ";_getErrorText; fi -_SessToken -_enableSIM -_switchMobileData # check and perform enable/disable mobile data connection +if ! _closeHilinkAPI; then echo -n "Hilink: failed - return status: $status . Error: ";_getErrorText; fi From b99752c4cd9931fe64d42d705068b796d1553900 Mon Sep 17 00:00:00 2001 From: Christian Zeitnitz Date: Fri, 21 May 2021 14:57:14 +0200 Subject: [PATCH 2/6] Implement login for Hilink devices --- ajax/networking/save_net_dev_config.php | 28 ++-- config/client_config/info_huawei.sh | 11 +- config/client_config/info_huawei_hilink.sh | 136 +++++++++++--------- config/client_config/onoff_huawei_hilink.sh | 46 +++---- config/config.php | 1 + includes/get_clients.php | 31 +++-- templates/networking.php | 2 +- 7 files changed, 132 insertions(+), 123 deletions(-) diff --git a/ajax/networking/save_net_dev_config.php b/ajax/networking/save_net_dev_config.php index be2c04dd..a95baa50 100644 --- a/ajax/networking/save_net_dev_config.php +++ b/ajax/networking/save_net_dev_config.php @@ -14,19 +14,26 @@ require_once '../../includes/functions.php'; if (isset($_POST['interface'])) { $int = $_POST['interface']; $cfg = []; - $file = $int.".ini"; + $file = $RASPI_MOBILEDATA_CONFIG; $cfgfile="/etc/wvdial.conf"; if ( $int == "mobiledata") { $cfg['pin'] = $_POST["pin-mobile"]; $cfg['apn'] = $_POST["apn-mobile"]; $cfg['apn_user'] = $_POST["apn-user-mobile"]; $cfg['apn_pw'] = $_POST["apn-pw-mobile"]; + $cfg['router_user'] = $cfg['apn_user'] ; + $cfg['router_pw'] = $cfg['apn_pw'] ; if (file_exists($cfgfile)) { if($cfg["pin"] !== "") exec('sudo /bin/sed -i "s/CPIN=\".*\"/CPIN=\"'.$cfg["pin"].'\"/gi" '.$cfgfile); if($cfg["apn"] !== "") exec('sudo /bin/sed -i "s/\"IP\"\,\".*\"/\"IP\"\,\"'.$cfg["apn"].'\"/gi" '.$cfgfile); if($cfg["apn_user"] !== "") exec('sudo /bin/sed -i "s/^username = .*$/Username = '.$cfg["apn_user"].'/gi" '.$cfgfile); if($cfg["apn_pw"] !== "") exec('sudo /bin/sed -i "s/^password = .*$/Password = '.$cfg["apn_pw"].'/gi" '.$cfgfile); } + if (write_php_ini($cfg, RASPI_MOBILEDATA_CONFIG)) { + $jsonData = ['return'=>0,'output'=>['Successfully saved mobile data settings']]; + } else { + $jsonData = ['return'=>1,'output'=>['Error saving mobile data settings']]; + } } else if ( preg_match("/netdevices/",$int)) { if(!isset($_POST['opts']) ) { $jsonData = ['return'=>0,'output'=>['No valid data to add/delete udev rule ']]; @@ -75,26 +82,9 @@ if (isset($_POST['interface'])) { if (!empty($rule)) exec('echo \''.$rule.'\' | sudo /usr/bin/tee -a '.$udevfile); } $jsonData = ['return'=>0,'output'=>['Settings changed for device '.$dev. '
Changes will only be in effect after reconnecting the device' ] ]; - echo json_encode($jsonData); - return; } } else { - $ip = $_POST[$int.'-ipaddress']; - $netmask = mask2cidr($_POST[$int.'-netmask']); - $dns1 = $_POST[$int.'-dnssvr']; - $dns2 = $_POST[$int.'-dnssvralt']; - - $cfg['interface'] = $int; - $cfg['routers'] = $_POST[$int.'-gateway']; - $cfg['ip_address'] = $ip."/".$netmask; - $cfg['domain_name_server'] = $dns1." ".$dns2; - $cfg['static'] = $_POST[$int.'-static']; - $cfg['failover'] = $_POST[$int.'-failover']; - } - if (write_php_ini($cfg, RASPI_CONFIG.'/networking/'.$file)) { - $jsonData = ['return'=>0,'output'=>['Successfully Updated Network Configuration']]; - } else { - $jsonData = ['return'=>1,'output'=>['Error saving network configuration to file']]; + $jsonData = ['return'=>1,'output'=>['Unknown network configuration']]; } } else { $jsonData = ['return'=>2,'output'=>'Unable to detect interface']; diff --git a/config/client_config/info_huawei.sh b/config/client_config/info_huawei.sh index 475767fe..540ede98 100644 --- a/config/client_config/info_huawei.sh +++ b/config/client_config/info_huawei.sh @@ -5,28 +5,31 @@ # $2 : (optional) type - hilink or modem (default: hilink) # $3 : (optional) for hilink: ip address of the device (default: 192.168.8.1) # for modem: tty interface for communication (default: /dev/ttypUSB2) +# $4 : more options can be added for Hilink devices ('-u user -P password -p pin'). These are passed to the corresponding script # # requires: bc # calls the scripts info_huawei_hilink.sh and info_huawei_modem.sh (same path as this script) # # zbchristian 2020 # +path=$(dirname "$0") opt="device" if [ ! -z "$1" ]; then opt=${1,,}; fi type="hilink" if [ ! -z "$2" ]; then type=${2,,}; fi -path=$(dirname "$0") +parms="" if [ "$type" = "hilink" ]; then - connect="192.168.8.1" - if [ ! -z "$3" ]; then connect=$3; fi + connect="-h 192.168.8.1" + if [ ! -z "$3" ]; then connect="-h $3"; fi + if [ ! -z "$4" ]; then parms="$4"; fi script="$path/info_huawei_hilink.sh" else connect="/dev/ttyUSB2" if [ ! -z "$3" ]; then connect=$3; fi script="$path/info_huawei_modem.sh" fi -res=$($script $opt $connect) +res=$($script $opt $connect $parms) # some results require special treatment case $opt in diff --git a/config/client_config/info_huawei_hilink.sh b/config/client_config/info_huawei_hilink.sh index d3b20541..345c1fe5 100644 --- a/config/client_config/info_huawei_hilink.sh +++ b/config/client_config/info_huawei_hilink.sh @@ -1,75 +1,93 @@ #!/bin/bash -# Information about HUAWEI hilink (router) modem -# ---------------------------------------------- +# Information about HUAWEI hilink +# ------------------------------- # get info about the device and signal -# parameter: $1 - see opts list below -# $2 - host ip address for API calls (optional) +# parameter: $1 - "connected", "device", "ipaddress", "mode", "signal" (see case statement below) +# -u,--user - username +# -P,--password - password +# -p,--pin - SIM pin +# -h,--host - host ip address for API calls (optional) # returns the value of the parameter, or "none" if not found or empty # # All device informations are buffered for 5 secs to speed up subsequent calls # -# zbchristian 2020 +# zbchristian 2021 + +function _setAPIParams() { + if [ ! -z "$hostip" ]; then host="$hostip"; fi + if [ ! -z "$username" ]; then user="$username"; fi + if [ ! -z "$password" ]; then pw="$password"; fi + if [ ! -z "$simpin" ]; then pin="$simpin"; fi +} if [ -z "$1" ]; then echo "none"; exit; fi - -host="192.168.8.1" - -status="no option given" -if [ ! -z "$2" ]; then host="$2"; fi - opt="${1,,}" +shift +while [ -n "$1" ]; do + case "$1" in + -u|--user) username="$2"; shift ;; + -P|--password) password="$2"; shift ;; + -p|--pin) simpin="$2"; shift ;; + -h|--host) hostip="$2"; shift ;; + esac + shift +done + +status="no valid option given" result="none" if [ "$opt" = "connected" ]; then - source /usr/local/sbin/huawei_hilink_api.sh - if ! _initHilinkAPI; then echo "none"; exit; fi - result=$(_getMobileDataStatus) - _closeHilinkAPI -else - info_file="/tmp/huawei_infos_$host.dat" - if [ -f "$info_file" ]; then - age=$(( $(date +%s) - $(stat $info_file -c %Y) )) - if [[ $age -gt 5 ]]; then rm -f $info_file; fi - fi - - if [ -f "$info_file" ]; then - infos=$(cat $info_file) - else - source /usr/local/sbin/huawei_hilink_api.sh - if ! _initHilinkAPI; then echo "none"; exit; fi - infos=$(_getAllInformations) + source /usr/local/sbin/huawei_hilink_api.sh + if ! _initHilinkAPI; then echo "none"; exit; fi + _setAPIParams + result=$(_getMobileDataStatus) _closeHilinkAPI - if [ ! -z "$infos" ]; then echo "$infos" > /tmp/huawei_infos_$host.dat; fi - fi +else + info_file="/tmp/huawei_infos_$host.dat" + if [ -f "$info_file" ]; then + age=$(( $(date +%s) - $(stat $info_file -c %Y) )) + if [[ $age -gt 5 ]]; then rm -f $info_file; fi + fi - case "$opt" in - device|devicename) - key="devicename" - ;; - ipaddress|wanipaddress) - key="wanipaddress" - ;; - mode) - key="workmode" - ;; - telnumber) - key="msisdn" - ;; - imei|imsi|rssi|rsrq|rsrp|sinr|ecio) - key="$opt" - ;; - signal) - key="rsrq" - ;; - operator|fullname) - key="fullname" - ;; - *) - key="" - ;; - esac - if [ -z "$key" ]; then result="none"; fi - result=$(echo "$infos" | sed -rn 's/'$key'=\"([^ \s]*)\"/\1/ip') - if [ -z "$result" ]; then result="none"; fi + if [ -f "$info_file" ]; then + infos=$(cat $info_file) + else + source /usr/local/sbin/huawei_hilink_api.sh + if ! _initHilinkAPI; then echo "none"; exit; fi + _setAPIParams + infos=$(_getAllInformations) + _closeHilinkAPI + if [ ! -z "$infos" ]; then echo "$infos" > /tmp/huawei_infos_$host.dat; fi + fi + + case "$opt" in + device|devicename) + key="devicename" + ;; + ipaddress|wanipaddress) + key="wanipaddress" + ;; + mode) + key="workmode" + ;; + telnumber) + key="msisdn" + ;; + imei|imsi|rssi|rsrq|rsrp|sinr|ecio) + key="$opt" + ;; + signal) + key="rsrq" + ;; + operator|fullname) + key="fullname" + ;; + *) + key="" + ;; + esac + if [ -z "$key" ]; then result="none"; fi + result=$(echo "$infos" | sed -rn 's/'$key'=\"([^ \s]*)\"/\1/ip') + if [ -z "$result" ]; then result="none"; fi fi echo -n "$result" diff --git a/config/client_config/onoff_huawei_hilink.sh b/config/client_config/onoff_huawei_hilink.sh index 65587d01..2ee413d2 100644 --- a/config/client_config/onoff_huawei_hilink.sh +++ b/config/client_config/onoff_huawei_hilink.sh @@ -1,42 +1,30 @@ #!/bin/bash # connect/disconnect Huawei mobile data stick in Hilink mode (e.g. E3372h) # ======================================================================== -# - send xml formatted string via HTTP API to stick -# - Requires session and verification token, which is obtained by an API call # -# options: -l "user":"password" - login data - DOES NOT WORK YET -# -h 192.168.8.1 - host ip address -# -p 1234 - PIN of SIM card -# -c 0/1 - connect - set datamode off/on +# options: -u, --user - user name (default "admin") +# -P, --password - password +# -h, --host - host ip address (default 192.168.8.1) +# -p, --pin - PIN of SIM card +# -c, --connect - connect 0/1 to set datamode off/on +# # required software: curl, base64, sha256sum # # zbchristian 2021 -# include the hilink API +# include the hilink API (defaults: user=admin, host=192.168.8.1) source /usr/local/sbin/huawei_hilink_api.sh -# handle options - -host="192.168.8.1" -pin="" -user="" -pw="" datamode="" - -while getopts ":c:h:l:m:p:" opt; do - case $opt in - h) if [[ $OPTARG =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then host="$OPTARG"; fi - ;; - p) if [[ $OPTARG =~ ^[0-9]{4,8} ]]; then pin="$OPTARG"; fi - ;; - l) if [[ $OPTARG =~ ^[0-9a-zA-Z]*:.*$ ]]; then - user=$(echo "$OPTARG" | cut -d':' -f1); - pw=$(echo "$OPTARG" | cut -d':' -f2); - fi - ;; - c) if [[ $OPTARG == "1" ]]; then datamode=1; else datamode=0; fi - ;; - esac +while [ -n "$1" ]; do + case "$1" in + -u|--user) user="$2"; shift ;; + -P|--password) pw="$2"; shift ;; + -p|--pin) if [[ $2 =~ ^[0-9]{4,8} ]]; then pin="$2"; fi; shift ;; + -h|--host) host="$2"; shift ;; + -c|--connect) if [ "$2" = "1" ]; then datamode=1; else datamode=0; fi; shift ;; + esac + shift done echo "Hilink: switch device at $host to mode $datamode" | systemd-cat @@ -44,7 +32,7 @@ echo "Hilink: switch device at $host to mode $datamode" | systemd-cat status="usage: -c 1/0 to disconnect/disconnect" if [ -z "$datamode" ] || [ ! _initHilinkAPI ]; then echo "Hilink: failed - return status: $status"; exit; fi -if ! _switchMobileData "$datamode"; then echo "Hilink: could not switch the data mode on/off . Error: ";_getErrorText; fi +if ! _switchMobileData "$datamode"; then echo -n "Hilink: could not switch the data mode on/off . Error: ";_getErrorText; fi if ! _closeHilinkAPI; then echo -n "Hilink: failed - return status: $status . Error: ";_getErrorText; fi diff --git a/config/config.php b/config/config.php index 8003a320..87b17830 100755 --- a/config/config.php +++ b/config/config.php @@ -28,6 +28,7 @@ define('RASPI_LIGHTTPD_CONFIG', '/etc/lighttpd/lighttpd.conf'); define('RASPI_ACCESS_CHECK_IP', '1.1.1.1'); define('RASPI_ACCESS_CHECK_DNS', 'one.one.one.one'); define('RASPI_CLIENT_CONFIG_PATH', '/etc/raspap/networking/client_udev_prototypes.json'); +define('RASPI_MOBILEDATA_CONFIG', '/etc/raspap/networking/mobiledata.ini'); define('RASPI_CLIENT_SCRIPT_PATH', '/usr/local/sbin'); // Constant for the 5GHz wireless regulatory domain diff --git a/includes/get_clients.php b/includes/get_clients.php index 094cb8bf..11a74e94 100644 --- a/includes/get_clients.php +++ b/includes/get_clients.php @@ -128,23 +128,26 @@ function getClients($simple=true) $cl["device"][$i]["operator"] = $res[0]; break; case "hilink": + $pin=$user=$pw=""; + getMobileLogin($pin,$pw,$user); + $opts=$pin.' '.$user.' '.$pw; unset($res); // exec("ip link show $dev 2> /dev/null | grep -oP ' UP '",$res); exec("ifconfig -a | grep -i $dev -A 1 | grep -oP '(?<=inet )([0-9]{1,3}\.){3}'", $apiadd); $apiadd = !empty($apiadd) ? $apiadd[0]."1" : ""; unset($res); - exec("$path/info_huawei.sh mode hilink $apiadd", $res); + exec("$path/info_huawei.sh mode hilink $apiadd \"$opts\" ", $res); $cl["device"][$i]["mode"] = $res[0]; unset($res); - exec("$path/info_huawei.sh device hilink $apiadd", $res); + exec("$path/info_huawei.sh device hilink $apiadd \"$opts\" ", $res); if ($res[0] != "none" ) { $cl["device"][$i]["model"] = $res[0]; } unset($res); - exec("$path/info_huawei.sh signal hilink $apiadd", $res); + exec("$path/info_huawei.sh signal hilink $apiadd \"$opts\" ", $res); $cl["device"][$i]["signal"] = $res[0]; unset($ipadd); - exec("$path/info_huawei.sh ipaddress hilink $apiadd", $ipadd); + exec("$path/info_huawei.sh ipaddress hilink $apiadd \"$opts\" ", $ipadd); if (!empty($ipadd) && $ipadd[0] !== "none" ) { $cl["device"][$i]["connected"] = "y"; $cl["device"][$i]["wan_ip"] = $ipadd[0]; @@ -153,7 +156,7 @@ function getClients($simple=true) $cl["device"][$i]["wan_ip"] = "-"; } unset($res); - exec("$path/info_huawei.sh operator hilink $apiadd", $res); + exec("$path/info_huawei.sh operator hilink $apiadd \"$opts\" ", $res); $cl["device"][$i]["operator"] = $res[0]; break; case "phone": @@ -194,6 +197,15 @@ function getClientType($dev) { return $type; } +function getMobileLogin(&$pin,&$pw,&$user) { + if (file_exists(($f = RASPI_MOBILEDATA_CONFIG))) { + $dat = parse_ini_file($f); + $pin = (isset($dat["pin"]) && preg_match("/^[0-9]*$/", $dat["pin"])) ? "-p ".$dat["pin"] : ""; + $user = (isset($dat["router_user"]) && !empty($dat["router_user"]) ) ? "-u ".$dat["router_user"] : ""; + $pw = (isset($dat["router_pw"]) && !empty($dat["router_pw"]) ) ? "-P ".$dat["router_pw"] : ""; + } +} + function loadClientConfig() { // load network device config file for UDEV rules into $_SESSION @@ -271,12 +283,9 @@ function setClientState($state) preg_match("/^([0-9]{1,3}\.){3}/", $connected, $ipadd); $ipadd = $ipadd[0].'1'; // ip address of the Hilink api $mode = ($state == "up") ? 1 : 0; - $pin=""; - if (file_exists(($f = RASPI_CONFIG."/networking/mobiledata.ini"))) { - $dat = parse_ini_file($f); - $pin = (isset($dat["pin"]) && preg_match("/^[0-9]*$/", $dat["pin"])) ? $dat["pin"] : ""; - } - exec('sudo '.RASPI_CLIENT_SCRIPT_PATH.'/onoff_huawei_hilink.sh -c '.$mode.' -h '.$ipadd.' -p '.$pin); + $pin=$user=$pw=""; + getMobileLogin($pin,$pw,$user) + exec('sudo '.RASPI_CLIENT_SCRIPT_PATH.'/onoff_huawei_hilink.sh -c '.$mode.' -h '.$ipadd.' '.$pin.' '.$user.' '.$pw); break; case "ppp": if ($state == "up") { diff --git a/templates/networking.php b/templates/networking.php index f497cb28..578495e0 100755 --- a/templates/networking.php +++ b/templates/networking.php @@ -81,7 +81,7 @@ -
From 26a50993b997160634dc8aee8ec341f19ce9d7df Mon Sep 17 00:00:00 2001 From: Christian Zeitnitz Date: Fri, 21 May 2021 22:07:04 +0200 Subject: [PATCH 3/6] Fix hilink login --- config/client_config/huawei_hilink_api.sh | 8 +++---- config/client_config/info_huawei_hilink.sh | 26 ++++++++++++---------- includes/get_clients.php | 2 +- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/config/client_config/huawei_hilink_api.sh b/config/client_config/huawei_hilink_api.sh index c4402a6e..5c9fd809 100644 --- a/config/client_config/huawei_hilink_api.sh +++ b/config/client_config/huawei_hilink_api.sh @@ -232,6 +232,7 @@ function _login() { if ! _sendRequest "api/user/state-login"; then return 1; fi pwtype=$(echo "$response" | sed -rn 's/.*([0-9])<\/password_type>.*/\1/pi') if [ -z "$pwtype" ];then pwtype=4; fi # fallback is type 4 + ret=1 if [[ ! -z "$user" ]] && [[ ! -z "$pw" ]]; then # password encoding # type 3 : base64(pw) encoded @@ -251,12 +252,11 @@ function _login() { tokenlist=( $(cat $header_file | sed -rn 's/^__RequestVerificationToken:\s*([0-9a-z#]*).*$/\1/pi' | sed 's/#/ /g') ) _getToken sessID=$(cat $header_file | grep -ioP 'SessionID=([a-z0-9]*)') - if [ ! -z "$sessID" ] && [ ! -z "$token" ]; then - return 0 - fi + if [ ! -z "$sessID" ] && [ ! -z "$token" ]; then ret=0; fi fi + rm -f $header_file fi - return 1 + return $ret } # logout of hilink device diff --git a/config/client_config/info_huawei_hilink.sh b/config/client_config/info_huawei_hilink.sh index 345c1fe5..24145bef 100644 --- a/config/client_config/info_huawei_hilink.sh +++ b/config/client_config/info_huawei_hilink.sh @@ -14,35 +14,37 @@ # zbchristian 2021 function _setAPIParams() { - if [ ! -z "$hostip" ]; then host="$hostip"; fi - if [ ! -z "$username" ]; then user="$username"; fi - if [ ! -z "$password" ]; then pw="$password"; fi - if [ ! -z "$simpin" ]; then pin="$simpin"; fi + if [ ! -z "$hostip" ]; then host="$hostip"; fi + if [ ! -z "$username" ]; then user="$username"; fi + if [ ! -z "$password" ]; then pw="$password"; fi + if [ ! -z "$simpin" ]; then pin="$simpin"; fi } if [ -z "$1" ]; then echo "none"; exit; fi opt="${1,,}" shift +hostip="192.168.8.1" while [ -n "$1" ]; do case "$1" in - -u|--user) username="$2"; shift ;; - -P|--password) password="$2"; shift ;; - -p|--pin) simpin="$2"; shift ;; - -h|--host) hostip="$2"; shift ;; + -u|--user) username="$2"; shift ;; + -P|--password) password="$2"; shift ;; + -p|--pin) simpin="$2"; shift ;; + -h|--host) hostip="$2"; shift ;; esac shift done status="no valid option given" result="none" +hostip="192.168.8.1" if [ "$opt" = "connected" ]; then source /usr/local/sbin/huawei_hilink_api.sh - if ! _initHilinkAPI; then echo "none"; exit; fi _setAPIParams + if ! _initHilinkAPI; then echo "none"; exit; fi result=$(_getMobileDataStatus) _closeHilinkAPI else - info_file="/tmp/huawei_infos_$host.dat" + info_file="/tmp/huawei_infos_${hostip}_${id -u}.dat" if [ -f "$info_file" ]; then age=$(( $(date +%s) - $(stat $info_file -c %Y) )) if [[ $age -gt 5 ]]; then rm -f $info_file; fi @@ -52,11 +54,11 @@ else infos=$(cat $info_file) else source /usr/local/sbin/huawei_hilink_api.sh + _setAPIParams if ! _initHilinkAPI; then echo "none"; exit; fi - _setAPIParams infos=$(_getAllInformations) _closeHilinkAPI - if [ ! -z "$infos" ]; then echo "$infos" > /tmp/huawei_infos_$host.dat; fi + if [ ! -z "$infos" ]; then echo "$infos" > $info_file; fi fi case "$opt" in diff --git a/includes/get_clients.php b/includes/get_clients.php index 11a74e94..279fbef8 100644 --- a/includes/get_clients.php +++ b/includes/get_clients.php @@ -284,7 +284,7 @@ function setClientState($state) $ipadd = $ipadd[0].'1'; // ip address of the Hilink api $mode = ($state == "up") ? 1 : 0; $pin=$user=$pw=""; - getMobileLogin($pin,$pw,$user) + getMobileLogin($pin,$pw,$user); exec('sudo '.RASPI_CLIENT_SCRIPT_PATH.'/onoff_huawei_hilink.sh -c '.$mode.' -h '.$ipadd.' '.$pin.' '.$user.' '.$pw); break; case "ppp": From 29547b52e1d4a7a2c7d708acb911bea525e912a9 Mon Sep 17 00:00:00 2001 From: Christian Zeitnitz Date: Sun, 23 May 2021 09:04:08 +0200 Subject: [PATCH 4/6] Use Hilink API --- config/client_config/info_huawei.sh | 2 +- config/client_config/info_huawei_hilink.sh | 10 +++++----- config/client_config/switchClientState.sh | 8 +++++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/config/client_config/info_huawei.sh b/config/client_config/info_huawei.sh index 540ede98..fe6c27a1 100644 --- a/config/client_config/info_huawei.sh +++ b/config/client_config/info_huawei.sh @@ -47,7 +47,7 @@ case $opt in if [ ! "$res" = "none" ]; then if [ "$type" = "hilink" ]; then if [ "$res" = "LTE" ]; then res="4G" - elif [ "$res" = "WCDMA" ]]; then res="3G"; + elif [ "$res" = "WCDMA" ]; then res="3G"; else res="2G"; fi else if [ $res -eq 7 ]; then res="4G" diff --git a/config/client_config/info_huawei_hilink.sh b/config/client_config/info_huawei_hilink.sh index 24145bef..32b27954 100644 --- a/config/client_config/info_huawei_hilink.sh +++ b/config/client_config/info_huawei_hilink.sh @@ -21,7 +21,7 @@ function _setAPIParams() { } if [ -z "$1" ]; then echo "none"; exit; fi -opt="${1,,}" +property="${1,,}" shift hostip="192.168.8.1" while [ -n "$1" ]; do @@ -47,7 +47,7 @@ else info_file="/tmp/huawei_infos_${hostip}_${id -u}.dat" if [ -f "$info_file" ]; then age=$(( $(date +%s) - $(stat $info_file -c %Y) )) - if [[ $age -gt 5 ]]; then rm -f $info_file; fi + if [[ $age -gt 10 ]]; then rm -f $info_file; fi fi if [ -f "$info_file" ]; then @@ -58,10 +58,10 @@ else if ! _initHilinkAPI; then echo "none"; exit; fi infos=$(_getAllInformations) _closeHilinkAPI - if [ ! -z "$infos" ]; then echo "$infos" > $info_file; fi + if [ ! -z "$infos" ]; then echo -n "$infos" > $info_file; fi fi - case "$opt" in + case "$property" in device|devicename) key="devicename" ;; @@ -84,7 +84,7 @@ else key="fullname" ;; *) - key="" + key="device" ;; esac if [ -z "$key" ]; then result="none"; fi diff --git a/config/client_config/switchClientState.sh b/config/client_config/switchClientState.sh index 4d8abbf2..acdd2892 100644 --- a/config/client_config/switchClientState.sh +++ b/config/client_config/switchClientState.sh @@ -7,8 +7,10 @@ # get webroot webroot=$(cat /etc/lighttpd/lighttpd.conf | sed -rn 's/server.document-root\s*=\s*\"(.*)\"\s*$/\1/p') -if [ -z "$webroot" ] || [ ! -d "$webroot" ]; then - exit +webuser=$(cat /etc/lighttpd/lighttpd.conf | sed -rn 's/server.username\s*=\s*\"(.*)\"\s*$/\1/p') +if [ -z "$webroot" ] || [ ! -d "$webroot" ] || [ -z "$webuser" ]; then + echo "$0 : Problem to obtain webroot directory and/or web user - exit" | systemd-cat + exit fi cd $webroot @@ -21,7 +23,7 @@ fi [ -z "$state" ] && exit -php << _EOF_ +sudo -u $webuser php << _EOF_ Date: Fri, 18 Jun 2021 14:04:56 +0200 Subject: [PATCH 5/6] Add raspap_helpers.sh --- config/client_config/huawei_hilink_api.sh | 281 ++++++++++-------- config/client_config/info_huawei_hilink.sh | 12 +- config/client_config/onoff_huawei_hilink.sh | 28 +- config/client_config/raspap_helpers.sh | 51 ++++ ...k.service => start_huawei_hilink@.service} | 2 +- config/client_config/switchClientState.sh | 36 --- config/client_udev_prototypes.json | 4 +- installers/raspap.sudoers | 1 - 8 files changed, 233 insertions(+), 182 deletions(-) create mode 100644 config/client_config/raspap_helpers.sh rename config/client_config/{start_huawei_hilink.service => start_huawei_hilink@.service} (76%) delete mode 100644 config/client_config/switchClientState.sh diff --git a/config/client_config/huawei_hilink_api.sh b/config/client_config/huawei_hilink_api.sh index 5c9fd809..6dc439f4 100644 --- a/config/client_config/huawei_hilink_api.sh +++ b/config/client_config/huawei_hilink_api.sh @@ -6,15 +6,16 @@ # - send a standard http request with a xml formatted string to the device (default IP 192.169.8.1) # - Howto: # o "source" this script in your own script from the command line -# o if host ip/name differs, set "host=192.168.178.1" before calling any function -# o if the device is locked by a password, set user="admin"; pw="1234secret" -# _login is called automaticallcall -# Password types 3 and 4 are supported -# o if the SIM is requiring a PIN, set "pin=1234" +# o if hilink_host ip/name differs, set "hilink_host=192.168.178.1" before calling any function +# o if the device is locked by a password, set hilink_user="admin"; hilink_password"1234secret" +# _login is called automatically +# only password type 4 is supported +# o if the SIM is requiring a PIN, set "hilink_pin=1234" # o connect device to network: _switchMobileData ON ( or 1 ) # o disconnect device: _switchMobileData OFF ( or 0 ) # o get informations about the device: _getDeviceInformation and _getStatus and _getNetProvider # all functions return XML formatted data in $response. +# o _getAllInformations: returns all available informations as key/value pairs (outputs text) # o Check if device is connected: "if _isConnected; then .... fi" # o $response can be parsed by calling _valueFromResponse # e.g "_valueFromResponse msisdn" to get the phone number after a call to _getDeviceInformation @@ -29,6 +30,7 @@ # # required software: curl, base64, sha256sum, sed # +# ToDo: improve error handling # # zbchristian 2021 # @@ -36,65 +38,73 @@ # Initialization procedure # ======================== # -# host=$host_default # ip address of device -# user="admin" # user name if locked (default admin) -# pw="1234Secret" # password if locked -# pin="1234" # PIN of SIM -# _initHilinkAPI # initialize the API +# hilink_host=192.168.8.1 # ip address of device +# hilink_user="admin" # user name if locked (default admin) +# hilink_password="1234Secret" # password if locked +# hilink_pin="1234" # PIN of SIM +# _initHilinkAPI # initialize the API # # Termination # =========== # cleanup the API before quitting the shell # _closeHilinkAPI (optional: add parameter "save" to save the session/token data for subsequent calls. Valid for a few minutes.) +# +# BE AWARE, THAT THE API USES SOME GLOBAL VARIABLES : hilink_host, user, password, pin, response, status +# USE THESE ONLY TO COMMUNICATE WITH THE API. +# DO NOT USE THE VARIABLE PRE_FIX "hilink_" FOR YOUR OWN VARIABLES +# -host_default="192.168.8.1" -save_file="/tmp/hilink_api_saved.dat" -save_age=60 -header_file="/tmp/hilink_login_hdr.txt" +hilink_host_default="192.168.8.1" +hilink_save_file="/tmp/hilink_api_saved.dat" +hilink_save_age=60 +hilink_header_file="/tmp/hilink_login_hdr.txt" # initialize function _initHilinkAPI() { - if [ -z "$host" ]; then host=$host_default; fi + local age + if [ -z "$hilink_host" ]; then hilink_host=$hilink_host_default; fi if ! _hostReachable; then return 1; fi - if [ -f $save_file ]; then # found file with saved data + if [ -f $hilink_save_file ]; then # found file with saved data _getSavedData - age=$(( $(date +%s) - $(stat $save_file -c %Y) )) - if [[ $age -gt $save_age ]]; then - rm -f $save_file + age=$(( $(date +%s) - $(stat $hilink_save_file -c %Y) )) + if [[ $age -gt $hilink_save_age ]]; then + rm -f $hilink_save_file _logout _sessToken fi fi - if [ -z "$sessID" ] || [ -z "$token" ]; then _sessToken; fi + if [ -z "$hilink_sessID" ] || [ -z "$hilink_token" ]; then _sessToken; fi _login return $? } function _getSavedData() { - if [ -f $save_file ]; then # restore saved session data - dat=$(cat $save_file) - sessID=$(echo "$dat" | sed -nr 's/sessionid: ([a-z0-9]*)/\1/ip') - token=$(echo "$dat" | sed -nr 's/token: ([a-z0-9]*)/\1/ip') - tokenlist=( $(echo "$dat" | sed -nr 's/tokenlist: ([a-z0-9 ]*)/\1/ip') ) + local dat + if [ -f $hilink_save_file ]; then # restore saved session data + dat=$(cat $hilink_save_file) + hilink_sessID=$(echo "$dat" | sed -nr 's/sessionid: ([a-z0-9]*)/\1/ip') + hilink_token=$(echo "$dat" | sed -nr 's/token: ([a-z0-9]*)/\1/ip') + hilink_tokenlist=( $(echo "$dat" | sed -nr 's/tokenlist: ([a-z0-9 ]*)/\1/ip') ) fi } # Cleanup # parameter: "save" - will store sessionid and tokens in file function _closeHilinkAPI() { - if [ -z "$host" ]; then host=$host_default; fi + local opt + if [ -z "$hilink_host" ]; then hilink_host=$hilink_host_default; fi if ! _hostReachable; then return 1; fi - rm -f $save_file + rm -f $hilink_save_file [ ! -z "$1" ] && opt="${1,,}" if [ ! -z "$opt" ] && [ "$opt" = "save" ]; then - echo "sessionid: $sessID" > $save_file - echo "token: $token" >> $save_file - echo "tokenlist: ${tokenlist[@]}" >> $save_file + echo "sessionid: $hilink_sessID" > $hilink_save_file + echo "token: $hilink_token" >> $hilink_save_file + echo "tokenlist: ${hilink_tokenlist[@]}" >> $hilink_save_file fi _logout - tokenlist="" - sessID="" - token="" + hilink_tokenlist="" + hilink_sessID="" + hilink_token="" return 0 } @@ -111,6 +121,7 @@ function _getStatus() { } function _isConnected() { + local conn conn=$(_getStatus "connectionstatus") status="NO" if [ ! -z "$conn" ] && [ $conn -eq 901 ]; then @@ -176,7 +187,7 @@ function _getMobileDataStatus() { } -# PIN of SIM can be passed either as $pin, or as parameter +# PIN of SIM can be passed either as $hilink_pin, or as parameter # parameter: PIN number of SIM card function _enableSIM() { #SimState: @@ -187,14 +198,15 @@ function _enableSIM() { #259 - check PIN, #260 - PIN required, #261 - PUK required - if [ ! -z "$1" ]; then pin="$1"; fi + local simstate + if [ ! -z "$1" ]; then hilink_pin="$1"; fi if ! _login; then return 1; fi if _sendRequest "api/pin/status"; then - simstate=`echo $response | sed -rn 's/.*([0-9]*)<\/simstate>.*/\1/pi'` + simstate=$(echo $response | sed -rn 's/.*([0-9]*)<\/simstate>.*/\1/pi') if [[ $simstate -eq 257 ]]; then status="SIM ready"; return 0; fi if [[ $simstate -eq 260 ]]; then - status="PIN required" - if [ ! -z "$pin" ]; then _setPIN "$pin"; fi + status="PIN required" + if [ ! -z "$hilink_pin" ]; then _setPIN "$hilink_pin"; fi return $? fi if [[ $simstate -eq 255 ]]; then status="NO SIM"; return 1; fi @@ -202,20 +214,20 @@ function _enableSIM() { return 1 } -# obtain session and verification token - stored in vars $sessID and $token +# obtain session and verification token - stored in vars $hilink_sessID and $token # parameter: none function _sessToken() { - tokenlist="" - token="" - sessID="" - response=$(curl -s http://$host/api/webserver/SesTokInfo -m 5 2> /dev/null) - if [ -z "$response" ]; then echo "No access to device at $host"; return 1; fi + hilink_tokenlist="" + hilink_token="" + hilink_sessID="" + response=$(curl -s http://$hilink_host/api/webserver/SesTokInfo -m 5 2> /dev/null) + if [ -z "$response" ]; then echo "No access to device at $hilink_host"; return 1; fi status=$(echo "$response" | sed -nr 's/.*([0-9]*)<\/code>.*/\1/ip') if [ -z "$status" ]; then - token=`echo $response | sed -r 's/.*(.*)<\/TokInfo>.*/\1/'` - sessID=`echo $response | sed -r 's/.*(.*)<\/SesInfo>.*/\1/'` - if [ ! -z "$sessID" ] && [ ! -z "$token" ]; then - sessID="SessionID=$sessID" + hilink_token=$(echo $response | sed -r 's/.*(.*)<\/TokInfo>.*/\1/') + hilink_sessID=$(echo $response | sed -r 's/.*(.*)<\/SesInfo>.*/\1/') + if [ ! -z "$hilink_sessID" ] && [ ! -z "$hilink_token" ]; then + hilink_sessID="SessionID=$hilink_sessID" return 0 fi fi @@ -223,38 +235,39 @@ function _sessToken() { } # unlock device (if locked) with user name and password -# requires stored user="admin"; pw="1234secret";host=$host_default +# requires stored hilink_user="admin"; hilink_password"1234secret";hilink_host=$hilink_host_default # parameter: none function _login() { + local ret encpw pwtype pwtype3 hashedpw pwtype4 if _loginState; then return 0; fi # login not required, or already done _sessToken # get password type if ! _sendRequest "api/user/state-login"; then return 1; fi pwtype=$(echo "$response" | sed -rn 's/.*([0-9])<\/password_type>.*/\1/pi') if [ -z "$pwtype" ];then pwtype=4; fi # fallback is type 4 - ret=1 - if [[ ! -z "$user" ]] && [[ ! -z "$pw" ]]; then + ret=1 + if [[ ! -z "$hilink_user" ]] && [[ ! -z "$hilink_password" ]]; then # password encoding # type 3 : base64(pw) encoded # type 4 : base64(sha256sum(user + base64(sha256sum(pw)) + token)) - pwtype3=$(echo -n "$pw" | base64 --wrap=0) - hashedpw=$(echo -n "$pw" | sha256sum -b | sed -nr 's/^([0-9a-z]*).*$/\1/ip' ) + pwtype3=$(echo -n "$hilink_password" | base64 --wrap=0) + hashedpw=$(echo -n "$hilink_password" | sha256sum -b | sed -nr 's/^([0-9a-z]*).*$/\1/ip' ) hashedpw=$(echo -n "$hashedpw" | base64 --wrap=0) - pwtype4=$(echo -n "$user$hashedpw$token" | sha256sum -b | sed -nr 's/^([0-9a-z]*).*$/\1/ip' ) + pwtype4=$(echo -n "$hilink_user$hashedpw$hilink_token" | sha256sum -b | sed -nr 's/^([0-9a-z]*).*$/\1/ip' ) encpw=$(echo -n "$pwtype4" | base64 --wrap=0) if [ $pwtype -ne 4 ]; then encpw=$pwtype3; fi - xmldata="$user$encpw$pwtype" - xtraopts="--dump-header $header_file" - rm -f $header_file + hilink_xmldata="$hilink_user$encpw$pwtype" + hilink_xtraopts="--dump-header $hilink_header_file" + rm -f $hilink_header_file _sendRequest "api/user/login" if [ ! -z "$status" ] && [ "$status" = "OK" ]; then # store the list of 30 tokens. Each token is valid for a single request - tokenlist=( $(cat $header_file | sed -rn 's/^__RequestVerificationToken:\s*([0-9a-z#]*).*$/\1/pi' | sed 's/#/ /g') ) + hilink_tokenlist=( $(cat $hilink_header_file | sed -rn 's/^__RequestVerificationToken:\s*([0-9a-z#]*).*$/\1/pi' | sed 's/#/ /g') ) _getToken - sessID=$(cat $header_file | grep -ioP 'SessionID=([a-z0-9]*)') - if [ ! -z "$sessID" ] && [ ! -z "$token" ]; then ret=0; fi + hilink_sessID=$(cat $hilink_header_file | grep -ioP 'SessionID=([a-z0-9]*)') + if [ ! -z "$hilink_sessID" ] && [ ! -z "$hilink_token" ]; then ret=0; fi fi - rm -f $header_file + rm -f $hilink_header_file fi return $ret } @@ -263,12 +276,12 @@ function _login() { # parameter: none function _logout() { if _loginState; then - xmldata="1" + hilink_xmldata="1" if _sendRequest "api/user/logout"; then - tokenlist="" - sessID="" - token="" - login_enabled="" + hilink_tokenlist="" + hilink_sessID="" + hilink_token="" + hilink_login_enabled="" fi return $? fi @@ -277,41 +290,44 @@ function _logout() { # parameter: none function _loginState() { - status="OK" - if [ -z "$login_enabled" ]; then _checkLoginEnabled; fi - if [ $login_enabled -eq 1 ]; then return 0; fi # login is disabled - _sendRequest "api/user/state-login" - state=`echo "$response" | sed -rn 's/.*(.*)<\/state>.*/\1/pi'` - if [ ! -z "$state" ] && [ $state -eq 0 ]; then # already logged in - return 0 - fi - return 1 + local state + status="OK" + if [ -z "$hilink_login_enabled" ]; then _checkLoginEnabled; fi + if [ $hilink_login_enabled -eq 1 ]; then return 0; fi # login is disabled + _sendRequest "api/user/state-login" + state=`echo "$response" | sed -rn 's/.*(.*)<\/state>.*/\1/pi'` + if [ ! -z "$state" ] && [ $state -eq 0 ]; then # already logged in + return 0 + fi + return 1 } function _checkLoginEnabled() { + local state if _sendRequest "api/user/hilink_login"; then - login_enabled=0 - state=$(echo $response | sed -rn 's/.*(.*)<\/hilink_login>.*/\1/pi') - if [ ! -z "$state" ] && [ $state -eq 0 ]; then # no login enabled - login_enabled=1 - fi - else - login_enabled="" - fi + hilink_login_enabled=0 + state=$(echo $response | sed -rn 's/.*(.*)<\/hilink_login>.*/\1/pi') + if [ ! -z "$state" ] && [ $state -eq 0 ]; then # no login enabled + hilink_login_enabled=1 + fi + else + hilink_login_enabled="" + fi } # switch mobile data on/off 1/0 -# if SIM is locked, $pin has to be set +# if SIM is locked, $hilink_pin has to be set # parameter: state - ON/OFF or 1/0 function _switchMobileData() { + local mode if [ -z "$1" ]; then return 1; fi _login mode="${1,,}" [ "$mode" = "on" ] && mode=1 [ "$mode" = "off" ] && mode=0 if [[ $mode -ge 0 ]]; then - if _enableSIM "$pin"; then - xmldata="$mode" + if _enableSIM "$hilink_pin"; then + hilink_xmldata="$mode" _sendRequest "api/dialup/mobile-dataswitch" return $? fi @@ -321,31 +337,33 @@ function _switchMobileData() { # parameter: PIN of SIM card function _setPIN() { + local pin if [ -z "$1" ]; then return 1; fi pin="$1" - xmldata="0$pin" + hilink_xmldata="0$pin" _sendRequest "api/pin/operate" return $? } -# Send request to host at http://$host/$apiurl -# data in $xmldata and options in $xtraopts +# Send request to host at http://$hilink_host/$apiurl +# data in $hilink_xmldata and options in $hilink_xtraopts # parameter: apiurl (e.g. "api/user/login") function _sendRequest() { + local ret apiurl status="ERROR" if [ -z "$1" ]; then return 1; fi apiurl="$1" ret=1 - if [ -z "$sessID" ] || [ -z "$token" ]; then _sessToken; fi - if [ -z "$xmldata" ];then - response=$(curl -s http://$host/$apiurl -m 10 \ - -H "Cookie: $sessID") + if [ -z "$hilink_sessID" ] || [ -z "$hilink_token" ]; then _sessToken; fi + if [ -z "$hilink_xmldata" ];then + response=$(curl -s http://$hilink_host/$apiurl -m 10 \ + -H "Cookie: $hilink_sessID") else - response=$(curl -s -X POST http://$host/$apiurl -m 10 \ + response=$(curl -s -X POST http://$hilink_host/$apiurl -m 10 \ -H "Content-Type: text/xml" \ - -H "Cookie: $sessID" \ - -H "__RequestVerificationToken: $token" \ - -d "$xmldata" $xtraopts 2> /dev/null) + -H "Cookie: $hilink_sessID" \ + -H "__RequestVerificationToken: $hilink_token" \ + -d "$hilink_xmldata" $hilink_xtraopts 2> /dev/null) _getToken fi if [ ! -z "$response" ];then @@ -363,28 +381,29 @@ function _sendRequest() { status="ERROR" fi if [[ "$status" =~ ERROR ]]; then _handleError; fi - xtraopts="" - xmldata="" + hilink_xtraopts="" + hilink_xmldata="" return $ret } # handle the list of tokens available after login # parameter: none function _getToken() { - if [ ! -z "$tokenlist" ] && [ ${#tokenlist[@]} -gt 0 ]; then - token=${tokenlist[0]} # get first token in list - tokenlist=("${tokenlist[@]:1}") # remove used token from list - if [ ${#tokenlist[@]} -eq 0 ]; then + if [ ! -z "$hilink_tokenlist" ] && [ ${#hilink_tokenlist[@]} -gt 0 ]; then + hilink_token=${hilink_tokenlist[0]} # get first token in list + hilink_tokenlist=("${hilink_tokenlist[@]:1}") # remove used token from list + if [ ${#hilink_tokenlist[@]} -eq 0 ]; then _logout # use the last token to logout fi - else - _sessToken # old token has been used - need new session + else + _sessToken # old token has been used - need new session fi } # Analyse $status for error code # return error text in $status function _handleError() { + local ret txt txt=$(_getErrorText) if [ -z "$code" ]; then return 1; fi ret=0 @@ -407,20 +426,21 @@ function _handleError() { return "$ret" } -declare -A err_hilink_api -err_hilink_api[101]="Unable to get session ID/token" -err_hilink_api[108001]="Invalid username/password" -err_hilink_api[108002]=${errors[108001]} -err_hilink_api[108006]=${errors[108001]} -err_hilink_api[108003]="User already logged in - need to wait a bit" -err_hilink_api[108007]="Too many login attempts - need to wait a bit" -err_hilink_api[125001]="Invalid session/request token" -err_hilink_api[125002]=${errors[125001]} -err_hilink_api[125003]=${errors[125001]} +declare -A hilink_err_api +hilink_err_api[101]="Unable to get session ID/token" +hilink_err_api[108001]="Invalid username/password" +hilink_err_api[108002]=${hilink_err_api[108001]} +hilink_err_api[108006]=${hilink_err_api[108001]} +hilink_err_api[108003]="User already logged in - need to wait a bit" +hilink_err_api[108007]="Too many login attempts - need to wait a bit" +hilink_err_api[125001]="Invalid session/request token" +hilink_err_api[125002]=${hilink_err_api[125001]} +hilink_err_api[125003]=${hilink_err_api[125001]} # check error and return error text # status passsed in $status, or $1 function _getErrorText() { + local err code errortext err="$status" code="0" if [ ! -z "$1" ]; then err="$1"; fi @@ -428,8 +448,8 @@ function _getErrorText() { errortext="$err" if [[ "$err" =~ ERROR\ *([0-9]*) ]] && [ ! -z "${BASH_REMATCH[1]}" ]; then code=${BASH_REMATCH[1]} - if [ ! -z "$code" ] && [ ! -z "${err_hilink_api[$code]}" ]; then - errortext="${err_hilink_api[$code]}" + if [ ! -z "$code" ] && [ ! -z "${hilink_err_api[$code]}" ]; then + errortext="${hilink_err_api[$code]}" fi fi echo $errortext @@ -437,8 +457,10 @@ function _getErrorText() { } function _hostReachable() { - avail=`timeout 0.5 ping -c 1 $host | sed -rn 's/.*time=.*/1/p'` - if [ -z "$avail" ]; then return 1; fi + local avail + avail=$( timeout 0.5 ping -c 1 $hilink_host | sed -rn 's/.*time=.*/1/p' ) + if [ -z "$avail" ]; then status="ERROR: Not reachable"; return 1; fi + status="OK" return 0; } @@ -446,6 +468,7 @@ function _hostReachable() { # call another function first! # parameter: tag-name function _valueFromResponse() { + local par value if [ -z "$response" ] || [ -z "$1" ]; then return 1; fi par="$1" value=$(echo $response | sed -rn 's/.*<'$par'>(.*)<\/'$par'>.*/\1/pi') @@ -468,15 +491,15 @@ function _keyValuePairs() { return 0 } -host=$host_default -user="admin" -pw="" -token="" -tokenlist="" -sessID="" -xmldata="" -xtraopts="" +hilink_token="" +hilink_tokenlist="" +hilink_sessID="" +hilink_xmldata="" +hilink_xtraopts="" +hilink_host=$hilink_host_default +hilink_user="admin" +hilink_password="" +hilink_pin="" response="" status="" -pwtype=-1 - + \ No newline at end of file diff --git a/config/client_config/info_huawei_hilink.sh b/config/client_config/info_huawei_hilink.sh index 32b27954..c98ee9fe 100644 --- a/config/client_config/info_huawei_hilink.sh +++ b/config/client_config/info_huawei_hilink.sh @@ -14,10 +14,10 @@ # zbchristian 2021 function _setAPIParams() { - if [ ! -z "$hostip" ]; then host="$hostip"; fi - if [ ! -z "$username" ]; then user="$username"; fi - if [ ! -z "$password" ]; then pw="$password"; fi - if [ ! -z "$simpin" ]; then pin="$simpin"; fi + if [ ! -z "$hostip" ]; then hilink_host="$hostip"; fi + if [ ! -z "$username" ]; then hilink_user="$username"; fi + if [ ! -z "$password" ]; then hilink_password="$password"; fi + if [ ! -z "$simpin" ]; then hilink_pin="$simpin"; fi } if [ -z "$1" ]; then echo "none"; exit; fi @@ -44,7 +44,7 @@ if [ "$opt" = "connected" ]; then result=$(_getMobileDataStatus) _closeHilinkAPI else - info_file="/tmp/huawei_infos_${hostip}_${id -u}.dat" + info_file="/tmp/huawei_infos_${hostip}_$(id -u).dat" if [ -f "$info_file" ]; then age=$(( $(date +%s) - $(stat $info_file -c %Y) )) if [[ $age -gt 10 ]]; then rm -f $info_file; fi @@ -75,7 +75,7 @@ else key="msisdn" ;; imei|imsi|rssi|rsrq|rsrp|sinr|ecio) - key="$opt" + key="$property" ;; signal) key="rsrq" diff --git a/config/client_config/onoff_huawei_hilink.sh b/config/client_config/onoff_huawei_hilink.sh index 2ee413d2..cd050016 100644 --- a/config/client_config/onoff_huawei_hilink.sh +++ b/config/client_config/onoff_huawei_hilink.sh @@ -5,6 +5,7 @@ # options: -u, --user - user name (default "admin") # -P, --password - password # -h, --host - host ip address (default 192.168.8.1) +# -d, --devname - device name (IP is extracted using default route) # -p, --pin - PIN of SIM card # -c, --connect - connect 0/1 to set datamode off/on # @@ -12,24 +13,37 @@ # # zbchristian 2021 -# include the hilink API (defaults: user=admin, host=192.168.8.1) +# include the hilink API (defaults: hilink_user=admin, hilink_host=192.168.8.1) source /usr/local/sbin/huawei_hilink_api.sh +# include the raspap helper functions +source /usr/local/sbin/raspap_helpers.sh + datamode="" +devname="" while [ -n "$1" ]; do case "$1" in - -u|--user) user="$2"; shift ;; - -P|--password) pw="$2"; shift ;; - -p|--pin) if [[ $2 =~ ^[0-9]{4,8} ]]; then pin="$2"; fi; shift ;; - -h|--host) host="$2"; shift ;; + -u|--user) hilink_user="$2"; shift ;; + -P|--password) hilink_password="$2"; shift ;; + -p|--pin) if [[ $2 =~ ^[0-9]{4,8} ]]; then hilink_pin="$2"; fi; shift ;; + -h|--host) hilink_host="$2"; shift ;; + -d|--devname) devname="$2"; shift ;; -c|--connect) if [ "$2" = "1" ]; then datamode=1; else datamode=0; fi; shift ;; esac shift done -echo "Hilink: switch device at $host to mode $datamode" | systemd-cat +if [ ! _loginState ] && [ -z "$hilink_password" ] || [ -z "$hilink_pin" ]; then _getAuthRouter; fi -status="usage: -c 1/0 to disconnect/disconnect" +if [ ! -z "$devname" ]; then # get host IP for given device name + gw=$(ip route list | sed -rn "s/default via (([0-9]{1,3}\.){3}[0-9]{1,3}).*dev $devname.*/\1/p") + if [ -z "$gw" ]; then exit; fi # device name not found in routing list -> abort + hilink_host="$gw" +fi + +echo "Hilink: switch device at $hilink_host to mode $datamode" | systemd-cat + +status="usage: -c 1/0 to disconnect/connect" if [ -z "$datamode" ] || [ ! _initHilinkAPI ]; then echo "Hilink: failed - return status: $status"; exit; fi if ! _switchMobileData "$datamode"; then echo -n "Hilink: could not switch the data mode on/off . Error: ";_getErrorText; fi diff --git a/config/client_config/raspap_helpers.sh b/config/client_config/raspap_helpers.sh new file mode 100644 index 00000000..a20ba309 --- /dev/null +++ b/config/client_config/raspap_helpers.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# +# Helper functions to extract informations from RaspAP config/settings +# +# zbchristian 2021 +# +# get the values of a RaspAP config variable +# call: _getRaspapConfig RASPAP_MOBILEDATA_CONFIG + +raspap_webroot="/var/www/html" + +function _getWebRoot() { + local path + path=$(cat /etc/lighttpd/lighttpd.conf | sed -rn "s/server.document-root \s*= \"([^ \s]*)\"/\1/p") + if [ ! -z "$path" ]; then raspap_webroot="$path"; fi + if [ -z "$path" ]; then return 1; else return 0; fi +} + +# expand an RaspAP config variable utilizing PHP +function _getRaspapConfig() { + local conf var + raspap_config="" + var="$1" + if [ ! -z "$var" ]; then + if ! _getWebRoot; then return 1; fi + conf="$raspap_webroot/includes/config.php" + if [ -f "$conf" ]; then + conf=$(php -r 'include "'$conf'"; echo '$var';' 2> /dev/null) + if [ ! -z "$conf" ] && [ -d ${conf%/*} ]; then raspap_config="$conf"; fi + fi + fi + if [ -z "$raspap_config" ]; then return 1; else return 0; fi +} + +# Username and password for mobile data devices is stored in a file (RASPAP_MOBILEDATA_CONFIG) +function _getAuthRouter() { + local mfile mdata pin user pw + if ! _getRaspapConfig "RASPI_MOBILEDATA_CONFIG"; then return 1; fi + mfile="$raspap_config" + if [ -f $mfile ]; then + mdata=$(cat "$mfile") + pin=$(echo "$mdata" | sed -rn 's/pin = ([^ \s]*)/\1/ip') + if [ ! -z "$pin" ]; then raspap_pin="$pin"; fi + user=$(echo "$mdata" | sed -rn 's/router_user = ([^ \s]*)/\1/ip') + if [ ! -z "$user" ]; then raspap_user="$user"; fi + pw=$(echo "$mdata" | sed -rn 's/router_pw = ([^ \s]*)/\1/ip') + if [ ! -z "$pw" ]; then raspap_password="$pw"; fi + return 0 + fi + return 1 +} diff --git a/config/client_config/start_huawei_hilink.service b/config/client_config/start_huawei_hilink@.service similarity index 76% rename from config/client_config/start_huawei_hilink.service rename to config/client_config/start_huawei_hilink@.service index 19d775d0..b735b1b1 100644 --- a/config/client_config/start_huawei_hilink.service +++ b/config/client_config/start_huawei_hilink@.service @@ -5,7 +5,7 @@ Description=Bring up HUAWEI mobile hilink device Type=oneshot RemainAfterExit=no ExecStart=/bin/sleep 15 -ExecStart=/usr/local/sbin/switchClientState.sh up +ExecStart=/usr/local/sbin/onoff_huawei_hilink.sh -c 1 -d %i [Install] Alias=start_ltemodem.service diff --git a/config/client_config/switchClientState.sh b/config/client_config/switchClientState.sh deleted file mode 100644 index acdd2892..00000000 --- a/config/client_config/switchClientState.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -# start with "sudo" -# parameters: up or on -# -# switch client state to UP -# the actual code is in PHP - -# get webroot -webroot=$(cat /etc/lighttpd/lighttpd.conf | sed -rn 's/server.document-root\s*=\s*\"(.*)\"\s*$/\1/p') -webuser=$(cat /etc/lighttpd/lighttpd.conf | sed -rn 's/server.username\s*=\s*\"(.*)\"\s*$/\1/p') -if [ -z "$webroot" ] || [ ! -d "$webroot" ] || [ -z "$webuser" ]; then - echo "$0 : Problem to obtain webroot directory and/or web user - exit" | systemd-cat - exit -fi -cd $webroot - -state="" -if [ ! -z $1 ] && [[ $1 =~ ^(up|on|UP|ON)$ ]]; then - state="up" -elif [ ! -z $1 ] && [[ $1 =~ ^(down|off|DOWN|OFF)$ ]]; then - state="down" -fi - -[ -z "$state" ] && exit - -sudo -u $webuser php << _EOF_ - -_EOF_ - - diff --git a/config/client_udev_prototypes.json b/config/client_udev_prototypes.json index a147e776..bd49f419 100644 --- a/config/client_udev_prototypes.json +++ b/config/client_udev_prototypes.json @@ -39,10 +39,10 @@ "type": "hilink", "type_info": "Huawei Hilink", "clientid": 4, - "comment": "Huawei mobile data device in router mode. Control via HTTP", + "comment": "Huawei mobile data device in router mode. Control via HTTP. Device is connecting via service", "name_prefix": "hilink", "default_ip": "192.168.8.1", - "udev_rule": "SUBSYSTEM==\"net\", ACTION==\"add\", SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"$IDVENDOR$\", ATTRS{idProduct}==\"$IDPRODUCT$\", NAME=\"$DEVNAME$\", ENV{raspapType}=\"hilink\", TAG+=\"systemd\", ENV{SYSTEMD_WANTS}=\"start start_huawei_hilink.service\" " + "udev_rule": "SUBSYSTEM==\"net\", ACTION==\"add\", SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"$IDVENDOR$\", ATTRS{idProduct}==\"$IDPRODUCT$\", NAME=\"$DEVNAME$\", ENV{raspapType}=\"hilink\", TAG+=\"systemd\", ENV{SYSTEMD_WANTS}=\"start start_huawei_hilink@hilink%n.service\" " }, { "type": "phone", diff --git a/installers/raspap.sudoers b/installers/raspap.sudoers index 355fd8eb..fc692e1c 100644 --- a/installers/raspap.sudoers +++ b/installers/raspap.sudoers @@ -53,7 +53,6 @@ www-data ALL=(ALL) NOPASSWD:/usr/local/sbin/onoff_huawei_hilink.sh * www-data ALL=(ALL) NOPASSWD:/bin/sed -i * /etc/wvdial.conf www-data ALL=(ALL) NOPASSWD:/bin/sed -i * /etc/udev/rules.d/80-raspap-net-devices.rules www-data ALL=(ALL) NOPASSWD:/usr/bin/tee -a /etc/udev/rules.d/80-raspap-net-devices.rules -www-data ALL=(ALL) NOPASSWD:/usr/local/sbin/switchClientState.sh * www-data ALL=(ALL) NOPASSWD:/usr/bin/tee /tmp/wireguard.log www-data ALL=(ALL) NOPASSWD:/bin/systemctl * wg-quick@wg0 www-data ALL=(ALL) NOPASSWD:/usr/bin/wg From 8f702a2a559fa22eea9859465146e330e20106a0 Mon Sep 17 00:00:00 2001 From: Christian Zeitnitz Date: Fri, 18 Jun 2021 17:27:11 +0200 Subject: [PATCH 6/6] Correct Hilink authentication and service --- config/client_config/80-raspap-net-devices.rules | 2 +- config/client_config/onoff_huawei_hilink.sh | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/config/client_config/80-raspap-net-devices.rules b/config/client_config/80-raspap-net-devices.rules index 33e6584c..ddec8203 100644 --- a/config/client_config/80-raspap-net-devices.rules +++ b/config/client_config/80-raspap-net-devices.rules @@ -1,3 +1,3 @@ -SUBSYSTEM=="net", ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="14db", NAME="hilink%n", TAG+="systemd", ENV{SYSTEMD_WANTS}="start start_huawei_hilink.service" +SUBSYSTEM=="net", ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="14db", NAME="hilink%n", TAG+="systemd", ENV{SYSTEMD_WANTS}="start start_huawei_hilink@hilink%n.service" diff --git a/config/client_config/onoff_huawei_hilink.sh b/config/client_config/onoff_huawei_hilink.sh index cd050016..9b3f8413 100644 --- a/config/client_config/onoff_huawei_hilink.sh +++ b/config/client_config/onoff_huawei_hilink.sh @@ -33,14 +33,19 @@ while [ -n "$1" ]; do shift done -if [ ! _loginState ] && [ -z "$hilink_password" ] || [ -z "$hilink_pin" ]; then _getAuthRouter; fi - if [ ! -z "$devname" ]; then # get host IP for given device name gw=$(ip route list | sed -rn "s/default via (([0-9]{1,3}\.){3}[0-9]{1,3}).*dev $devname.*/\1/p") if [ -z "$gw" ]; then exit; fi # device name not found in routing list -> abort hilink_host="$gw" fi +if [ -z "$hilink_password" ] || [ -z "$hilink_pin" ]; then + _getAuthRouter + if [ ! -z "$raspap_user" ]; then hilink_user="$raspap_user"; fi + if [ ! -z "$raspap_password" ]; then hilink_password="$raspap_password"; fi + if [ ! -z "$raspap_pin" ]; then hilink_pin="$raspap_pin"; fi +fi + echo "Hilink: switch device at $hilink_host to mode $datamode" | systemd-cat status="usage: -c 1/0 to disconnect/connect"