Автоматизация отправки СМС с модемов Huawei с прошивкой HiLink

()

Очень часто для отправки СМС из различных скриптов используются недорогие мобильные USB-модемы. Раньше использовались модемы, при подключении которых в системе появлялся один или несколько последовательных портов и для отправки СМС было необходимо отправлять AT-команды на один из этих портов, для чего можно было использовать пакет smstools или gsm-utils.

В последнее время набирают популярность модемы, при подключении которых в системе создаётся виртуальная сетевая карта, а управление модемом осуществляется через web-интерфейс (например модемы Huawei с прошивкой HiLink). Использовать привычные решения для отправки SMS с этими модемами не получится, однако это не означает что их нельзя использовать для отправки SMS из скриптов. Далее будет рассмотрен пример скрипта на Perl, который позволит отправлять SMS используя модемы Huawei с прошивкой HiLink.

Модемы Huawei с прошивкой HiLink

Вобщем-то задача достаточно простая: в веб-интерфейсе есть функция отправки SMS и нужно просто выяснить какие запросы отправляются из браузера и потом реализовать отправку таких же запросов из скрипта. Для изучения были выбраны два модема Huawei E3272. Один с прошивкой от оператора «Билайн», другой - с прошивкой от татарстанского оператора «Летай».

В процессе изучения выяснилось что несмотря на то что оба модема одной и той же модели, они имеют определённые различия не только в оформлении веб-интерфейса, но и во внутреннем API, использующемся Web-интерфейсом.

Так на модеме с прошивкой от «Билайн» достаточно отправить запрос на URL "http://192.168.1.1/api/sms/send-sms" без всякой авторизации. На модеме с прошивкой от «Летай» предварительно надо "кинуть" запрос на "http://192.168.1.1/api/webserver/SesTokInfo" чтобы получить идентификатор сессии и авторизационный токен. Разобравшись с особенностями этих модемов был написан скрипт, листинг которого приведён ниже:

#!/usr/bin/perl

use strict;
use warnings;
use diagnostics;

use LWP::UserAgent;
use HTML::Entities;
use Time::HiRes qw (time);
use POSIX;
use Data::Dumper;
use utf8;
use Encode;

# Собственно функция отправки СМС
sub SendSMS {
        my $ip = shift;
        my $phone = shift;
        my $msg = shift;

        # Формируем запрос
        my $request_data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
        $request_data .= "<request><Index>-1</Index><Phones><Phone>";
        $request_data .= encode_entities($phone);
        $request_data .= "</Phone></Phones><Sca></Sca><Content>";
        $request_data .= encode_entities(decode("utf8", $msg));
        $request_data .= "</Content><Length>";
        $request_data .= length($msg);
        $request_data .= "</Length><Reserved>1</Reserved><Date>";
        $request_data .= encode_entities(strftime("%Y-%m-%d %H:%M:%S", localtime()));
        $request_data .= "</Date></request>";

        # Сначала попробуем получить авторизационный токен и идентификатор сессии
        # ВАЖНО! Отсутствие токена не всегда является проблемой!
        my $ua = LWP::UserAgent->new(
                agent => "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
        );
        my $response = $ua->get("http://$ip/api/webserver/SesTokInfo");
        my $token;
        my $session_id;
        if ($response->content =~ m{<TokInfo>(.+?)</TokInfo>}) {
                $token = $1;
        }
        if ($response->content =~ m{<SesInfo>SessionID=(.+?)</SesInfo>}) {
                $session_id = $1;
        }

        # Создаём запрос
        my $req = HTTP::Request->new("POST" => "http://$ip/api/sms/send-sms");
        # Указываем основные заголовки
        $req->header("Origin" => "http://$ip");
        $req->header("Referer" => "http://$ip/html/smsinbox.html");
        $req->header("Content-Type" => "application/x-www-form-urlencoded; charset=UTF-8");
        $req->header("X-Requested-With" => "XMLHttpRequest");
        # Если есть токен то добавляем ещё и его
        $req->header(":__RequestVerificationToken" => $token) if $token;
        # Если есть идентификатор сессии
        $req->header("Cookie" => "SessionID=$session_id") if $session_id;
        # Добавляем данные к запросу
        $req->content($request_data);

        # Выполняем запрос
        $response = $ua->request($req);

        # Обрабатываем результат
        return $response->is_success && $response->content =~ m{<response>OK</response>}s ? 1 : 0;
}
my $ip = shift @ARGV;
my $phone = shift @ARGV;
my $msg = shift @ARGV;

