EM-129: различия между версиями

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску
 
(не показано 7 промежуточных версий этого же участника)
Строка 1: Строка 1:
  +
[[Категория:Linux]]
  +
[[Категория:IoT]]
  +
[[Категория:EM-129]]
  +
[[Категория:Networking]]
  +
[[Категория:Zabbix]]
  +
  +
 
=EM-129=
 
=EM-129=
 
В связи с нестабильностью питания решил наконец поставить хоть какое-то защитное реле что б не спалить технику <BR>
 
В связи с нестабильностью питания решил наконец поставить хоть какое-то защитное реле что б не спалить технику <BR>
Строка 46: Строка 53:
 
* Пользователь вводит пароль
 
* Пользователь вводит пароль
 
* Браузер отправляет на устройство запрос что бы получить "соль" (случайное число) и тип устройства (похоже что аналогичный код используется не только в EM-129 но и других реле)
 
* Браузер отправляет на устройство запрос что бы получить "соль" (случайное число) и тип устройства (похоже что аналогичный код используется не только в EM-129 но и других реле)
* На оснвани полученой соли, имени устройства и пользовательского пароля формируется "секретная строка" и отправляется на сервер
+
* На оснвани полученой соли, имени устройства и пользовательского пароля формируется "секретная строка" и отправляется на сервер (основое время было потрачено на то что б найти как формируется эта секретная строка, и я не пишу на JavaScript. Думаю у web-разработчика это заняло бы единицы минут а не пол часа как у меня)
 
* Если строка верна то сервер возвращает SID
 
* Если строка верна то сервер возвращает SID
 
* ВСЕ!
 
* ВСЕ!
Строка 57: Строка 64:
 
* TOKEN_URL - адрес куда послылать запрос на SID
 
* TOKEN_URL - адрес куда послылать запрос на SID
 
* ALL_DATA_URI - суффикс запроса данных
 
* ALL_DATA_URI - суффикс запроса данных
  +
<BR>
 
  +
<BR>
 
Секретная строка формируется следующим образом:
 
Секретная строка формируется следующим образом:
   
Строка 64: Строка 72:
 
- Пользовательский пароль закодированный в base64
 
- Пользовательский пароль закодированный в base64
 
- "соль"
 
- "соль"
  +
<BR>
 
 
По шагам
 
По шагам
* A__EM_129_SALT="$(curl ${SALT_URL} | jq -r '.SALT')" - послать запрос на соль и взять поле с именем "SALT" из полученного json
+
* '''A__EM_129_SALT="$(curl ${SALT_URL} | jq -r '.SALT')'''" - послать запрос на соль и взять поле с именем "SALT" из полученного json
* S=$(printf ${EM_129_PASSWORD} | base64) - закодировать пароль
+
* '''S=$(printf ${EM_129_PASSWORD} | base64)''' - закодировать пароль
* SUM="${E__EM_129_DEVNAME}${S}${A__EM_129_SALT}" - склеять строки
+
* '''SUM="${E__EM_129_DEVNAME}${S}${A__EM_129_SALT}"''' - склеять строки
* LOGIN="$(printf "${SUM}" | sha1sum | awk '{ print $1}')" - взять sha1 от склейки строк
+
* '''LOGIN="$(printf "${SUM}" | sha1sum | awk '{ print $1}')"''' - взять sha1 от склейки строк
* SID="$(curl "${TOKEN_URL}${LOGIN}"| jq -r '.SID')" - отправить запрос на SID и взять из ответа значение поля SID
+
* '''SID="$(curl "${TOKEN_URL}${LOGIN}"| jq -r '.SID')"''' - отправить запрос на SID и взять из ответа значение поля SID
  +
<BR>
 
 
Получение данных дальше
 
Получение данных дальше
* ALL_DATA_URL="http://${IP}/${SID}/${ALL_DATA_URI}" - сформировать адрес куда слать запрос с учетом SID
+
* '''ALL_DATA_URL="http://${IP}/${SID}/${ALL_DATA_URI}"''' - сформировать адрес куда слать запрос с учетом SID
* D=$(curl ${ALL_DATA_URL} | jq -r .) получить данные
+
* '''D=$(curl ${ALL_DATA_URL} | jq -r .)''' получить данные
  +
<BR>
 
  +
<BR>
Данные получаются в виде json
 
  +
Данные получаются в виде json (для некоторых полей нужен множитель 0.1 или 0.01 - сопоставить с интерфейсом устройства не сложно)
  +
<BR>
 
<PRE>
 
<PRE>
 
