[nowość] Poznaj bezpieczeństwo Windows. Cześć pierwsza: usługi systemowe. Nowe, bezpłatne szkolenie od sekuraka!

Jak skonfigurować automatyczną wysyłkę / odbiór SMS-ów pod Linuksem?

24 czerwca 2013, 10:15 | Narzędzia, Teksty | komentarzy 6
Tagi: ,

Wstęp

Na jedno z moich szkoleń z bezpieczeństwa przygotowałem swego czasu ćwiczenie, polegające na wykorzystaniu pewnych błędów aplikacyjnych używając w tym celu realnych SMS-ów (to znaczy uczestnicy aby rozwiązać ćwiczenie muszą użyć swoich komórek – również tych szarych ;-). Jak jednak zorganizować niewielkim kosztem w LAB infrastrukturę umożliwiającą na żywo wysyłkę / odbiór SMS-ów, a także ich przetwarzanie i odpowiednie reagowanie jeśli zajdzie określona sytuacja?

Pierwsze co mi przyszło do głowy, to darmowe rozwiązanie gammu. Jakie ma możliwości to oprogramowanie? Sami twórcy opisują je tak:

Gammu command line utility provides access to wide range of phone features, however support level differs from phone to phone (…) Generally following features are supported:

  • Call listing, initiating and handling
  • SMS retrieval, backup and sending
  • MMS retrieval
  • Phonebook listing, export and import (also from standard formats such as vCard)
  • Calendar and tasks listing, export and import (also from standard formats such as vCalendar or iCalendar)
  • Retrieval of phone and network information
  • Access to phone file system (note that some phones work also as USB storage devices and those are not accessible through Gammu)

Opcja dotycząca SMS-ów wydaje się być idealna pod nasze potrzeby. Co więcej w ramach gammu dostępny jest monitor komunikacji SMS o nazwie smsd:

Gammu SMS Daemon is a program that periodically scans GSM modem for received messages, stores them in defined storage and also sends messages enqueued in this storage. It is perfect tool for managing big amounts of received or sent messages and automatically process them.

Wskazanym w powyższym cytacie 'storage’ może być bazą danych (np. MySQL). Finalnie, kiedy więc przyjdzie na nasz numer wiadomość SMS, smsd automatycznie wpisuje odpowiedni rekord do bazy (zawierający dane SMS-a). Z kolei gdy chcemy SMS-a wysłać, po prostu robimy jednego INSERT-a do konkretnej tabeli – reszta dzieje się automatycznie. Proste? Wydaje się że tak :-) Architektura rozwiązania wygląda tak:

gammu

Zabieramy się do pracy

Akurat pod ręką miałem stary telefon Nokia 6300, który jest na liście wspieranego przez gammu sprzętu. Wyposażyłem go w prepaidową kartę SIM za 5 zł, dającą własny numer oraz możliwość wysłania w tej kwocie dość dużej liczby SMS-ów.

Po podłączeniu telefonu kablem USB do komputera zacząłem testy. Tu niestety napotkałem na pewne problemy. O ile działało wysyłanie SMS-ów z konsoli:

securitum-t1:~# echo "testowy sms" |gammu sendsms TEXT 123123123
If you want break, press Ctrl+C...
Sending SMS 1/1....waiting for network answer..OK, message reference=107

…to z odbieraniem nie było już tak różowo. Ściągnąłem więc wersję deweloperską gammu, po skompilowaniu której… pomogło :-) W tym momencie byłem w stanie zarówno wysyłać jak i odbierać SMS-y. Wystarczyło tylko uruchomić oraz skonfigurować smsd.

Tutaj niestety pojawiły się kolejne schody (oszczędzę na razie szczegółów konfiguracyjnych) – smsd był w stanie tylko wysyłać SMS-y (bez możliwości odbioru). W końcu, po spędzeniu dłuższego czasu na listach dyskusyjnych gammu, stwierdziłem że prawdopodobnie jest to bug w obsłudze telefonu Nokia 6300 i prościej niż patchować smsd będzie poszukać innego sprzętu.

