[Из песочницы] Инструкция к спецификации SMPP

Различные сервисы, использующие SMS уведомления или SMS авторизацию, с каждым днем набирают популярность, т.к. это действительно очень удобно с точки зрения пользователя и достаточно безопасно с точки зрения разработчиков. Большинство компаний, предоставляющие сервис SMS рассылок, предлагают свои API для реализации процесса отправки (как правило на основе HTTP), но у всех есть стандартный вариант подключения — протокол SMPP. Мой опыт работы с пользователями SMPP протокола показывает, что они испытываю довольно много сложностей. Причиной этого (по моему мнению) является бездумное использование готовых библиотек и в результате полное непонимание что происходит «под капотом».

В этой статье я опишу один из самых частых вопросов от клиентов — «Как прочитать текст входящего сообщения? Я нашёл on-line декодер, но он показывает абракадабру». Дело в том, что у некоторых сервисов есть не только возможность отправки сообщений, но и получения на них ответных сообщений. Однако алгоритм, описанный мной, применим к любому действию в SMPP протоколе, т.к. по сути является инструкцией к спецификации протокола.

Разбор входящего сообщения без использования какого-либо SMPP ПО


Нам потребуются:

  • SMPP Protocol Specification v3.4
  • Wireshark
  • Блокнот
  • Браузер


Я не буду описывать процесс получения самого cap файла (дампа) SMPP обмена, т.к. уже есть много статей на эту тему (например эта).

Общий порядок обмена пакетами в SMPP выглядит следующим образом:

4e13f2211ee74cc4bb5feaf0f4cf77ba.PNG

Как видно в случае входящего сообщения нас интересует пакет deliver_sm. Определение типа пакета происходит по полю command_id, которое в случае deliver_sm имеет значение 0x00000005 (пункт 5.1.2.1 в спецификации).

В итоге фильтр в wireshark выглядит так:

smpp.command_id == 0x00000005

После того как нашли пакет по фильтру копируем его содержимое в HEX формате:

1d6a9cc803dd4a238ae55d6f99b87c6e.png

Итоговая строка, которую предстоит расшифровать:

00000048000000050000000000000003000101636F6F6E6F6C616E642E727500010137393132333435363738390000000000000000 0800000424000c043f044004380432043504424

Пункт, описывающий формат пакета deliver_sm, в спецификации, имеет номер 4.6.1 “DELIVER_SM” Syntax. В этом пункте имеется таблица, в которой расписывается каждое поле пакета:

ceea0c2103854473b2ef4a5e64b4a3b7.png

Приступим к разбору пакета
Первое поле пакета — command_length имеет размер 4 октета (столбец size octets) и тип Integer. Это означает что от начала нашей HEX строки необходимо отсчитать 4 х 2 = 8 символов.

Почему умножаем на 2?

Мы скопировали строку в шестнадцатеричном формате который кодирует один октет (байт) двумя символами.


00 00 00 48 000000050000000000000003000101636F6F6...

(HEX) 00000048 -> (DEC) 72 октета или 144 символа — длина всего SMPP пакета.

Следующее поле command_id — аналогично 4 октета и Integer.

00000048 00 00 00 05 0000000000000003000101636F6F6...

Преобразуем в читаемый вид: 00000005 = deliver_sm

72d3d003f1a443feb5b4ed94044698df.PNG

Поля command_status и sequence_number так же имею по 4 октета. Где посмотреть их значения, я предполагаю Вы уже догадываетесь.

0000004800000005 00 00 00 00 00 00 00 03 000101636F6F6...

Поле service_type может содержать максимум 6 октетов и имеет тип C-Octet String. В пункте 3.1 SMPP PDU — Type Definitions сказано:

C-Octet String A series of ASCII characters terminated with the NULL character


Другими словами это последовательность ASCII символов с нулевым октетом как знак окончания поля. Т.е. это поле может содержать максимум 6 символов, но может быть и меньше — конец данного поля обозначается HEX 00. В данном конкретном примере мы сразу видим 00 — поле не содержит ни какого значения.

00000048000000050000000000000003 00 0101636F6F6...

Если бы этот столбец был заполнен, то расшифровать его можно по таблице ASCII символов.

Пропустим следующие 2 поля source_addr_ton и source_addr_npi, т.к. как их расшифровать уже ясно и разберем еще одно поле с типом C-Octet String — source_addr.

Source_addr может содержать максимум 21 октет, но в данном случае оно состоит из 13 октетов включая нулевой октет который означает окончание поля:

63 6F 6F 6E 6F 6C 61 6E 64 2E 72 75 00

В поисковике делаем запрос «ascii table» и начинаем расшифровывать:

adc317bf074e432ab93acf56fc7a452f.png

63 = c
6F = o
6F = o
6E = n
6F = o
6C = l
61 = a
6E = n
64 = d

И так далее до символов 00.

Остальные поля я тоже пропускаю — их много и их определение ни чем не отличается от выше описанного. Перейдём к полю data_coding, без значения данного поля мы не сможем прочитать текст сообщения.

Я разделил все поля в HEX строке примера, а поле data_coding выделил жирным и вот что получилось:
00000047;00000005;00000000;00000003;00;01;01;373932393937333630333000;01;01;373932333235303039353900;00;00;00;00;00;00;00;
08;00;00;0424;000c;043f04400438043204350442

Пункт 5.2.19 спецификации указывает что используется кодировка UCS2 (ISO/IEC-10646). (HEX) 08 -> (BIN) 00001000 -> UCS2 (ISO/IEC-10646):

1af41034bc9b4b74b814f3ab6cf5412f.PNG

Ищем таблицу символов по запросу: «ucs2 code chart»

043f04400438043204350442

Выбираем первые 2 октета текста «043f» и ищем их на странице

f1c14a74782843ccb7e3d3f7368659ba.png

Продолжаем выделять по 2 октета и искать:
[р] 0440 CYRILLIC SMALL LETTER ER
[и] 0438 CYRILLIC SMALL LETTER I
[в] 0432 CYRILLIC SMALL LETTER VE
[е] 0435 CYRILLIC SMALL LETTER IE
[т] 0442 CYRILLIC SMALL LETTER TE

На этом разбор пакета окончен. Надеюсь что описание получилось понятное и достаточно полное. В целом если у Вас получилось осознать как прочитать сообщение, то отправить его не составит ни какого труда. Поменяется несколько полей.

Читайте спецификации — там почти все уже написано.

© Habrahabr.ru