{
 
{
Строка 129: Строка 139:
 
exit 0
 
exit 0
 
</PRE>
 
</PRE>
  +
  +
=Интеграция с мониторингом=
  +
Имя возможность получать данные с устройства не составит труда сделать интеграцию за заббиксом или прометеем
  +
<BR>
  +
В моем случае все максимально просто и практически полностью соответвует статье https://serveradmin.ru/parsing-i-peredacha-json-dannyih-v-zabbix/
  +
  +
* Добавить скрипт в агента (не забыть дать возможность агенту ходить на устройство если они в разных VLAN и между ними есть фильтрация)
  +
<PRE>
  +
cat /etc/zabbix/zabbix_agentd.d/UserParameter-ElectricCounter.conf
  +
</PRE>
  +
<PRE>
  +
UserParameter=electricCounter,/etc/zabbix/scripts/counter.sh
  +
</PRE>
  +
Далее сделать зависимые Items как описано выше по сслыке. Готовый темплейт для особо ленивых ниже =)
  +
  +
=Zabbix template=
  +
{{#spoiler:show=zabbix template|
  +
  +
<PRE>
  +
<?xml version="1.0" encoding="UTF-8"?>
  +
<zabbix_export>
  +
<version>5.0</version>
  +
<date>2022-08-14T12:27:09Z</date>
  +
<groups>
  +
<group>
  +
<name>Electric Counter</name>
  +
</group>
  +
</groups>
  +
<templates>
  +
<template>
  +
<template>Template Electric Counter</template>
  +
<name>Template Electric Counter</name>
  +
<groups>
  +
<group>
  +
<name>Electric Counter</name>
  +
</group>
  +
</groups>
  +
<applications>
  +
<application>
  +
<name>electricCounter</name>
  +
</application>
  +
</applications>
  +
<items>
  +
<item>
  +
<name>electricCounter</name>
  +
<key>electricCounter</key>
  +
<history>0</history>
  +
<trends>0</trends>
  +
<value_type>TEXT</value_type>
  +
<applications>
  +
<application>
  +
<name>electricCounter</name>
  +
</application>
  +
</applications>
  +
</item>
  +
<item>
  +
<name>electricCounter.current</name>
  +
<type>DEPENDENT</type>
  +
<key>electricCounter.current</key>
  +
<delay>0</delay>
  +
<value_type>FLOAT</value_type>
  +
<units>A</units>
  +
<applications>
  +
<application>
  +
<name>electricCounter</name>
  +
</application>
  +
</applications>
  +
<preprocessing>
  +
<step>
  +
<type>JSONPATH</type>
  +
<params>$.cur_msr</params>
  +
</step>
  +
<step>
  +
<type>MULTIPLIER</type>
  +
<params>0.01</params>
  +
</step>
  +
</preprocessing>
  +
<master_item>
  +
<key>electricCounter</key>
  +
</master_item>
  +
</item>
  +
<item>
  +
<name>electricCounter.power</name>
  +
<type>DEPENDENT</type>
  +
<key>electricCounter.powerVA</key>
  +
<delay>0</delay>
  +
<value_type>FLOAT</value_type>
  +
<units>VA</units>
  +
<applications>
  +
<application>
  +
<name>electricCounter</name>
  +
</application>
  +
</applications>
  +
<preprocessing>
  +
<step>
  +
<type>JSONPATH</type>
  +
<params>$.pows_msr</params>
  +
</step>
  +
</preprocessing>
  +
<master_item>
  +
<key>electricCounter</key>
  +
</master_item>
  +
</item>
  +
<item>
  +
<name>electricCounter.freq</name>
  +
<type>DEPENDENT</type>
  +
<key>electricCounter.vfreq</key>
  +
<delay>0</delay>
  +
<value_type>FLOAT</value_type>
  +
<units>Hz</units>
  +
<applications>
  +
<application>
  +
<name>electricCounter</name>
  +
</application>
  +
</applications>
  +
<preprocessing>
  +
<step>
  +
<type>JSONPATH</type>
  +
<params>$.freq_msr</params>
  +
</step>
  +
<step>
  +
<type>MULTIPLIER</type>
  +
<params>0.01</params>
  +
</step>
  +
</preprocessing>
  +
<master_item>
  +
<key>electricCounter</key>
  +
</master_item>
  +
</item>
  +
<item>
  +
<name>electricCounter.volt</name>
  +
<type>DEPENDENT</type>
  +
<key>electricCounter.volt</key>
  +
<delay>0</delay>
  +
<value_type>FLOAT</value_type>
  +
<units>V</units>
  +
<applications>
  +
<application>
  +
<name>electricCounter</name>
  +
</application>
  +
</applications>
  +
<preprocessing>
  +
<step>
  +
<type>JSONPATH</type>
  +
<params>$.volt_msr</params>
  +
</step>
  +
<step>
  +
<type>MULTIPLIER</type>
  +
<params>0.1</params>
  +
</step>
  +
</preprocessing>
  +
<master_item>
  +
<key>electricCounter</key>
  +
</master_item>
  +
</item>
  +
</items>
  +
<screens>
  +
<screen>
  +
<name>Counters</name>
  +
<hsize>1</hsize>
  +
<vsize>3</vsize>
  +
<screen_items>
  +
<screen_item>
  +
<resourcetype>0</resourcetype>
  +
<style>0</style>
  +
<resource>
  +
<name>Volts/Ampers</name>
  +
<host>Template Electric Counter</host>
  +
</resource>
  +
<width>1500</width>
  +
<height>200</height>
  +
<x>0</x>
  +
<y>0</y>
  +
<colspan>1</colspan>
  +
<rowspan>1</rowspan>
  +
<elements>0</elements>
  +
<valign>0</valign>
  +
<halign>0</halign>
  +
<dynamic>0</dynamic>
  +
<sort_triggers>0</sort_triggers>
  +
<url/>
  +
<application/>
  +
<max_columns>3</max_columns>
  +
</screen_item>
  +
<screen_item>
  +
<resourcetype>0</resourcetype>
  +
<style>0</style>
  +
<resource>
  +
<name>Power</name>
  +
<host>Template Electric Counter</host>
  +
</resource>
  +
<width>1500</width>
  +
<height>200</height>
  +
<x>0</x>
  +
<y>1</y>
  +
<colspan>1</colspan>
  +
<rowspan>1</rowspan>
  +
<elements>0</elements>
  +
<valign>0</valign>
  +
<halign>0</halign>
  +
<dynamic>0</dynamic>
  +
<sort_triggers>0</sort_triggers>
  +
<url/>
  +
<application/>
  +
<max_columns>3</max_columns>
  +
</screen_item>
  +
<screen_item>
  +
<resourcetype>0</resourcetype>
  +
<style>0</style>
  +
<resource>
  +
<name>Freq</name>
  +
<host>Template Electric Counter</host>
  +
</resource>
  +
<width>1500</width>
  +
<height>200</height>
  +
<x>0</x>
  +
<y>2</y>
  +
<colspan>1</colspan>
  +
<rowspan>1</rowspan>
  +
<elements>0</elements>
  +
<valign>0</valign>
  +
<halign>0</halign>
  +
<dynamic>0</dynamic>
  +
<sort_triggers>0</sort_triggers>
  +
<url/>
  +
<application/>
  +
<max_columns>3</max_columns>
  +
</screen_item>
  +
</screen_items>
  +
</screen>
  +
</screens>
  +
</template>
  +
</templates>
  +
<graphs>
  +
<graph>
  +
<name>Freq</name>
  +
<graph_items>
  +
<graph_item>
  +
<sortorder>1</sortorder>
  +
<color>1A7C11</color>
  +
<item>
  +
<host>Template Electric Counter</host>
  +
<key>electricCounter.vfreq</key>
  +
</item>
  +
</graph_item>
  +
</graph_items>
  +
</graph>
  +
<graph>
  +
<name>Power</name>
  +
<graph_items>
  +
<graph_item>
  +
<sortorder>1</sortorder>
  +
<color>1A7C11</color>
  +
<item>
  +
<host>Template Electric Counter</host>
  +
<key>electricCounter.powerVA</key>
  +
</item>
  +
</graph_item>
  +
</graph_items>
  +
</graph>
  +
<graph>
  +
<name>Volts/Ampers</name>
  +
<graph_items>
  +
<graph_item>
  +
<sortorder>1</sortorder>
  +
<color>F63100</color>
  +
<yaxisside>RIGHT</yaxisside>
  +
<item>
  +
<host>Template Electric Counter</host>
  +
<key>electricCounter.volt</key>
  +
</item>
  +
</graph_item>
  +
<graph_item>
  +
<sortorder>2</sortorder>
  +
<color>2774A4</color>
  +
<item>
  +
<host>Template Electric Counter</host>
  +
<key>electricCounter.current</key>
  +
</item>
  +
</graph_item>
  +
</graph_items>
  +
</graph>
  +
</graphs>
  +
</zabbix_export>
  +
  +
</PRE>
  +
}}

Текущая версия на 16:59, 24 августа 2022


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 (для некоторых полей нужен множитель 0.1 или 0.01 - сопоставить с интерфейсом устройства не сложно)

{
  "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 как описано выше по сслыке. Готовый темплейт для особо ленивых ниже =)

Zabbix template