Stanęło tym razem na popularnym modemie Huavei E173, który akurat miałem pod ręką (jest dość popularnym urządzeniem w ofercie jednego z operatorów GSM). Sprzęt miał już z 2 lata więc miałem nadzieję, że jeszcze działa :-)

W systemie modem został wykryty:

root@securitum-t1:~# lsusb
Bus 003 Device 003: ID 12d1:1446 Huawei Technologies Co., Ltd. E1552 (HSPA modem                                                                                                                                                             )
Bus 003 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 004: ID 8087:07da Intel Corp.
Bus 002 Device 003: ID 1bcf:288e Sunplus Innovation Technology Inc.
Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub

Jak wydać powyżej parametry modemu to  12d1:1446 (tj. productID = 12d1, vendorID = 1446). Szczegóły wyglądają tak:

securitum-t1:~# lsusb -v -d 12d1:1446 
Bus 003 Device 003: ID 12d1:1446 Huawei Technologies Co., Ltd. E1552 (HSPA modem)
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x12d1 Huawei Technologies Co., Ltd.
  idProduct          0x1446 E1552 (HSPA modem)
  bcdDevice            0.00
  iManufacturer           3 HUAWEI Technology
  iProduct                2 HUAWEI Mobile
  iSerial                 0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           55
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          1 Huawei   Configuration
    bmAttributes         0xe0
      Self Powered
      Remote Wakeup
    MaxPower              500mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         8 Mass Storage
      bInterfaceSubClass      6 SCSI
      bInterfaceProtocol     80 Bulk (Zip)
      iInterface              0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         8 Mass Storage
      bInterfaceSubClass      6 SCSI
      bInterfaceProtocol     80 Bulk (Zip)
      iInterface              0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
Device Qualifier (for other device speed):
  bLength                10
  bDescriptorType         6
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  bNumConfigurations      1
Device Status:     0x0001
  Self Powered

Problem w tym, że nie byłem go w żaden sposób zmusić do współpracy z gammu. Okazuje się, że domyślnie urządzenie to działa pod Linuksem w trybie storage USB – czyli jako pendrive, a nie jako potrzebny mi modem. Szybkie googlanie pokazało rozwiązanie problemu. Użyjmy więc polecanego wyżej narzędzia usb_modeswitch:

securitum-t1:~# apt-get install usb-modeswitch -y
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following package was automatically installed and is no longer required:
  libgammu-i18n
Use 'apt-get autoremove' to remove them.
The following extra packages will be installed:
  usb-modeswitch-data
Suggested packages:
  comgt wvdial
The following NEW packages will be installed:
  usb-modeswitch usb-modeswitch-data
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/69.1 kB of archives.
After this operation, 889 kB of additional disk space will be used.
Selecting previously deselected package usb-modeswitch-data.
(Reading database ... 50191 files and directories currently installed.)
Unpacking usb-modeswitch-data (from .../usb-modeswitch-data_20100826-1+squeeze0_all.deb) ...
Selecting previously deselected package usb-modeswitch.
Unpacking usb-modeswitch (from .../usb-modeswitch_1.1.4-2_i386.deb) ...
Processing triggers for man-db ...
Setting up usb-modeswitch-data (20100826-1+squeeze0) ...
Setting up usb-modeswitch (1.1.4-2) ...

I wykorzystajmy taki plik konfiguracyjny:

securitum-t1:~# cat usb_modeswitch.conf
DisableSwitching=0

# Enable logging (results in a extensive report file in /var/log, named
# "usb_modeswitch_<interface-name>"

EnableLogging=0
DefaultVendor=  0x12d1
DefaultProduct= 0x1446

TargetVendor=   0x12d1
TargetProduct=  0x140c

MessageContent="55534243000000000000000000000011060000000000000000000000000000"