if (!defined($msg)) {
        print "Usage: $0 <Modem IP> <Phone Number> <Message>\n";
        exit();
}

# $ip не валидируем, потому что там может быть и доменное имя (например m.home)
# пробуем валидировать $phone:
if ($phone !~ m{^(?:\+7|8)?\d{10}$}) {
        print "Bad phone number!\n";
        exit();
}
# $msg не валидируем. Если до сюда дошли то значит он не пуст и этого достаточно

my $result = SendSMS($ip, $phone, $msg);
print $result ? "OK\n" : "ERROR\n";

Скрипт необходимо сохранить под любым удобным именем (например "sendsms_hilink.pl") и сделать исполняемым. Скрипт принимает три параметра: IP-адрес модема, номер телефона получателя и собственно текст сообщения. Например:

./sendsms_hilink.pl 192.168.1.1 +79112345678 "Тестовое сообщение"

В случае успеха скрипт напечатает на стандартный вывод "OK", в случае ошибки - "ERROR". Скорее всего скрипт будет работать и с другими модемами Huawei с прошивкой HiLink, но гарантировать что-либо тут трудно.

На этом всё. Приятной работы!

Ключевые слова: usb modem, sms, скрипт, perl, huawei, hilink, e3272.

Подписаться на обновления: RSS-лента Telegram канал Twitter

Комментарии:

Anonymous 2018-03-15 15:53:42 (#)

А еще можно переключить модем в режим модем (вот такой каламбур :-)) и по старинке пользоваться AT командами

MooSE 2018-03-15 17:51:33 (#)

А еще можно переключить модем в режим модем (вот такой каламбур :-)) и по старинке пользоваться AT командами
Редактировать

Этот режим часто называют "стик" (stick) :) Но если не ошибаюсь то для перевода в этот режим нужно перепрошивать модем. Причём если промахнуться то можно получить "кирпич". Я предпочитаю не рисковать:)

Anonymous 2018-03-16 10:31:43 (#)

>если не ошибаюсь то для перевода в этот режим нужно перепрошивать модем.

Ошибаешься. Это зависит от модема. Например, для ZTE MF823D достаточно выполнить http запрос http://192.168.0.1/goform/goform_process?goformId=MODE_SWITCH&switchCmd=FACTORY
естественно поменяв IP на правильный

MooSE 2018-03-19 16:02:21 (#)

Например, для ZTE MF823D достаточно выполнить http запрос
До ZTE модемов я ещё не добрался:) Хотя планы есть:)

Anonymous 2018-05-10 19:58:52 (#)

Спасибо, очень помогло в одном проекте!
Однако, скрипт не работает на новой прошивке от МТС, пришлось даунгейдить с 4pda на :
Версия ПО: 22.328.62.00.143
Версия веб-интерфейса: 17.100.13.01.03-Mod1.10
Заработало.
Скрипт некорректно переводит кириллицу, получаются иероглифы, как правильно закодировать кириллицу?

MooSE 2018-05-10 22:32:39 (#)

Насчёт кириллицы: у меня всё нормально отрабатывает:) Возможно на разных версиях прошивок надо использовать разные кодировки. Когда я писал скрипт я тупо с отладчиком в браузере смотрел запросы, а потом пытался повторить их.

Я бы и с МТС-модемом так же поступил: встал бы с отладчиком и посмотрел что и как оно шлёт:)
Новый комментарий



© 2006-2018 Вадим Калинников aka MooSE