Building a SMS gateway from a Huawei USB Modem

In this tutorial, we will use a cheap usb modem to send SMS messages over the internet. We can use both a gui and an API for interactive and scripted uses

Table of Contents

Introduction

A while back I came across a Huawei E303 usb modem stick for next to nothing on eBay.

The modem itself is nothing great considering its data capabilities are pretty obsolete.

It does have one cool feature. It has a Web GUI for sending and receiving SMS messages. It also has an API which can be used on the command line.

This makes the modem handy to carry around as an emergency replacement for my mobile

I want to access it via the cloud

Main features:

  • Send text/sms messages from a web browser
  • Send text/sms remotely from the command line
  • Send alerts via txt
  • Query device info

The plan

The Web interface will be made available to the internet via SSH remote forwarding between my Raspberry Pi (this has the dongle connected) and a web server in the cloud. The internet facing web server will have HTTPS and password protection.

The neat thing is that the Raspberry Pi does not need to listen on any externally reachable ports, instead the RaspberryPi acts as an SSH client, initiating a connection to the cloud. The SSH "RemoteForward" option allows an SSH client to 'push' a port so that it is reachable on the remote SSH server.

Part 1: Configuration on the Pi

First plug the modem into your server and beware that it may automatically assign itself as the primary internet connection. Depending on your OS it will immediately show up as either as "enx582c80139263" or eth1 If you're not so lucky, you may need to run the command below, this instructs the modem to act as an ethernet device rather than an old fashioned modem

sudo usb_modeswitch -v 12d1 -p 1f01 "55534243123456780000000000000011062000000101000100000000000000"

Next, let's bring it online (if it hasn't automatically)

ip link set up enx582c80139263
ip addr add 192.168.1.2/30 dev enx582c80139263
cat >> /etc/network/interfaces << EOF
    allow-hotplug enx582c80139263
    iface enx582c80139263 inet static
    address 192.168.1.2
    netmask 255.255.255.252
EOF

Part 2: Sending and receiving SMS

Now we'll learn how the API works and demonstrate sendding and receiving SMS messages. I have made a script containing most of the HiLink API functions.

wget https://s3.amazonaws.com/etherarp.net/hilink.sh
chmod +x hilink.sh

$ ./hilink.sh send_sms "Hello, World" 55512345678
<?xml version="1.0" encoding="UTF-8"?>
<response>OK</response>

$./hilink.sh get_sms
<?xml version="1.0" encoding="utf-8"?>
<response>
    <Count>1</Count>
    <Messages>
        <Message>
            <Smstat>0</Smstat>
            <Index>20029</Index>
            <Phone>32665</Phone>
            <Content>Use 892223 to log in to Facebook.</Content>
            <Date>2018-03-19 23:43:58</Date>
            <Sca></Sca>
            <SaveType>4</SaveType>
            <Priority>0</Priority>
            <SmsType>1</SmsType>
        </Message>
    </Messages>
</response>

Let's look at what's going on under the hood inside send_sms

send_sms)
    curl $curl_options \
    -X POST "$scheme://$host:$port/api/sms/send-sms" \
    -H "Cookie:$COOKIE" \
    -H "__RequestVerificationToken:$TOKEN" \
    -d "<request><Index>-1</Index><Phones><Phone>$2</Phone></Phones><Sca>$sca</Sca><Content>$3</Content><Length>${#3}</Length><Reserved>1</Reserved><Date>$(date '+%Y-%m-%d %T')</Date></request>"
;;

Part 3: Tunnelling to the Frontend Server.

The command below initiates the ssh reverse tunnel which allows the cloud server to communicate with the dongle. This instance of SSH needs to be kept running. We can make this easier using AutoSSH, however this is beyond the scope.

On the Pi:

 ssh cloud_server -R 8088:192.168.1.1:80 -N &

Now log into the server and test it's working

$ curl http://localhost:8088/api/monitoring/check-notifications

<?xml version="1.0" encoding="UTF-8"?>
<response>
<UnreadMessage>1</UnreadMessage>
<SmsStorageFull>0</SmsStorageFull>
<OnlineUpdateStatus>10</OnlineUpdateStatus>
</response>

Part 4: Install and Configure Nginx

Generating the SSL certificate (with LetsEncrypt)

    sudo wget -O -  https://get.acme.sh | sh
    acme.sh --issue --standalone -d hilink.example.etherarp.net

Create the username/password

htpasswd -c /etc/nginx/.htpasswd hilink
New password: 
Re-type new password: 
Adding password for user hilink

Configuring Nginx Virtualhost

Paste the following into /etc/nginx/sites-enabled/hilink
(Be sure to find-and-replace hilink.example.etherarp.net)

server { 
    listen 127.0.0.1:8443 ssl;
    server_name hilink.example.etherarp.net;
    ssl_certificate /root/.acme.sh/hilink.example.etherarp.net/fullchain.cer;
    ssl_certificate_key /root/.acme.sh/hilink.example.etherarp.net/hilink.example.etherarp.net.key;
    location ~ ^/$ {
        return 301 https://hilink.example.etherarp.net/html/smsinbox.html;
    }
    location / {
        auth_basic "Restricted";
        auth_basic_user_file /etc/nginx/.htpasswd;
        proxy_pass http://127.0.0.1:8088;
        proxy_set_header Host hi.link;
        add_header Host hi.link;

    }
}