CheckSuccess=5

Pozostaje tylko wypróbować ustawienia:

securitum-t1:~# usb_modeswitch -c usb_modeswitch.conf

Looking for target devices ...
 No devices in target mode or class found
Looking for default devices ...
 Found devices in default mode or class (1)
Accessing device 003 on bus 003 ...
Using endpoints 0x01 (out) and 0x81 (in)
Using endpoints 0x01 (out) and 0x81 (in)
Inquiring device details; driver will be detached ...
Looking for active driver ...
 OK, driver found ("usb-storage")
 OK, driver "usb-storage" detached

SCSI inquiry data (for identification)
-------------------------
  Vendor String: HUAWEI
   Model String: Mass Storage
Revision String: 2.31
-------------------------

USB description data (for identification)
-------------------------
Manufacturer: HUAWEI Technology
     Product: HUAWEI Mobile
  Serial No.: not provided
-------------------------
Setting up communication with interface 0 ...
Using endpoint 0x01 for message sending ...
Trying to send message 1 to endpoint 0x01 ...
 OK, message successfully sent
Resetting response endpoint 0x81
 Error resetting endpoint: -71
Resetting message endpoint 0x01
 Error resetting endpoint: -71

Checking for mode switch (max. 5 times, once per second) ...
 Waiting for original device to vanish ...
 Original device can't be accessed anymore. Good.
 Searching for target devices ...
 Searching for target devices ...
 Searching for target devices ...
 Searching for target devices ...
 Searching for target devices ...
 Found correct target device

Mode switch succeeded. Bye.

Ostatnia linijka wygląda zachęcająco, zobaczmy czy posiadamy już wirtualne urządzenie, przez które moglibyśmy się odwołać do modemu:

securitum-t1:~# dmesg |grep ttyUSB
[  203.442061] usb 3-1.1: GSM modem (1-port) converter now attached to ttyUSB0
[  203.442436] usb 3-1.1: GSM modem (1-port) converter now attached to ttyUSB1
[  203.442570] usb 3-1.1: GSM modem (1-port) converter now attached to ttyUSB2
[  203.442640] usb 3-1.1: GSM modem (1-port) converter now attached to ttyUSB3

Spróbujemy więc przygotować odpowiednio .gammurc:

securitum-t1:~# cat .gammurc

[gammu]

port = /dev/ttyUSB3
model = E173
connection = at115200
synchronizetime = yes
logfile =
logformat = nothing
use_locking =
gammuloc =

Z tymi ustawieniami wysyłka SMSów…działa! :-)

securitum-t1:~# echo "testowy sms" |gammu sendsms TEXT 123123123
If you want break, press Ctrl+C...
Sending SMS 1/1....waiting for network answer..OK, message reference=107

Teraz pozostaje nam konfiguracja i przetestowanie smsd. Do zbudowania bazy MySQL użyłem schematu dostępnego tutaj: gammu-1.32.0/docs/sql/mysql.sql

securitum-t1:~# mysql -u gammu -p gammu < ./gammu-1.32.0/docs/sql/mysql.sql

Z kolei moja konfiguracja smsd wygląda tak:

securitum-t1:~# cat /etc/gammu-smsdrc
# Configuration file for Gammu SMS Daemon

# Gammu library configuration, see gammurc(5)
[gammu]
# Please configure this!
port = /dev/ttyUSB2
model = E173
connection = at115200

# Debugging
logformat = textall

# SMSD configuration, see gammu-smsdrc(5)
[smsd]

CommTimeout = 5
ReceiveFrequency = 5
service = sql
driver = native_mysql
user = gammu
password = tutaj_haselko_do_db
pc = localhost
database = gammu
logformat = textall
logfile = /tmp/test.log
deliveryreport = log
# Increase for debugging information
debuglevel = 3

Po starcie smsd, jego logi wyglądają zachęcająco:

securitum-t1:~# cat /tmp/test.log

