miércoles, 22 de noviembre de 2023

Envío de mensajes SMS con modems Huawei HiLink

Los módem Huawei HiLink funcionan como un router. Al conectarse al puerto USB del ordenador le proporcionan un dispositivo de red. No es posible utilizar comandos AT para controlar el dispositivo, es necesario utilizar su servicio web. En este artículo voy a explicar como utilizar el servicio web para enviar mensajes SMS. Mi módem es el modelo E8372h-320.

Por defecto la dirección IP del módem/router es 192.168.8.1 y el usuario para conectar "admin". En el dispositivo se indica la contraseña. Para no tener que introducir el código PIN cada vez que iniciemos el módem/router podemos deshabilitar la protección por código PIN. La comunicación con el servicio web la podemos realizar con cualquier lenguaje de programación. Yo he usado el interprete de comandos Bash y algunos programas como el cliente HTTP cURL.

#!/usr/bin/bash

SERVER=192.168.8.1
USERNAME="admin"
PASSWORD="xxxxxxxx"

En primer lugar debemos solicitar un ID de session y un "token" en la dirección /api/webserver/SesTokInfo. Recibiremos un documento XML, con el comando xmllint podemos extraer los datos que necesitamos utilizando XPath.

info=`curl -s http://$SERVER/api/webserver/SesTokInfo`

session=`echo $info | xmllint --xpath "/response/SesInfo/text()" -` 
token=`echo $info | xmllint --xpath "/response/TokInfo/text()" -`
<response><SesInfo>6MOMvUWALNM6aPQEZOTIHYuVEBC1C91u7Vd4f8MBdKx0BsxUjQ0Rceal8cyc8n4Qm7hUoIUOcOH40KLPEy743mUlySXQYAendJT00iu53uqLtUHrc2XL8bBW0vZVHhpC</SesInfo><TokInfo>TEQxGdHf0jU3w0B0o2WtL3meQrcPRJxq</TokInfo></response>

El siguiente paso es realizar la autenticación en el servicio web para tener permiso de ejecución de acciones. Para ello es necesario enviar un documento XML a la dirección /api/user/login con el usuario, la contraseña y el tipo de contraseña. Debemos usar el ID de sesión y el "token" obtenidos anteriormente.

login="<request><Username>$USERNAME</Username><Password>$hash</Password><password_type>4</password_type></request>"

login_response=`curl -i -s -b "SessionID=$session" -H "__RequestVerificationToken: $token" -d "$login" http://$SERVER/api/user/login`

Dependiendo del modelo de módem necesitaremos un tipo de contraseña diferente. Para el tipo 4 debemos en primer lugar hacer un "hash" SHA-256 de la contraseña y codificarlo en Base64. A continuación hay que unir el usuario, el "hash" de la contraseña y el "token" en una cadena de texto. Por último debemos hacer el "hash" SHA-256 de esta cadena y codificarlo en Base64. El resultado es lo que hay que usar en el parámetro Password del documento XML.

sha256base64 () {
	hash=`echo -n $1 | sha256sum | cut -d " " -f 1 | tr -d "\n" | base64 -w 0`
}

sha256base64 "$PASSWORD"
sha256base64 "$USERNAME$hash$token"

Al realizar la autenticación recibiremos una respuesta con la "cookie" SessionID con un nuevo ID de sesión y varias cabeceras con "tokens" para realizar acciones. Si solo queremos realizar una o dos acciones nos basta con leer las cabeceras __RequestVerificationTokenone y __RequestVerificationTokentwo. En la cabecera __RequestVerificationToken se encuentran esos dos "tokens" y algunos más separados por el carácter "#".

