EM-129
EM-129
В связи с нестабильностью питания решил наконец поставить хоть какое-то защитное реле что б не спалить технику
(в последний раз броски напряжения не пережил свитч Catalyst 3550 и я остался без PoE для все своих железок чем был сильно расстроен)
По EM-129 есть практически исчерпывающий обзор от Андрея, которому нет причин не доверять:
Однако в обзоре не упоминается ничего про программную часть устройства
Зачем?
Я принципиально не хочу отправлять свои данные в любой клауд, если это не мой клауд и привязывать устройство к чему-ьто в интернете мне кажется очень странной идеей
Пару слов об устройстве
Я не могу сказать ничего хорошего про реализацию безопастности EM-129
- Поддержка HTTPS отсутвует
- Кабельного подключения нет
Этих 2 факторов вполне достаточно что бы при желании можно было взломать сеть и отснифить пароль - в качестве "защиты" могу скаазть только что надо подойти достаточно близко что бы сниффить траффик.
Сигнал достаточно слабый хотя расстяние от места установки до точки доступа - примерно 5 метров и одна бетонная стена
/interface/wireless/registration-table/print Columns: INTERFACE, MAC-ADDRESS, AP, SIGNAL-STRENGTH, TX-RATE, UPTIME 2 wlan-2.4Ghz-ssid-infra-1 CC:50:E3:FA:83:55 no -81dBm@1Mbps 18Mbps 1d1h13m32s
Получение данных
О программной реализации интерфейса тоже можо сказать мало хорошего
Из плюсов могу отметить только то что инерфейс работает относительно быстро и не слишком уродлив, впрочем что и не удивительно - под капотом там JavaScript который только отсылает на устройство запросы данных, вся обработка и отрисовка происходит на стороне браузера
Из минусов - авторизация сделана максимально плохо
- Используется только пароль, без логина
- При авторизации создается Session ID (далее SID) который может быть только один и который по сути представляет собой префикс в URL для получения данных
- Прямое следствие этого - на устройство можно зайходить и смотреть только одному пользователю одновременно. При подключении второго SID меняется и первого "отлогинивает"
- BasicAuth был бы лучше в разы
Для того что бы понять как происходит авторизация пришлось немного покопаться в коде JS (что замечу говорит о "удачности" решения)
Авторизация происходит следующим образом
- Пользователь вводит пароль
- Браузер отправляет на устройство запрос что бы получить "соль" (случайное число) и тип устройства (похоже что аналогичный код используется не только в EM-129 но и других реле)
- На оснвани полученой соли, имени устройства и пользовательского пароля формируется "секретная строка" и отправляется на сервер (основое время было потрачено на то что б найти как формируется эта секретная строка, и я не пишу на JavaScript. Думаю у web-разработчика это заняло бы единицы минут а не пол часа как у меня)
- Если строка верна то сервер возвращает SID
- ВСЕ!
Код скрипта
27 строк на bash
- IP - адрес реле
- SALT_URL - адрес куда посылать запрос на "соль"
- TOKEN_URL - адрес куда послылать запрос на SID
- ALL_DATA_URI - суффикс запроса данных
Секретная строка формируется следующим образом:
- sha1 от строки состоящей из 3 частей
- имя устройства - Пользовательский пароль закодированный в base64 - "соль"
По шагам
- A__EM_129_SALT="$(curl ${SALT_URL} | jq -r '.SALT')" - послать запрос на соль и взять поле с именем "SALT" из полученного json
- S=$(printf ${EM_129_PASSWORD} | base64) - закодировать пароль
- SUM="${E__EM_129_DEVNAME}${S}${A__EM_129_SALT}" - склеять строки
- LOGIN="$(printf "${SUM}" | sha1sum | awk '{ print $1}')" - взять sha1 от склейки строк
- SID="$(curl "${TOKEN_URL}${LOGIN}"| jq -r '.SID')" - отправить запрос на SID и взять из ответа значение поля SID
Получение данных дальше
- ALL_DATA_URL="http://${IP}/${SID}/${ALL_DATA_URI}" - сформировать адрес куда слать запрос с учетом SID
- D=$(curl ${ALL_DATA_URL} | jq -r .) получить данные
Данные получаются в виде json
{ "volt_msr": 2302, "freq_msr": 5000, "cur_msr": 321, "pows_msr": 740, "enrga_msr": 32,. "enrga_d_msr": 0, "enrga_w_msr": 0, "enrga_m_msr": 0, "enrgs_msr": 39, "sys_flag": 1409482896, "faul_flag": 0, "ar_time": 0, "cost_energy": 1700, "cost_unit": 16, "STATUS": "OK" }
Код скрипта
#!/bin/bash set -eu${DEBUG:+x} IP="192.168.31.250" SALT_URL="http://${IP}/api/login?salt" TOKEN_URL="http://${IP}/api/login?login=" ALL_DATA_URI="api/all/get?volt_msr&freq_msr&cur_msr&pows_msr&enrga_msr&enrga_d_msr&enrga_w_msr&enrga_m_msr&enrgs_msr&sys_flag&faul_flag&ar_time&cost_energy&cost_unit" A__EM_129_SALT="$(curl ${SALT_URL} | jq -r '.SALT')" E__EM_129_DEVNAME="EM-129" EM_129_PASSWORD="12345678" S=$(printf ${EM_129_PASSWORD} | base64) SUM="${E__EM_129_DEVNAME}${S}${A__EM_129_SALT}" LOGIN="$(printf "${SUM}" | sha1sum | awk '{ print $1}')" SID="$(curl "${TOKEN_URL}${LOGIN}"| jq -r '.SID')" ALL_DATA_URL="http://${IP}/${SID}/${ALL_DATA_URI}" D=$(curl ${ALL_DATA_URL} | jq -r .) if [ "${D}X" != "X" ]; then echo "${D}" else echo "{}" exit 1 fi exit 0
Интеграция с мониторингом
Имя возможность получать данные с устройства не составит труда сделать интеграцию за заббиксом или прометеем
В моем случае все максимально просто и практически полностью соответвует статье https://serveradmin.ru/parsing-i-peredacha-json-dannyih-v-zabbix/
- Добавить скрипт в агента (не забыть дать возможность агенту ходить на устройство если они в разных VLAN и между ними есть фильтрация)
cat /etc/zabbix/zabbix_agentd.d/UserParameter-ElectricCounter.conf
UserParameter=electricCounter,/etc/zabbix/scripts/counter.sh
Далее сделать зависимые Items как описано выше по сслыке. Готовый темплейт для особо ленивых ниже =)