Sat 2013/06/22 15:07:13 gammu-smsd[4712]: Connected to Database: gammu on localhost
Sat 2013/06/22 15:07:13 gammu-smsd[4712]: Execute SQL: SELECT  `ID` FROM outbox LIMIT 1
Sat 2013/06/22 15:07:13 gammu-smsd[4712]: Execute SQL: SELECT  `ID` FROM outbox_multipart LIMIT 1
Sat 2013/06/22 15:07:13 gammu-smsd[4712]: Execute SQL: SELECT  `ID` FROM sentitems LIMIT 1
Sat 2013/06/22 15:07:13 gammu-smsd[4712]: Execute SQL: SELECT  `ID` FROM inbox LIMIT 1
Sat 2013/06/22 15:07:13 gammu-smsd[4712]: Execute SQL: SELECT `Version` FROM gammu
Sat 2013/06/22 15:07:13 gammu-smsd[4712]: Database structures version: 13, SMSD current version: 13
Sat 2013/06/22 15:07:13 gammu-smsd[4712]: Connected to Database native_mysql: gammu on localhost
Sat 2013/06/22 15:07:13 gammu-smsd[4712]: Created POSIX RW shared memory at 0xb76fb000
Sat 2013/06/22 15:07:13 gammu-smsd[4712]: Starting phone communication...

Czas teraz na finalne testy:

securitum-t1:~# mysql -u gammu -p gammu
Enter password:
mysql> show tables;
+------------------+
| Tables_in_gammu  |
+------------------+
| answers          |
| blacklist        |
| daemons          |
| gammu            |
| inbox            |
| outbox           |
| outbox_multipart |
| pbk              |
| pbk_groups       |
| phones           |
| reset_pass       |
| sentitems        |
| users            |
+------------------+
13 rows in set (0.00 sec)

mysql> desc outbox;
+-------------------+------------------------------------------------------------------------------------------------------------+------+-----+------------------------+-----------------------------+
| Field             | Type                                                                                                       | Null | Key | Default                | Extra                       |
+-------------------+------------------------------------------------------------------------------------------------------------+------+-----+------------------------+-----------------------------+
| UpdatedInDB       | timestamp                                                                                                  | NO   |     | CURRENT_TIMESTAMP      | on update CURRENT_TIMESTAMP |
| InsertIntoDB      | timestamp                                                                                                  | NO   |     | 0000-00-00 00:00:00    |                             |
| SendingDateTime   | timestamp                                                                                                  | NO   | MUL | 0000-00-00 00:00:00    |                             |
| SendBefore        | time                                                                                                       | NO   |     | 23:59:59               |                             |
| SendAfter         | time                                                                                                       | NO   |     | 00:00:00               |                             |
| Text              | text                                                                                                       | YES  |     | NULL                   |                             |
| DestinationNumber | varchar(20)                                                                                                | NO   |     |                        |                             |
| Coding            | enum('Default_No_Compression','Unicode_No_Compression','8bit','Default_Compression','Unicode_Compression') | NO   |     | Default_No_Compression |                             |
| UDH               | text                                                                                                       | YES  |     | NULL                   |                             |
| Class             | int(11)                                                                                                    | YES  |     | -1                     |                             |
| TextDecoded       | text                                                                                                       | NO   |     | NULL                   |                             |
| ID                | int(10) unsigned                                                                                           | NO   | PRI | NULL                   | auto_increment              |
| MultiPart         | enum('false','true')                                                                                       | YES  |     | false                  |                             |
| RelativeValidity  | int(11)                                                                                                    | YES  |     | -1                     |                             |
| SenderID          | varchar(255)                                                                                               | YES  | MUL | NULL                   |                             |
| SendingTimeOut    | timestamp                                                                                                  | YES  |     | 0000-00-00 00:00:00    |                             |
| DeliveryReport    | enum('default','yes','no')                                                                                 | YES  |     | default                |                             |
| CreatorID         | text                                                                                                       | NO   |     | NULL                   |                             |
+-------------------+------------------------------------------------------------------------------------------------------------+------+-----+------------------------+-----------------------------+