We now should be able to access the Web UI. Try https://hilink.example.etherarp.net/html/home.html (replacing etherarp.net with our own domain)

If you wish to use my hilink.sh script, make sure you set the following environment variables

export $HILINK_PROTO=https 
export $HILINK_HOST=hilink.example.etherarp.net
export $HILINK_AUTH="-u hilink:not_mY_r3a1_P@s5w0rd!!"

If you're noticing oddities, be careful about how you're entering the URL, because if the Hauweis web server isn't happy, it will reply with a redirect and your browser will try to reach http://192.168.1.1.

Part 5: API

In addition to the web interface, we can also use its XML-RPC based API so that we can automatically send an receive sms messages through scripts. (We covered this earlier) Perhaps to inform you of critical changes to a system.

We can also use the API to activate its modem, so it could be used with scripts to both fall over to 3G internet and text you if you loose connectivity. I'm still quite new to Web API stuff, so this section will be brief.

In these examples, we use the variable api_url which when interfacing with the dongle should be set to http://192.168.1.1/api

5.1 - Activating/Deactivating the modem

#! /bin/bash
hilink_host=192.168.1.1
api_url="http://$hilink_host/api"

activate_modem()
{
    curl $api_url/dialup/dial --data \
         "<request><Action>1</Action></request>"

    #sudo ip route add to default via 192.168.1.1 dev eth1 metric 1
}

deactivate_modem()
{
    curl $api_url/api/dialup/dial --data \
         "<request><Action>0</Action></request>"

    #sudo ip route del default via 192.168.1.1 dev eth1 metric 1
}

5.2 - Network Information

curl 192.168.1.1/api/monitoring/status

<?xml version="1.0" encoding="UTF-8"?>
<response>
<ConnectionStatus>902</ConnectionStatus>
<SignalStrength>99</SignalStrength>
<SignalIcon>5</SignalIcon>
<CurrentNetworkType>4</CurrentNetworkType>
<CurrentServiceDomain>3</CurrentServiceDomain>
<RoamingStatus>0</RoamingStatus>
<BatteryStatus></BatteryStatus>
<BatteryLevel></BatteryLevel>
<simlockStatus>0</simlockStatus>
<WanIPAddress></WanIPAddress>
<PrimaryDns></PrimaryDns>
<SecondaryDns></SecondaryDns>
<CurrentWifiUser></CurrentWifiUser>
<TotalWifiUser></TotalWifiUser>
<ServiceStatus>2</ServiceStatus>
<SimStatus>1</SimStatus>
<WifiStatus></WifiStatus>
</response>

5.3 - Device information (IMEI etc)

curl 192.168.1.1/api/device/information

<?xml version="1.0" encoding="UTF-8"?>
<response>
<DeviceName>E303</DeviceName>
<SerialNumber>123456789</SerialNumber>
<Imei>123456789012345</Imei>
<Imsi>123456789012345</Imsi>
<Iccid>123456789012345678901f</Iccid>
<Msisdn></Msisdn>
<HardwareVersion>CH2E303SM</HardwareVersion>
<SoftwareVersion>22.158.01.00.00</SoftwareVersion>
<WebUIVersion>12.012.02.02.723</WebUIVersion>
<MacAddress1>01:02:03:04:05:06</MacAddress1>
<MacAddress2></MacAddress2>
<ProductFamily>GW</ProductFamily>
<Classify>DataCard</Classify>
</response>

5.4 - Traffic Statistics

$ curl 192.168.1.1/api/monitoring/traffic-statistics

<?xml version="1.0" encoding="UTF-8"?>
<response>
<CurrentConnectTime>138</CurrentConnectTime>
<CurrentUpload>91432</CurrentUpload>
<CurrentDownload>3389</CurrentDownload>
<CurrentDownloadRate>0</CurrentDownloadRate>
<CurrentUploadRate>0</CurrentUploadRate>
<TotalUpload>1114254272</TotalUpload>
<TotalDownload>1591026668</TotalDownload>
<TotalConnectTime>992214</TotalConnectTime>
</response>

5.5 - Checking notifications

$ curl 192.168.1.1/api/monitoring/check-notifications

<?xml version="1.0" encoding="UTF-8"?>
<response>
<UnreadMessage>9</UnreadMessage>
<SmsStorageFull>0</SmsStorageFull>
<OnlineUpdateStatus>14</OnlineUpdateStatus>
</response>

5.6 - USSD data

This script performs a USSD request using the code supplied in the first argument (for *123# supply 123 as the arg). It sends the request, waits 5 seconds, and then shows the response.

#! /bin/bash

hilink_host="192.168.1.1"
api_url="http://$hilink_host/api"

request="<request><content>$1</content><codeType>CodeType</codeType></request>"

ussd_send_request()
{   
    curl $api_url/ussd/send --data $request
} 

ussd_get_response()
{
    curl $api_url/ussd/get --data $request
}

ussd_send_request
sleep 5
ussd_get_response

For more API info check out

https://chaddyhv.wordpress.com/2012/08/13/programming-and-installing-huawei-hilink-e3131-under-linux/

http://www.mrt-prodz.com/blog/view/2015/05/huawei-modem-api-and-data-plan-monitor

originally published on 2017-02-25