Set-Cookie: SessionID=KStfxWIiy8jlXbCrfP4zdkljk1BUvs84s8HQxckZz4obgTVtTpydBP87PO4cvjhAhqWSRsXkWCP7hLhBCQ70VR4Cydh7LXNYMYVnQfWKaXcPq7y4e7eBTWj00nR9Byla; path=/; HttpOnly;
__RequestVerificationTokenone: Bj02gvGS5bX80xfyhI32Jue69sAayt1Y
__RequestVerificationTokentwo: 0YO0Piy6RjWToDYuwC4uPl65ZZHF0yJv
__RequestVerificationToken: Bj02gvGS5bX80xfyhI32Jue69sAayt1Y#0YO0Piy6RjWToDYuwC4uPl65ZZHF0yJv#g23cIa8CG1QM6PLq5p0a0E0uzaYBALqW#R9rbWeZLmw0OGCd4oY5P2PHS0A2J9NIp#GOdHohrOjgB4mqkXN6X01Bm0cK1ulyyD#lQhntCogUbJ1kpEk45kqGJ5qNnqp9iuh#ADV1dYflDsm1mxpmBMwbeyN21jYTgYlv#TpfvkhBuZXjhmTepci5qVaZEQkeMuuKI#wyU6zQWvqNsyqtJ420s3mGNL0XV3Negx#a1s3OUp7yALiY9Yel473R0ymEPNLSD0D#imFzzR0lpQXdrHauh1u3GMCjSKBBDER6#GXbKBZ0BSXXpCZQucwIaPEt0R5GzvX7i#d8KqyjkmBiW81NHZXIsLMNW3q10EWXme#dDH3nhfJ09IAxFgqGkvckQSYGPf0kFYX#eNGn9TKmJ8EwFySmlcCKB1lyDGxSLvYn#cfcBw0XJyDqO31PxMdMDhZzCR1toaIPl#0ZFxajlHwK3eerw8h5tTYNORjJANd9RA#D1tGSDh3udWlROrUpKKYQAAdYMKytJiP#PNswsMQ3zW0e9bY2020OuoriSJEZf0oL#IVvt0050Eka5R4Ro0Ok4kawrMGI7BBy3#ww0qQSHq0a8VGgyXUQiyokp0gWtTc8zg#K0AXbLnRcpvWyx0Cgkn3XL8f0t7Heh0d#Y2AMqOdnaYXRXb5QwHyRZViNvcTMje7N#nmW4XjcjZsNGprw4mgMuNQ08rHLrf9zK#Mi9GmNorbl0iW0lL2YBqLCSIEoxA9T0k#xRAcG0ss42dX0c1DMc0MAqAroGN01oXl#rBfOzhcLOklRY0gMo1tHnpEocbkHuojF#LWDJoEpY7v5neIRWwzJV4hFjU69en5k4#FH9t6cc4En1XyvztexerCHsXyXmOEvaL#bxKPUfszcdLqpZK6S3K4ZIpPATZLGgKS#UXSF7hgjiAag0DjF0OgXd0umpOi4is2B#ksjbqLoj0ddIFDdDuVTPxPDIsIwQQgjb
session=`echo "$login_response" | grep -o "SessionID=[0-9a-zA-Z]*" | cut -d "=" -f 2`
token=`echo "$login_response" | grep -o "__RequestVerificationTokenone: [0-9a-zA-Z]*" | cut -d " " -f 2`

Con estos ID de sesión y "token" ya podemos mandar un mensaje SMS enviando un documento XML a la dirección /api/sms/send-sms. En este documento se indican los números de teléfono de los destinatarios, el mensaje, la longitud del mensaje y la fecha. Yo solo utilizo un número de teléfono pero es posible utilizar varios.

phone=$1
content=$2
length=${#content}
date=`date "+%F %H:%M:%S"`

sms="<request><Index>-1</Index><Phones><Phone>$phone</Phone></Phones><Content>$content</Content><Length>$length</Length><Reserved>1</Reserved><Date>$date</Date></request>"

sms_response=`curl -s -b "SessionID=$session" -H "__RequestVerificationToken: $token" -d "$sms" http://$SERVER/api/sms/send-sms`

Como respuesta obtenemos otro documento XML con el resultado del envío. Si se realizó correctamente recibiremos la cadena de texto "OK". De lo contrario recibiremos un número de error.

<response>OK</response>
<error><code>100005</code><message></message></error>
result=`echo $sms_response | xmllint --xpath "/response/text()" -`

if [[ $result == "OK" ]]
then
	exit 0
else
	exit 1
fi

El servicio web permite otras muchas acciones y hay varias bibliotecas en múltiples lenguajes de programación para utilizarlo. Podemos usar estas bibliotecas para interactuar con el servicio web o nos pueden servir como fuente de información para desarrollar nuestro propio código. A continuación se muestra el "script" completo para el envió de mensajes, se le deben pasar como parámetros el número de teléfono y el mensaje. También está disponible en un repositorio de GitHub.

./send-sms.sh XXXXXXXXX "Prueba de mensaje SMS"
#!/usr/bin/bash

SERVER=192.168.8.1
USERNAME="admin"
PASSWORD="xxxxxxxx"

sha256base64 () {
	hash=`echo -n $1 | sha256sum | cut -d " " -f 1 | tr -d "\n" | base64 -w 0`
}

phone=$1
content=$2
length=${#content}
date=`date "+%F %H:%M:%S"`

info=`curl -s http://$SERVER/api/webserver/SesTokInfo`

session=`echo $info | xmllint --xpath "/response/SesInfo/text()" -` 
token=`echo $info | xmllint --xpath "/response/TokInfo/text()" -`

sha256base64 "$PASSWORD"
sha256base64 "$USERNAME$hash$token"

login="<request><Username>$USERNAME</Username><Password>$hash</Password><password_type>4</password_type></request>"
login_response=`curl -i -s -b "SessionID=$session" -H "__RequestVerificationToken: $token" -d "$login" http://$SERVER/api/user/login`

session=`echo "$login_response" | grep -o "SessionID=[0-9a-zA-Z]*" | cut -d "=" -f 2`
token=`echo "$login_response" | grep -o "__RequestVerificationTokenone: [0-9a-zA-Z]*" | cut -d " " -f 2`

sms="<request><Index>-1</Index><Phones><Phone>$phone</Phone></Phones><Content>$content</Content><Length>$length</Length><Reserved>1</Reserved><Date>$date</Date></request>"
sms_response=`curl -s -b "SessionID=$session" -H "__RequestVerificationToken: $token" -d "$sms" http://$SERVER/api/sms/send-sms`

result=`echo $sms_response | xmllint --xpath "/response/text()" -`

if [[ $result == "OK" ]]
then
	exit 0
else
	exit 1
fi

No hay comentarios:

Publicar un comentario