Pokazana wyżej tabela outbox jest skanowana cyklicznie przez smsd w poszukiwaniu nowych rekordów. Jeśli takowy zostanie znaleziony – SMS jest wysyłany. Jak więc wysłać SMS-a? Na przykład tak:

mysql> INSERT INTO outbox (DestinationNumber, TextDecoded) VALUES ('+48123123123','testowy smsik');
Query OK, 1 row affected, 1 warning (0.00 sec)

Tak można z kolei odczytać SMS-y, które ktoś do nas przysłał (poniżej SMS o treści „Aaa”):

mysql> select * from inbox;
+---------------------+---------------------+--------------+--------------+------------------------+-----+--------------+-------+-------------+-----+-------------+-----------+
| UpdatedInDB         | ReceivingDateTime   | Text         | SenderNumber | Coding                 | UDH | SMSCNumber   | Class | TextDecoded | ID  | RecipientID | Processed |
+---------------------+---------------------+--------------+--------------+------------------------+-----+--------------+-------+-------------+-----+-------------+-----------+
| 2013-06-22 15:13:33 | 2013-06-22 13:13:16 | 004100610061 | +48123123123 | Default_No_Compression |     | +48790123123 |    -1 | Aaa         | 102 |             | false     |
+---------------------+---------------------+--------------+--------------+------------------------+-----+--------------+-------+-------------+-----+-------------+-----------+

 

Pozostało mi już tylko wykonać skrypty łączące się bazą i realizujące logikę, którą zaplanowałem do realizacji jednego z ćwiczeń :-)

Całość w działaniu wygląda całkiem niepozornie…:j2

 

Użyte w tekście numery GSM są „losowe” – we własnych testach należy użyć własnych numerów :-)

PS

Zmianę trybu można zautomatyzować poprzez stworzenie pliku: /etc/usb_modeswitch.d/12d1:1446 o zawartości:

# Huawei, newer modems

DefaultVendor= 0x12d1
DefaultProduct=0x1446

TargetVendor=  0x12d1
TargetProductList="1001,1406,140b,140c,1412,141b,14ac"

CheckSuccess=20

MessageContent="55534243123456780000000000000011062000000100000000000000000000"

 

–michal.sajdak<at>securitum.pl

 

Spodobał Ci się wpis? Podziel się nim ze znajomymi:



Komentarze

  1. Adam
    Odpowiedz
    • @Adam – wygląda ciekawie, choć nie widzę czegoś jak smsd (+ połączenie jego z bazą)?
      –ms

      Odpowiedz
  2. p

    Przy niektórych modemach zamiast usb_modeswitch można (a nawet trzeba) użyć polecenia… eject z odpowiednimi parametrami.

    Odpowiedz
  3. Odpowiedz
  4. `gammu-smsd` najlepiej do kompletu pilnować przy pomocy `monit`, bo jeśli jednocześnie używamy `gammu-smsd`i np. okazyjnie `wvdial` do wdzwaniania się do netu, `gammu-smsd` lubi się wysypać z powodu braku dostępu do /dev/ttyUSB0.

    Odpowiedz
  5. Emil

    Mam pytanie. Robię tak jak w poradniku czyli przełączam mój ZTE w tryb modemu. Wywala error, ale się urządzenie przełącza w tryb modemu (zaczyna świecić na niebiesko). Ale wyświetla się jako ttyACM0, ttyACM1 i ttyACM2. To normalne?

    A i da się to jakoś zautomatyzować po restarcie komputera? Czasem muszę robić to jeszcze raz a gdy usługa ma działać cały czas bez ingerencji muszę to jakoś albo scalić na stałe albo monitorwać. Macie jakiś pomysł?

    Odpowiedz

Odpowiedz